From e6f5230c58a86c6518d34efb2631e7f33d72b417 Mon Sep 17 00:00:00 2001 From: Nick Guy Date: Tue, 22 Jul 2025 23:57:44 +0100 Subject: [PATCH] Add advanced Skyblock world generation and clean up existing code. - Introduced tiered island network generation. - Enhanced player/team-specific world spawning. - Refactored persistent data usage for key workflows. - Added unit tests for circle placement logic. --- build.gradle | 9 +- .../ncguy/usefulSkyblock/HexagonalWorld.java | 20 -- .../ncguy/usefulSkyblock/UsefulSkyblock.java | 27 --- .../command/SkyblockGenCommand.java | 109 ---------- .../StructureRef.java | 2 +- .../ncguy/usefulskyblock/UsefulSkyblock.java | 104 +++++++++ .../UsefulSkyblockBootstrap.java | 8 +- .../UsefulSkyblockLoader.java | 2 +- .../command/AbstractSkyblockCommand.java | 2 +- .../command/CommandFunction.java | 2 +- .../command/SkyblockAdminCommand.java | 56 +++-- .../command/SkyblockGenCommand.java | 198 ++++++++++++++++++ .../hexagon/HexagonRenderer.java | 2 +- .../utils/BoxVisualizer.java | 52 +++-- .../utils/MathsUtils.java | 32 ++- .../usefulskyblock/world/PortalHandler.java | 20 ++ .../data/minecraft/dimension/overworld.json | 11 + .../data/minecraft/dimension/the_nether.json | 11 + .../data/usefulskyblock/dimension/void.json | 11 +- .../dimension_type/skyblock.json | 24 +++ .../structures/classic-sand.nbt | Bin 10902 -> 569 bytes .../usefulskyblock/structures/classic.nbt | Bin 88062 -> 3125 bytes .../data/usefulskyblock/structures/spawn.nbt | Bin 0 -> 75070 bytes src/main/resources/paper-plugin.yml | 8 +- .../com/ncguy/usefulskyblock/SimpleTests.java | 57 +++++ 25 files changed, 559 insertions(+), 208 deletions(-) delete mode 100644 src/main/java/com/ncguy/usefulSkyblock/HexagonalWorld.java delete mode 100644 src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblock.java delete mode 100644 src/main/java/com/ncguy/usefulSkyblock/command/SkyblockGenCommand.java rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/StructureRef.java (99%) create mode 100644 src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/UsefulSkyblockBootstrap.java (90%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/UsefulSkyblockLoader.java (88%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/command/AbstractSkyblockCommand.java (97%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/command/CommandFunction.java (87%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/command/SkyblockAdminCommand.java (82%) create mode 100644 src/main/java/com/ncguy/usefulskyblock/command/SkyblockGenCommand.java rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/hexagon/HexagonRenderer.java (98%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/utils/BoxVisualizer.java (66%) rename src/main/java/com/ncguy/{usefulSkyblock => usefulskyblock}/utils/MathsUtils.java (60%) create mode 100644 src/main/java/com/ncguy/usefulskyblock/world/PortalHandler.java create mode 100644 src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/overworld.json create mode 100644 src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/the_nether.json create mode 100644 src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension_type/skyblock.json create mode 100644 src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/spawn.nbt create mode 100644 src/test/java/com/ncguy/usefulskyblock/SimpleTests.java diff --git a/build.gradle b/build.gradle index 90aa724..4353375 100644 --- a/build.gradle +++ b/build.gradle @@ -18,13 +18,19 @@ repositories { name = "sonatype" url = "https://oss.sonatype.org/content/groups/public/" } + maven { + name = "multiverseMultiverseReleases" + url = uri("https://repo.onarandombox.com/multiverse-releases") + } + } dependencies { compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT") implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation 'com.github.DigitalSmile:hexagon:v0.2.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } tasks { @@ -52,6 +58,7 @@ tasks.withType(JavaCompile).configureEach { } } + processResources { def props = [version: version] inputs.properties props diff --git a/src/main/java/com/ncguy/usefulSkyblock/HexagonalWorld.java b/src/main/java/com/ncguy/usefulSkyblock/HexagonalWorld.java deleted file mode 100644 index 7cbe4e4..0000000 --- a/src/main/java/com/ncguy/usefulSkyblock/HexagonalWorld.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ncguy.usefulSkyblock; - -import org.digitalsmile.hexgrid.HexagonGrid; -import org.digitalsmile.hexgrid.layout.Orientation; -import org.digitalsmile.hexgrid.shapes.hexagonal.HexagonalShape; - -public class HexagonalWorld { - - public void Init() { - var hexagonGrid = new HexagonGrid.HexagonGridBuilder<>() - .shape(new HexagonalShape(5), Orientation.FLAT) - .hexagonWidth(150) - .build(); - hexagonGrid.generateHexagons(); - } - - - - -} diff --git a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblock.java b/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblock.java deleted file mode 100644 index eafe31d..0000000 --- a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblock.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ncguy.usefulSkyblock; - -import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.plugin.java.JavaPlugin; - -public final class UsefulSkyblock extends JavaPlugin implements Listener { - - @Override - public void onEnable() { - // Plugin startup logic - Bukkit.getPluginManager().registerEvents(this, this); - } - - @Override - public void onDisable() { - // Plugin shutdown logic - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - event.getPlayer().sendMessage(Component.text("Hello, " + event.getPlayer().getName() + "!")); - } -} diff --git a/src/main/java/com/ncguy/usefulSkyblock/command/SkyblockGenCommand.java b/src/main/java/com/ncguy/usefulSkyblock/command/SkyblockGenCommand.java deleted file mode 100644 index 208f35e..0000000 --- a/src/main/java/com/ncguy/usefulSkyblock/command/SkyblockGenCommand.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.ncguy.usefulSkyblock.command; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.tree.LiteralCommandNode; -import com.ncguy.usefulSkyblock.StructureRef; -import com.ncguy.usefulSkyblock.utils.MathsUtils; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import io.papermc.paper.command.brigadier.Commands; -import org.bukkit.Location; -import org.bukkit.block.structure.Mirror; -import org.bukkit.block.structure.StructureRotation; -import org.bukkit.structure.Structure; -import org.bukkit.util.Vector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Random; -import java.util.function.Supplier; - -public class SkyblockGenCommand extends AbstractSkyblockCommand { - - private static final Logger log = LoggerFactory.getLogger(SkyblockGenCommand.class); - - private StructureRef[] centralIslands = { - new StructureRef(key("classic")), - }; - - private StructureRef[] t1Islands = { - new StructureRef(key("classic-sand")), - }; - - private StructureRef[] t2Islands = { - }; - - private StructureRef[] t3Islands = { - }; - - - private float playerIslandSpacing = 1024; - - private static final int T1_ISLAND_SLOTS = 8; - private static final int T2_ISLAND_SLOTS = 16; - private static final int T3_ISLAND_SLOTS = 32; - - private static float T1_ISLAND_SPACING = T1_ISLAND_SLOTS << 3; - private static float T2_ISLAND_SPACING = T2_ISLAND_SLOTS << 3; - private static float T3_ISLAND_SPACING = T3_ISLAND_SLOTS << 3; - - private Location placeStructureAtLocation(Structure structure, Location loc) { - Vector extents = structure.getSize().clone().multiply(0.5); - loc.subtract(extents); - - structure.place(loc, true, randomEnum(StructureRotation.class), randomEnum(Mirror.class), 0, 1, new Random()); - return loc; - } - - private > T randomEnum(Class enumCls) { - assert(enumCls.isEnum()); - return randomElement(enumCls.getEnumConstants()); - } - - private T randomElement(T[] array) { - int idx = (int) (Math.random() * array.length); - return array[idx]; - } - - private Location generateIslandNetwork(Location origin) { - Location centralIslandSpawnLoc = placeStructureAtLocation(randomElement(centralIslands), origin.clone()); - - int[] t1Slots = MathsUtils.sampleUniqueInts(T1_ISLAND_SLOTS, t1Islands.length); -// int[] t2Slots = MathsUtils.sampleUniqueInts(T2_ISLAND_SLOTS, t2Islands.length); -// int[] t3Slots = MathsUtils.sampleUniqueInts(T3_ISLAND_SLOTS, t3Islands.length); - double t1Step = 360.0 / T1_ISLAND_SLOTS; - - Supplier yNoiseFunc = () -> 0f; - - for (int i = 0; i < t1Islands.length; i++) { - StructureRef island = t1Islands[i]; - int slot = t1Slots[i]; - double angle = t1Step * slot; - double x = Math.cos(angle) * T1_ISLAND_SPACING; - double z = Math.sin(angle) * T1_ISLAND_SPACING; - double y = yNoiseFunc.get(); - Location pos = origin.clone().add(x, y, z); - placeStructureAtLocation(island, pos); - } - return centralIslandSpawnLoc; - } - - public int executeGenerate(CommandContext ctx) { - ctx.getSource().getExecutor().sendMessage("Generating skyblock world for " + ctx.getSource().getExecutor().getName() + "..."); - - // TODO Add team-specific offsets - Location originLoc = new Location(getOverworld(), 0, 128, 0); - Location tpLoc = generateIslandNetwork(originLoc); - ctx.getSource().getExecutor().teleport(tpLoc); - return 0; - } - - public static LiteralCommandNode create() { - var root = Commands.literal("skyblock"); - - var cmd = Get(SkyblockGenCommand.class); - root.then(Commands.literal("generate").executes(cmd::executeGenerate)); - - return root.build(); - } - -} diff --git a/src/main/java/com/ncguy/usefulSkyblock/StructureRef.java b/src/main/java/com/ncguy/usefulskyblock/StructureRef.java similarity index 99% rename from src/main/java/com/ncguy/usefulSkyblock/StructureRef.java rename to src/main/java/com/ncguy/usefulskyblock/StructureRef.java index 83ae031..f1afdc3 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/StructureRef.java +++ b/src/main/java/com/ncguy/usefulskyblock/StructureRef.java @@ -1,4 +1,4 @@ -package com.ncguy.usefulSkyblock; +package com.ncguy.usefulskyblock; import org.bukkit.Bukkit; import org.bukkit.Location; diff --git a/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java new file mode 100644 index 0000000..8360e5d --- /dev/null +++ b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java @@ -0,0 +1,104 @@ +package com.ncguy.usefulskyblock; + +import com.ncguy.usefulskyblock.world.PortalHandler; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.block.structure.Mirror; +import org.bukkit.block.structure.StructureRotation; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.server.ServerLoadEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Random; + +public final class UsefulSkyblock extends JavaPlugin implements Listener { + + private static final Logger log = LoggerFactory.getLogger(UsefulSkyblock.class); + + @Override + public void onEnable() { + // Plugin startup logic + PluginManager pluginManager = Bukkit.getPluginManager(); + pluginManager.registerEvents(this, this); + pluginManager.registerEvents(new PortalHandler(), this); + } + + @Override + public void onDisable() { + // Plugin shutdown logic + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + player.sendMessage(Component.text("Hello, " + player.getName() + "!")); + PersistentDataContainer pdc = player.getPersistentDataContainer(); + NamespacedKey initKey = new NamespacedKey(this, "player_init"); + if (pdc.has(initKey)) + return; + + NamespacedKey worldKey = new NamespacedKey(this, "void"); + World world = Bukkit.getWorld(worldKey); + player.teleport(world.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); + pdc.set(initKey, PersistentDataType.BOOLEAN, true); + player.sendMessage(Component.text("This is your first time playing on this server.")); + } + + @EventHandler + public void onServerLoad(ServerLoadEvent event) { + if(event.getType() != ServerLoadEvent.LoadType.STARTUP) + return; + + World world = Bukkit.getWorld(new NamespacedKey(this, "void")); + if (world == null) + return; + + PersistentDataContainer pdc = world.getPersistentDataContainer(); + NamespacedKey initKey = new NamespacedKey(this, "world_init"); + if(pdc.has(initKey)) + return; + pdc.set(initKey, PersistentDataType.BOOLEAN, true); + + log.info("Generating spawn point for world {}", world.getName()); + StructureRef spawn = new StructureRef(new NamespacedKey(this, "spawn")); + log.info("Entities in spawn: {}", spawn.getEntities().size()); + log.info("Palettes in spawn: {}", spawn.getPalettes().size()); + log.info("Palette count in spawn: {}", spawn.getPaletteCount()); + log.info("spawn.getSize(): {}", spawn.getSize()); + spawn.place(new Location(world, 0, 64, 0), true, StructureRotation.NONE, Mirror.NONE, 0, 1, new Random(System.currentTimeMillis())); + world.setSpawnLocation(0, 64, 0); + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + World world = event.getWorld(); + if (!world.getKey().equals(new NamespacedKey(this, "void"))) + return; + + PersistentDataContainer pdc = world.getPersistentDataContainer(); + NamespacedKey initKey = new NamespacedKey(this, "world_init"); + if(pdc.has(initKey)) + return; + pdc.set(initKey, PersistentDataType.BOOLEAN, true); + + log.info("Generating spawn point for world {}", world.getName()); + StructureRef spawn = new StructureRef(new NamespacedKey(this, "spawn")); + spawn.place(new Location(world, 0, 64, 0), true, StructureRotation.NONE, Mirror.NONE, 0, 1, new Random(System.currentTimeMillis())); + world.setSpawnLocation(0, 64, 0); + } + + +} diff --git a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockBootstrap.java b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockBootstrap.java similarity index 90% rename from src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockBootstrap.java rename to src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockBootstrap.java index 8fd52d4..45f89ab 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockBootstrap.java +++ b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockBootstrap.java @@ -1,8 +1,8 @@ -package com.ncguy.usefulSkyblock; +package com.ncguy.usefulskyblock; -import com.ncguy.usefulSkyblock.command.SkyblockAdminCommand; -import com.ncguy.usefulSkyblock.command.SkyblockGenCommand; -import com.ncguy.usefulSkyblock.hexagon.HexagonRenderer; +import com.ncguy.usefulskyblock.command.SkyblockAdminCommand; +import com.ncguy.usefulskyblock.command.SkyblockGenCommand; +import com.ncguy.usefulskyblock.hexagon.HexagonRenderer; import io.papermc.paper.datapack.DatapackRegistrar; import io.papermc.paper.datapack.DiscoveredDatapack; import io.papermc.paper.plugin.bootstrap.BootstrapContext; diff --git a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockLoader.java b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockLoader.java similarity index 88% rename from src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockLoader.java rename to src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockLoader.java index 4f4cdfa..4bae377 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/UsefulSkyblockLoader.java +++ b/src/main/java/com/ncguy/usefulskyblock/UsefulSkyblockLoader.java @@ -1,4 +1,4 @@ -package com.ncguy.usefulSkyblock; +package com.ncguy.usefulskyblock; import io.papermc.paper.plugin.loader.PluginClasspathBuilder; import io.papermc.paper.plugin.loader.PluginLoader; diff --git a/src/main/java/com/ncguy/usefulSkyblock/command/AbstractSkyblockCommand.java b/src/main/java/com/ncguy/usefulskyblock/command/AbstractSkyblockCommand.java similarity index 97% rename from src/main/java/com/ncguy/usefulSkyblock/command/AbstractSkyblockCommand.java rename to src/main/java/com/ncguy/usefulskyblock/command/AbstractSkyblockCommand.java index a2158d4..7617424 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/command/AbstractSkyblockCommand.java +++ b/src/main/java/com/ncguy/usefulskyblock/command/AbstractSkyblockCommand.java @@ -1,4 +1,4 @@ -package com.ncguy.usefulSkyblock.command; +package com.ncguy.usefulskyblock.command; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; diff --git a/src/main/java/com/ncguy/usefulSkyblock/command/CommandFunction.java b/src/main/java/com/ncguy/usefulskyblock/command/CommandFunction.java similarity index 87% rename from src/main/java/com/ncguy/usefulSkyblock/command/CommandFunction.java rename to src/main/java/com/ncguy/usefulskyblock/command/CommandFunction.java index e41b312..0d7885f 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/command/CommandFunction.java +++ b/src/main/java/com/ncguy/usefulskyblock/command/CommandFunction.java @@ -1,4 +1,4 @@ -package com.ncguy.usefulSkyblock.command; +package com.ncguy.usefulskyblock.command; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/ncguy/usefulSkyblock/command/SkyblockAdminCommand.java b/src/main/java/com/ncguy/usefulskyblock/command/SkyblockAdminCommand.java similarity index 82% rename from src/main/java/com/ncguy/usefulSkyblock/command/SkyblockAdminCommand.java rename to src/main/java/com/ncguy/usefulskyblock/command/SkyblockAdminCommand.java index 1d9979e..8533908 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/command/SkyblockAdminCommand.java +++ b/src/main/java/com/ncguy/usefulskyblock/command/SkyblockAdminCommand.java @@ -1,42 +1,33 @@ -package com.ncguy.usefulSkyblock.command; +package com.ncguy.usefulskyblock.command; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.Suggestion; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import com.mojang.brigadier.tree.LiteralCommandNode; -import com.ncguy.usefulSkyblock.StructureRef; +import com.ncguy.usefulskyblock.StructureRef; +import com.ncguy.usefulskyblock.utils.BoxVisualizer; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; -import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import io.papermc.paper.command.brigadier.argument.CustomArgumentType; -import io.papermc.paper.math.BlockPosition; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.block.Block; import org.bukkit.block.structure.Mirror; import org.bukkit.block.structure.StructureRotation; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.structure.Structure; import org.bukkit.structure.StructureManager; -import org.bukkit.util.BlockVector; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; -import org.codehaus.plexus.util.cli.Arg; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.xml.stream.events.Namespace; import java.io.File; import java.io.IOException; import java.util.*; @@ -45,6 +36,8 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand { private static final Logger log = LoggerFactory.getLogger(SkyblockAdminCommand.class); + private BoxVisualizer box = new BoxVisualizer(); + public int executeStructuresList(CommandContext ctx) { StructureManager structureManager = getServer().getStructureManager(); @@ -131,7 +124,19 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand { RayTraceResult rayTraceResult = p.rayTraceBlocks(8); Vector hitPosition = rayTraceResult.getHitPosition(); - p.getPersistentDataContainer().set(key("_p0"), PersistentDataType.INTEGER_ARRAY, new int[]{hitPosition.getBlockX(), hitPosition.getBlockY(), hitPosition.getBlockZ()}); + PersistentDataContainer pdc = p.getPersistentDataContainer(); + pdc.set(key("_p0"), PersistentDataType.INTEGER_ARRAY, new int[]{hitPosition.getBlockX(), hitPosition.getBlockY(), hitPosition.getBlockZ()}); + + Location p0 = new Location(p.getWorld(), hitPosition.getX(), hitPosition.getY(), hitPosition.getZ()); + Location p1 = p0.clone(); + + NamespacedKey p1Key = key("_p1"); + if(pdc.has(p1Key, PersistentDataType.INTEGER_ARRAY)) { + int[] ints = pdc.get(p1Key, PersistentDataType.INTEGER_ARRAY); + p1.set(ints[0], ints[1], ints[2]); + } + + box.createBox(p0, p1); } return 0; @@ -146,7 +151,20 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand { RayTraceResult rayTraceResult = p.rayTraceBlocks(8); Vector hitPosition = rayTraceResult.getHitPosition(); - p.getPersistentDataContainer().set(key("_p1"), PersistentDataType.INTEGER_ARRAY, new int[]{hitPosition.getBlockX(), hitPosition.getBlockY(), hitPosition.getBlockZ()}); + PersistentDataContainer pdc = p.getPersistentDataContainer(); + pdc.set(key("_p1"), PersistentDataType.INTEGER_ARRAY, new int[]{hitPosition.getBlockX(), hitPosition.getBlockY(), hitPosition.getBlockZ()}); + + Location p1 = new Location(p.getWorld(), hitPosition.getX(), hitPosition.getY(), hitPosition.getZ()); + Location p0 = p1.clone(); + + NamespacedKey p0Key = key("_p0"); + if(pdc.has(p0Key, PersistentDataType.INTEGER_ARRAY)) { + int[] ints = pdc.get(p0Key, PersistentDataType.INTEGER_ARRAY); + p0.set(ints[0], ints[1], ints[2]); + } + + box.createBox(p0, p1); + } return 0; @@ -160,8 +178,9 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand { if (!(executor instanceof Player)) return 0; Player p = (Player) executor; - int[] p0 = p.getPersistentDataContainer().get(key("_p0"), PersistentDataType.INTEGER_ARRAY); - int[] p1 = p.getPersistentDataContainer().get(key("_p1"), PersistentDataType.INTEGER_ARRAY); + PersistentDataContainer pdc = p.getPersistentDataContainer(); + int[] p0 = pdc.get(key("_p0"), PersistentDataType.INTEGER_ARRAY); + int[] p1 = pdc.get(key("_p1"), PersistentDataType.INTEGER_ARRAY); if (p0 == null) { executor.sendMessage("No P0 found"); @@ -190,6 +209,9 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand { f.getParentFile().mkdirs(); getServer().getStructureManager().saveStructure(f, structure); log.info("Saved structure {} to {}", name, f.getAbsolutePath()); + pdc.remove(key("_p0")); + pdc.remove(key("_p1")); + box.cleanup(); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/ncguy/usefulskyblock/command/SkyblockGenCommand.java b/src/main/java/com/ncguy/usefulskyblock/command/SkyblockGenCommand.java new file mode 100644 index 0000000..428e885 --- /dev/null +++ b/src/main/java/com/ncguy/usefulskyblock/command/SkyblockGenCommand.java @@ -0,0 +1,198 @@ +package com.ncguy.usefulskyblock.command; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.LiteralCommandNode; +import com.ncguy.usefulskyblock.StructureRef; +import com.ncguy.usefulskyblock.utils.MathsUtils; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.block.structure.Mirror; +import org.bukkit.block.structure.StructureRotation; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.ScoreboardManager; +import org.bukkit.scoreboard.Team; +import org.bukkit.structure.Structure; +import org.bukkit.util.Vector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Random; +import java.util.function.Supplier; + +public class SkyblockGenCommand extends AbstractSkyblockCommand { + + private static final Logger log = LoggerFactory.getLogger(SkyblockGenCommand.class); + + private StructureRef[] centralIslands = { + new StructureRef(key("classic")), + }; + + private StructureRef[] t1Islands = { + new StructureRef(key("classic-sand")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic-sand")), + }; + + private StructureRef[] t2Islands = { + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + }; + + private StructureRef[] t3Islands = { + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + new StructureRef(key("classic")), + new StructureRef(key("classic-sand")), + }; + + + private float playerIslandSpacing = 1024; + + private static final int T1_ISLAND_SLOTS = 8; + private static final int T2_ISLAND_SLOTS = 24; + private static final int T3_ISLAND_SLOTS = 48; + + private static float T1_ISLAND_SPACING = T1_ISLAND_SLOTS << 3; + private static float T2_ISLAND_SPACING = T2_ISLAND_SLOTS << 3; + private static float T3_ISLAND_SPACING = T3_ISLAND_SLOTS << 3; + + private Location placeStructureAtLocation(Structure structure, Location loc) { + Vector extents = structure.getSize().clone().multiply(0.5); + loc.subtract(extents); + + structure.place(loc, true, randomEnum(StructureRotation.class), randomEnum(Mirror.class), 0, 1, new Random()); + return loc; + } + + private > T randomEnum(Class enumCls) { + assert(enumCls.isEnum()); + return randomElement(enumCls.getEnumConstants()); + } + + private T randomElement(T[] array) { + int idx = (int) (Math.random() * array.length); + return array[idx]; + } + + private Location generateIslandNetwork(Location origin) { + Location centralIslandSpawnLoc = placeStructureAtLocation(randomElement(centralIslands), origin.clone()); + + int[] t1Slots = MathsUtils.sampleUniqueInts(T1_ISLAND_SLOTS, t1Islands.length); + int[] t2Slots = MathsUtils.sampleUniqueInts(T2_ISLAND_SLOTS, t2Islands.length); + int[] t3Slots = MathsUtils.sampleUniqueInts(T3_ISLAND_SLOTS, t3Islands.length); + double t1Step = 360.0 / T1_ISLAND_SLOTS; + double t2Step = 360.0 / T2_ISLAND_SLOTS; + double t3Step = 360.0 / T3_ISLAND_SLOTS; + + Supplier yNoiseFunc = () -> 0f; + + extracted(origin, t1Islands, T1_ISLAND_SPACING, t1Slots, t1Step, yNoiseFunc); + extracted(origin, t2Islands, T2_ISLAND_SPACING, t2Slots, t2Step, yNoiseFunc); + extracted(origin, t3Islands, T3_ISLAND_SPACING, t3Slots, t3Step, yNoiseFunc); + return centralIslandSpawnLoc; + } + + private void extracted(Location origin, StructureRef[] islands, float islandSpacing, int[] slots, double step, Supplier yNoiseFunc) { + for (int i = 0; i < islands.length; i++) { + StructureRef island = islands[i]; + int slot = slots[i]; + double angle = step * slot; + double x = Math.cos(angle) * islandSpacing; + double z = Math.sin(angle) * islandSpacing; + double y = yNoiseFunc.get(); + Location pos = origin.clone().add(x, y, z); + placeStructureAtLocation(island, pos); + } + } + + public int executeGenerate(CommandContext ctx) { + Entity executor = ctx.getSource().getExecutor(); + if(!(executor instanceof Player)) + return 0; + + World overworld = getServer().getWorld(new NamespacedKey("minecraft", "overworld")); + + PersistentDataContainer pdc = executor.getPersistentDataContainer(); + + ScoreboardManager scoreboardManager = getServer().getScoreboardManager(); + Scoreboard scoreboard = scoreboardManager.getMainScoreboard(); + Player player = (Player) executor; + Team playerTeam = scoreboard.getPlayerTeam(player); + if(playerTeam == null) { + executor.sendMessage("Not part of a team, can't generate skyblock world"); + return 0; + } + + executor.sendMessage("Generating skyblock world for " + playerTeam.getName() + "..."); + PersistentDataContainer worldPDC = overworld.getPersistentDataContainer(); + + int count = 0; + if(worldPDC.has(key("skyblock.team.count"), PersistentDataType.INTEGER)) { + //noinspection DataFlowIssue + count = worldPDC.get(key("skyblock.team.count"), PersistentDataType.INTEGER); + } + + Location originLoc; + if(count == 0) { + originLoc = new Location(overworld, 0, 96, 0); + }else{ + int ring = MathsUtils.getRing(count); + int slot = MathsUtils.getSlot(count); + + int numSlots = MathsUtils.getSlotsInRing(ring); + + float step = numSlots / 360f; + float angle = slot * step; + float x = (float) Math.cos(angle) * playerIslandSpacing; + float y = (float) Math.sin(angle) * playerIslandSpacing; + originLoc = new Location(overworld, x, 96, y); + } + + Location tpLoc = generateIslandNetwork(originLoc); + + // TODO Sanitize playerTeam.getName() + worldPDC.set(key("skyblock.team." + playerTeam.getName()), PersistentDataType.INTEGER_ARRAY, new int[]{tpLoc.getBlockX(), tpLoc.getBlockY(), tpLoc.getBlockZ()}); + worldPDC.set(key("skyblock.team.count"), PersistentDataType.INTEGER, count + 1); + + executor.teleport(tpLoc); + pdc.set(key("island.home.loc"), PersistentDataType.INTEGER_ARRAY, new int[]{tpLoc.getBlockX(), tpLoc.getBlockY(), tpLoc.getBlockZ()}); + + return 0; + } + + public static LiteralCommandNode create() { + var root = Commands.literal("skyblock"); + + var cmd = Get(SkyblockGenCommand.class); + root.then(Commands.literal("generate").executes(cmd::executeGenerate)); + + return root.build(); + } + +} diff --git a/src/main/java/com/ncguy/usefulSkyblock/hexagon/HexagonRenderer.java b/src/main/java/com/ncguy/usefulskyblock/hexagon/HexagonRenderer.java similarity index 98% rename from src/main/java/com/ncguy/usefulSkyblock/hexagon/HexagonRenderer.java rename to src/main/java/com/ncguy/usefulskyblock/hexagon/HexagonRenderer.java index b5155dd..092c852 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/hexagon/HexagonRenderer.java +++ b/src/main/java/com/ncguy/usefulskyblock/hexagon/HexagonRenderer.java @@ -1,4 +1,4 @@ -package com.ncguy.usefulSkyblock.hexagon; +package com.ncguy.usefulskyblock.hexagon; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.tree.LiteralCommandNode; diff --git a/src/main/java/com/ncguy/usefulSkyblock/utils/BoxVisualizer.java b/src/main/java/com/ncguy/usefulskyblock/utils/BoxVisualizer.java similarity index 66% rename from src/main/java/com/ncguy/usefulSkyblock/utils/BoxVisualizer.java rename to src/main/java/com/ncguy/usefulskyblock/utils/BoxVisualizer.java index 6b2cd6c..554b69b 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/utils/BoxVisualizer.java +++ b/src/main/java/com/ncguy/usefulskyblock/utils/BoxVisualizer.java @@ -1,5 +1,6 @@ -package com.ncguy.usefulSkyblock.utils; +package com.ncguy.usefulskyblock.utils; +import io.papermc.paper.entity.LookAnchor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -32,12 +33,12 @@ public class BoxVisualizer { } // Get min and max coordinates - double minX = Math.min(corner1.getX(), corner2.getX()); - double minY = Math.min(corner1.getY(), corner2.getY()); - double minZ = Math.min(corner1.getZ(), corner2.getZ()); - double maxX = Math.max(corner1.getX(), corner2.getX()); - double maxY = Math.max(corner1.getY(), corner2.getY()); - double maxZ = Math.max(corner1.getZ(), corner2.getZ()); + double minX = Math.min(corner1.getBlockX(), corner2.getBlockX()); + double minY = Math.min(corner1.getBlockY(), corner2.getBlockY()); + double minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ()); + double maxX = Math.max(corner1.getBlockX(), corner2.getBlockX()); + double maxY = Math.max(corner1.getBlockY(), corner2.getBlockY()); + double maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ()); // Create the 12 edges of the box // Bottom rectangle @@ -58,6 +59,31 @@ public class BoxVisualizer { createEdge(world, minX, minY, maxZ, minX, maxY, maxZ); // Back left createEdge(world, maxX, minY, maxZ, maxX, maxY, maxZ); // Back right + Location center = new Location(world, (minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2); + + Location min = new Location(world, minX, minY, minZ); + + BlockDisplay glass = world.spawn(min, BlockDisplay.class, entity -> { + + Vector3f delta = new Vector3f((float) (maxX - minX), (float) (maxY - minY), (float) (maxZ - minZ)); + + entity.setBlock(Material.GLASS.createBlockData()); + // Create transformation + Transformation transformation = new Transformation( + new Vector3f(0, 0, 0), + new AxisAngle4f(0, 0, 0, 1), + delta, + new AxisAngle4f(0, 0, 0, 1) + ); + + entity.setTransformation(transformation); + entity.setBrightness(new Display.Brightness(15, 15)); // Full brightness + entity.setViewRange(64f); // Visible up to 64 blocks away + entity.setPersistent(false); // Will be removed when chunk unloads + }); + + displays.add(glass); + return new ArrayList<>(displays); } @@ -86,19 +112,17 @@ public class BoxVisualizer { double dy = y2 - y1; double dz = z2 - z1; - // Calculate rotation angles (in radians) - double yaw = Math.atan2(dz, dx); - double pitch = Math.atan2(dy, Math.sqrt(dx * dx + dz * dz)); // Create transformation Transformation transformation = new Transformation( - new Vector3f(0, 0, 0), // Translation (already at center) - new AxisAngle4f((float)pitch, 0, 1, 0), // Pitch rotation - new Vector3f((float)length, LINE_THICKNESS, LINE_THICKNESS), // Scale - new AxisAngle4f(0, 0, 0, 1) // No additional rotation + new Vector3f(0, 0, 0), + new AxisAngle4f(0, 0, 0, 1), + new Vector3f(LINE_THICKNESS, LINE_THICKNESS, (float) length), + new AxisAngle4f(0, 0, 0, 1) ); entity.setTransformation(transformation); + entity.lookAt(centerX + dx, centerY + dy, centerZ + dz, LookAnchor.FEET); entity.setBrightness(new Display.Brightness(15, 15)); // Full brightness entity.setViewRange(64f); // Visible up to 64 blocks away entity.setPersistent(false); // Will be removed when chunk unloads diff --git a/src/main/java/com/ncguy/usefulSkyblock/utils/MathsUtils.java b/src/main/java/com/ncguy/usefulskyblock/utils/MathsUtils.java similarity index 60% rename from src/main/java/com/ncguy/usefulSkyblock/utils/MathsUtils.java rename to src/main/java/com/ncguy/usefulskyblock/utils/MathsUtils.java index abca42b..6728427 100644 --- a/src/main/java/com/ncguy/usefulSkyblock/utils/MathsUtils.java +++ b/src/main/java/com/ncguy/usefulskyblock/utils/MathsUtils.java @@ -1,9 +1,6 @@ -package com.ncguy.usefulSkyblock.utils; +package com.ncguy.usefulskyblock.utils; -import java.util.ArrayList; -import java.util.List; import java.util.Random; -import java.util.stream.Collectors; import java.util.stream.IntStream; public class MathsUtils { @@ -45,5 +42,32 @@ public class MathsUtils { return result; } + public static int getRing(int count) { + if(count == 0) + return 0; + double log = Math.log(count) / Math.log(2); + log /= 2; + return (int) Math.max(1, Math.ceil(log)); + } + + public static int getSlot(int count) { + if(count == 0) + return 0; + + // TODO make respect value from getSlotsInRing + // Count exceeding 12 will cause the tests to fail, + // as the slot returned from here exceeds getSlotsInRing + int ring = getRing(count); + int base = ring << (ring+1); + int diff = -(count - base); + return getSlotsInRing(ring)-(diff+1); + } + + public static int getSlotsInRing(int ring) { + if(ring == 0) + return 1; + + return ring << 2; + } } diff --git a/src/main/java/com/ncguy/usefulskyblock/world/PortalHandler.java b/src/main/java/com/ncguy/usefulskyblock/world/PortalHandler.java new file mode 100644 index 0000000..9576e94 --- /dev/null +++ b/src/main/java/com/ncguy/usefulskyblock/world/PortalHandler.java @@ -0,0 +1,20 @@ +package com.ncguy.usefulskyblock.world; + +import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.PortalCreateEvent; + +public class PortalHandler implements Listener { + + @EventHandler + public void onPortalCreate(PortalCreateEvent event) { + if(event.getReason() != PortalCreateEvent.CreateReason.FIRE) + return; + + Entity entity = event.getEntity(); + if(entity == null) + return; + } + +} diff --git a/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/overworld.json b/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/overworld.json new file mode 100644 index 0000000..0d42178 --- /dev/null +++ b/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/overworld.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:overworld", + "generator": { + "type": "flat", + "settings":{ + "layers": [], + "biome": "minecraft:void", + "structure_overrides": [] + } + } +} \ No newline at end of file diff --git a/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/the_nether.json b/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/the_nether.json new file mode 100644 index 0000000..f47e112 --- /dev/null +++ b/src/main/resources/datapacks/usefulskyblock/data/minecraft/dimension/the_nether.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:the_nether", + "generator": { + "type": "flat", + "settings":{ + "layers": [], + "biome": "minecraft:void", + "structure_overrides": [] + } + } +} \ No newline at end of file diff --git a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension/void.json b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension/void.json index 0d42178..c0af0e5 100644 --- a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension/void.json +++ b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension/void.json @@ -1,10 +1,15 @@ { - "type": "minecraft:overworld", + "type": "usefulskyblock:skyblock", "generator": { "type": "flat", "settings":{ - "layers": [], - "biome": "minecraft:void", + "layers": [ + { + "block": "minecraft:grass", + "height": 64 + } + ], + "biome": "minecraft:plains", "structure_overrides": [] } } diff --git a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension_type/skyblock.json b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension_type/skyblock.json new file mode 100644 index 0000000..d832977 --- /dev/null +++ b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/dimension_type/skyblock.json @@ -0,0 +1,24 @@ +{ + "ultrawarm": false, + "natural": true, + "coordinate_scale": 1, + "has_skylight": true, + "has_ceiling": false, + "piglin_safe": false, + "infiniburn": "#minecraft:infiniburn_overworld", + "ambient_light": 0, + "bed_works": true, + "respawn_anchor_works": true, + "has_raids": true, + "logical_height": 256, + "min_y": 0, + "height": 256, + "effects": "minecraft:overworld", + "has_portals": true, + "monster_spawn_light_level": { + "type": "minecraft:uniform", + "min_inclusive": 0, + "max_inclusive": 7 + }, + "monster_spawn_block_light_limit": 0 +} \ No newline at end of file diff --git a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic-sand.nbt b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic-sand.nbt index 54d538436ef5c82d8191c25febad96be3bc407e9..1730d8af58845aeea091d6f232b5b462da709b6e 100644 GIT binary patch literal 569 zcmb2|=3oGW|Gn4l=G}4-V0|$2BY&Go<`peZ`Nh}wzVppr6*jd@BW-`F_QNQsFL-NdS3qcu-Uvs1?6-jo(K?R0z#q9Kfc`hd811Cu*0)CM;ky; z6%1W}uRCs>EX#G_;S6NKzZGd~4zs){IFocB>3|RrPMV>*{Q5k(XiuBN4sPdCBsNGy zxHput{5T`DS?OjJ;k}YIwY9y0<=eZEE(khu%L| z*!gJw7AyJtOJ`nb_SC%K_IH1KH2;R~oRD|ijwdN{?D%kalviA*I&PJe=U{U92y^x6z273 z<~Qc)hZ{D&{rBPSM=So*r)*yfSp1XgpHq|R6}^5}_2Jw@$&TXZ@9JI(%iDU1HPt(~ k@@*KGes9pb-3d!;`CG3Y{KlPAZ&ARJ@%s>=u$3%e`NF3)u{77uyo$uT@z7IP- z+A3|@$R9U}@44rE-|zcfyUojpHU`slrIVC`Ris@?p%KcDR_U-0hRwMW%|4K95Cd3wrp(&Tn@ zFm-2LCSN3A=$Dxddi_i!pwHIps)OU*Ms>*Qs0a;3ZRO0^n{|aUbJQ{E^x9NDBfT%| zuo)E>t{ctn9KSnDa@=txOVadK@qrur2DTdOOHVFodTaV-YkzIH#=}f+)f@9yAZ4iW+rdhEB2yCycj82%K0vgbMF>Z8>09u?=~;=P@&jXHEk(xTcw-#|1Y z8bw)E?Cdf%bvw<}=!uH$Ik~VRJv#LZO_J5wN#jP9TBleOMu;X~9G`rEWODDG;XBx1 zOLg5J4Ll6^R-MxUN2p~!Jq(hD(eoPwA6d4HX}|1K9S$fbHlK<% zMy~Bi{C$y^kClxK+4n(n5UBr&i1-DInw6yq;2^H{Pq5byb>F3u2G%Pxcxhi72% zs!+m$#0)6MdCq8y$C9~-lAH&Nx9wIkuu!h>@S&&3T+Jo(!6hT}!Axdcl+3tHGUN7I zU9|z^KK&R#s(l3TFFpq`m5hO!B3dqlNLk*70AA+DIuR=o(yx9a-~}Fw8OlTatzX#{xQ^a;M_sroNNG8P_jX9t!lmHwGY=Ic@#=m zf{2jF#VbRW1JPO}rSl79IMVqo5PC9fhhGjuic9NuR$WGRFu6#sg*uzi7;b9zS-UEE zs*=cutR({ZV&w<>%(2+AO(1IY^`y?*$P~9QsUQ^M7;x%>wljqcX`|EqsnS2;s8HuM zlKFgf_6FyTl1Q1k2q$po79m$^+*wv}5biS_W2o0a{prO(xIQde`5@P&PrwEe(XRqi z65ocxoRoPYS$m%>B(izInJagFWJR!5E#M2wIFU4eks`n>3*&W_zAmmaJy$pVwk>{X z%*g%x>T?@-m%;+{Z~P)(3W{0K*=tO#v@;$tz};0AvzWEPraS$wPo5_)cuxv_v$ zd_frN)geCc7lg48?f8Ot-Uc$`OujpwEi1sb5hQ8O59Hv)nFcT`z}DJ|-()6kYm-=r zKN5Mfh0L4%WZponjRTdy15%6!1>Wb)Mx@mrQ8bDpAsRwJONapVYRKrpOl+kiz6-#)RNN9jc7!|swRQS=2e`8bwLKE!b!AA=fw;nQ@b_IVLd9)ESYNfyMMwuzVhX zE?)uudmm-Dr8R{p(c-srdA7{?$ZjRMP~d|D*KT$!$TAlSd~o1`%3=rV$%O(R9MVSw z9~`*YvoVG3F!y0EAvSPu;8^R;P^$aHE+ItdeHga6z@PH7K@%OP96(f2qtmeq4d))n zFagEKb5XMp2qFvnFmrVgiag4Z=<)CSZEwFaZgSLj=sLLC8hv)hK5e z?bCooaW@?KdgG0|Wrz-pZixB8A?9~Lv^UHt`h?w^fpVt{OK4Qav|J#WIdpi z-8(*!Xgis7K)KtcdwxGT;VkLfercIS6Lhhq)3?$1b zA@{w|NhWXxI>`h&PPi|5_>BS47U(zREVYbEID< z%d=rZMH6gFQz_bi@2P{ziHuky`LUdGO81(yt4g7f_`96hy4v8txRdhem`J%N78}18 zZu2pN;c=UBQhG5+DSFLPCNvO^TsY9`i_JuBUiYPjXty_WCS-SX`1?DfUqoMt4&_Yw zei?PrQ!0IA+^9S|GuC0W+5Amifge`pNGDX3^0v(ulq&1a%~X06I^UvEwc?gqp+A?~ z*hnk&kx(QkouJhbS(9#hGSlx-$fK_g-Zz^4Qi_t&>Vw_;oKde+DmCjPr$fF5e^ZlE zcfd8>7}U>5)%xh@WQ(;fI60id47GIKFSpjk28}tvDSZ?fW1}dKTv4|$5@@jb>{d;S zbj+#NpYwO=nQ>Jkr5tSWhfb>wgknCkUlAGW`I}9tU}Ej=$i43$p*;G?K!eS1iU!L) uO1W-&Bdw3!+n2w#?t30(lXbDpmPz|BQ@4)!Uv@H!zUe7Cvwz*f1^)zII)+gI diff --git a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic.nbt b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic.nbt index 6812fbadf1b687fb6ba58df6c93c468a7f4f9ab4..5dcf63b42ab7425bcd1ebb55a71b307c5b4e2397 100644 GIT binary patch literal 3125 zcmZ`)3sjP68n&6OX^XK_YNB~*Vk=$KqCYGRVs~(K8ZF(^WMy6o3oBi7Fe^22Cr=n& zGD;KgOIDVqX37{Uc0s%(h($_fNS5I>bi81S;C?@p&}BLAd4A6GU7q)SzwdoN>%@fy zn%^udyD8M7$>b*#L|te2Zr&Yy-J3_j$7|4tO|Oc*uKsfDM`PPNh2Kpj&IGEL?7>8A z$Dl@Yn$Ima9)_q@^uu-D6fRfuOh-ljh77t7ucX1ysb&vsDP;zDLQ)zSc| zc`Y|eGXv`jvrQqP=MZ!W09hb*Z+adwybbftK;Y$qD6ML2!z125oT%1wQGJwS28i;%%4fyKve?@ne7EN;IV6nQq9fWS4Ux@&;Hp1dQFntS*$3(2l)E%%rMEMAC7 z$slgP9Qc1*9a~V2tHzw_~n!2n@A5vlkM|;*|7`8#(clMf%L#I6xp__ z@E2%SY^@cAG$^)Re{bhs8OMBsriYw~vW7gjp$1ONdQvEd8y_>Xm}CZp-|@B*l#?xk za?LmJ7;GeD8Ym<3eO;mB)6w}^?Bon5M!^M=KYJ%yMk9shN4{V*)kmy~FDU)~kg3sO zQ=?)`4C$&e$Xo!OzEU0OUGj#%D{hdVpYfeAdh^%;Y2SyXxuTHMEr5+)90@*qWHkBI z#>~i(8WG3G6)N>z8@03fh^$<_PfoJJ4omoPG5J}MZ=HFJwVCW>nc2_^3D!808SJaGG)LL{4Py#2a>@<}vwV?P zJ?J|we8n||E2~^%KrceFbx=qzGG_z$EN<_pnf1_#8;8Q}op)JL)cn?rOWoUy2|>S5m0=q#cG4^p zV3p4R76l`;ne)JyscOho93`!a_f)QeP8eR|61Nx=dRIEFqgh_5(;R1O zhPxq82QG%e#CS{@0ZrE$mjo90oz5Ci z40&FqcCWm2e}VrAOn*0+N5vCwih;nh!A7Rq?;jwS6V7BCYLw;FQUd1!h{4~DQU|8t zb<>ao5j}U1pD)(1=3iyOW&Ko0b3MD^_$4X86FKb3BjB+#O~^tqPbA zb07a+?)E}N;DK{h)=s*W6T`S$N;m*jBgg}##|_LG%@03UWep;bq{zz(!Y`NsUbA*D zLL;J?&4g!b+3$7i!5u?iQ_=aygB{a%Kr>|9&$+|*njGAQKX{HQ7spT@Eh0!te}{$4 zw`6}+^``L8|9*%ZBv(nd)`XyN`541kg&U-Q1o?C20$0jvYSnVpOP*KCDzMm%o=1AW zlz>YB=VkR1NM_0^5Rn_53p*QS46=nw0D1m6WZN&D+Cab+D%a(hP@{gG+~;hEn7BC~ zp27MLAx360VFO3NLf zvqgj;(E>6J)C_q?J@ztMc!&?J7~|Jt%hAFR{^jJzyJ%01B2TB7Jf|pNxFOzkk7qlg z_CRFJhj);8WXbThQ=#XWxNIP(g&73=w?>I5F`+6(Adp8z*kg>@n1@C)WKL77)xlW1 zVlKJ_U3BJSn*y!S74f3*7fHSX(6+R1E)CxK%zdzP7)YQNM#8}vC`RPaTW{nGuJDI+ zfVN@~oJLaKaGx|2ZWc>m zN8`0^3=i^l)B2Jg3%9W^S-6dT!G@th#wb63IGTP;o&T(9l8HY$7F6MG%K4{SG?p7&no&S z1BSa^O8q#oGx_VUoIZ75G919EbyEKs={ze|Ng5=o?x;$s#r2n6s`s{Sm7Q5Chh&H7 z%9z;!nOssnY}c7rGI?}*eDwHKfB$~UxE=KWVM|ghH+!kvu;8cBKD}1535ErXwd;B>1guryuF*srH_Ge|hfv{+{Rkz0dQ$?~OWg=WPrBSbsNQ$cy+z!Ry^W_}Nph{5&%9 zzox8{ZC|Vsi0@5Yzwi9_x0VYgItDH0f23=DNJ{6Aoxbf+9`n*$L%-3jPJDA~&dxJ* z#@wXdIwLBgPDJHISWTBN%#aFehkm9%rs2wzI%DWa z#@tk`evawA*(()T3H{7pf1Fn`pw*k3A`JUCOUj1}+P7)>T^9!SU)j~Ztu#UuQJ_4e z9Xj0vJvu`b2(W_L^W!G_fXw!dC5?Z5RG$F-4Rt-kmAj-T#R{vjL~VTQz?e_^p~ z>NZkY^Y1#>%2UjoO3IFoRAekqRtxpy=XVTBek#!pCH5vOo=r&5$CrL=>6=#RE18LL z@fX7+ZHtc2FZy6~&cC#6}f#%0Jvd?`rQXeL7YzpV5wI4R`by{)RT5 zs$yQWtdVxsRF>Bc>jVSFvBL6_whSvZdzf!*Ns%^mZ|l{^PfhER;)xf{@`y_Gd`-+pF=bbM)W=^ls z)GKmsSR}>Ssug*HD)L3kXys7s8X^@PJ(RpCdw50OmIY(fCq-{R zH^mny=dIsjoo*#5vh6R%nJd>4nwjrVmGY7ssu6u|Nrr^pw^`CyBWtbUnYzMkxp^XyL5#AQzn*_qnTCFr!h`^{W-e|m%6 zQx9|5sJrZqTFT}7C)gu(GnY)2HQ7nk&!wqShpGJ>I+aXsH+7mzQgsmyu1 zshm21&|xZxWggn0+Sei?%O9f;W1iy*2PK~xihs3oU0YHJs_V$$aLsxtuoD;Gc|jbq&9Q*FM! zc0Th(k(^3j8bPWf2+$4$=t>0rV-WPOzXAyU=?L=asch<$DYoT&_jafo zL;a6KoD$34dyCN|ZJ&mt^fc+7m(&?mp*L^(QYR(fyQvJ34;3DRRE(Ak zrH#GjP}4$j3LgTM&MpdeHaOxd^b?c8HLz}*pFz5MjJL2NCZM%CEV5JDeo269fp|-4 z<-w;*1GAT8n?{ueVs8K%wVk!Sx_}BZ7MAw*dUPxABUbYuiwHpmo=Bz7CX#+?c|oaE z!XJUP0XBfc5eD;o44dS@Vz_oZz)}s+d0r!gETl}jH%26}@+QP>tZXB zLrX#$*%NfLIt{|=M%OWeY34?%G0n~t=1!^-6^k*VA>?LtikYo;3X}a@H0vTm=-hb< zGp*b-t3&?T{D|tOuMf9xvNBXCgT7M>II*pd+csF>8vy}z2ux1PDo&t0(@l<=H+nHy zLGG?D3UI)8>Ufu$k!K~iNIxf6XMZtf(NvH82e3OQ z{uFCamLgIB>;x;zwsbgy5z+f=5V;yN0yG_wrWb^$fIKR^W&}@VO`MOZwtX3F=Rko_ zm7GP4r=`B;z`>4(p-WW{gM%6|o+KgIFGmoSxqu*QE+G9$P9um~erTLF0n(}n{%a7R zB$pEvhfIfnu5__9x-l{EeAiORk%mxy&4^XBG9AEECFcO3G-SamWFcWDB2X0|K+gg? zN`ffTN)W5_0?Vng)IYKoK%3Htj-nwvg{+}&LJU$Cm(cGRWmtBzV@Bq#{-Yqu4>6v| z5tDwdvZ*f3OFxH*eIp3vr$rEzLJ&3i%2m(?s$gegOLdgPxw;Ter9w=nlnBr?M22FC zMy=>qg;=DwB@=cdJoPHVQz2WO>JaYlv-BUVvsEK3Wl{MLe0YVdqzk@6>%G1}>_?Cv zvN{p6B@fb35S|8G_4la}Da0T(h!{`gh)e>5*gZ(^MYt4=7*8q?0hQB&zk|Id1W{WN zL_KXg>+RHfu1;cdnp21niW&k+AnIsc2vDbTzlVxQ;N$+nbRZgGsmCR%jijFiXb$)B z@+M?hrFxe}VU_Bb%KBlEi{}twmFg6;y{88PYSXWjO0}xbPQU;1LwCJ$-#rGNdU$kB zoA&EFl3w|bm#U6T-u?3jKCkl?lW0K`_h+@pDhIgVTi@Je4mJXK@AbhVfD#DqS0K1Qg5Z8Gfctb3fcp%B`*H;LTM;xhA!w>b(3Aqu zR5VOk_k?f~zl$h!8iUp#wA3<$mfDQy{~<*GUj+0&c@Pk$B#!{X6ip2+?1s^l3?LIv~^iYd}PiY(&VODuC=+Lm)Dph|#nbF`8-+qbY+JO?M+` z%JWK7a>CRXjXTbd&+nQ3Z&OO7PlI-lpB&#}UVPu0u?t1YV|5tVTG8W$v~9 zNW^Skh@fdQ0+d8>zXQSjLjdm6h!lbh!F@S``$-7yXCP=wA!ten`})lvS!rkCss(T0d8`vLKUMl6q0~n5)o03AZYpxTztCa^_TC8fA|k64_^ASLZqw+Jw^0v0YOQQPLdWjfBtm#F>ntsHPSPU2vX+$P~L1Y5t2=2EcXbM^N zVnWcg(?mUXk^5sU)*vEEc#o6+HEixH#e7E7_=)fyr;yg+d2HQiL`2z&82DJPAzh*= zJ*d3uz9;-^Q4h~~RIUAN!1AZrsn+}izXI59mrwa<;YuBzWUmf=iP`Hzqn^~TN3Cj? znBs!?3)0?egF9=Aq`uPIWO%ER_tTX;I=%mk&4>y8AYwvKA!1GVq$e+@BL=x}$2M+# zt+pyjIp0xdQ!nAIO1`3aP|Qk2M3nGWCI90?fZAT-eXCMX{k~wJ4zZ&yjdg9zL-NvH zFd94a-1D36w|LKly5DK+;u6fj63l0Y^7<@$QRgKcdP@LCWtu`whb|;kr#4Re%DuX% zO`E(ttf}j+-g(SCU>BPA`&eNmv$3tpdZ$+Wz{R)j``*9z^(ZA>W<^JQ|6BKTKmD8G z-7V{H)Bk>M&n5NIspC&79{x<2GJEm$sW)HIQr3VpWN|q_TwqJ7hhku>fDcN8uwiCa50S-^l;VF ztwq)BMNBnoI|EQg{Rq$|_MlCQ-aLnr^VO~vjn-RhdumsEzjU`e;VZC{yKaUc86CmX ztp~~d2++Ll_SV^l=NF-e%xyx)7iS1SkOjRU+C{iD*+LqD_^EHcdmcX&RzU(^$8u zXEC}|9$h_rljW@g{p{0hMnsDm5iM$D-J$`gLt{WJopzGFzC!zQM82aO0V+g*5(v;3 z1ZV>SREz+n5TH>AP&EQH0|9D6fF>hA^$1Ygp82Q$m8(k3qMVehFXA4QhUor$fbJ)= z5TJz!&^-vyg9y-l2v9i!bTB%J*`}?XrTwQYO^s%Gn1pn(97Jm9bLJ^Cl5A(MU_GCIr`o40T3qdrnv?ty$~pZHoi>csL$#4@T#5nyeWDi}-2>!x$}`bvnC zh#W`-0<;$aszrcW5TNAZsppe}-CWNJxdh79L!eW!-#i`*MJwR)J<7)K2 zb9MHt+@G(G`d52?CETi9Ci~_RVfUq4V)48~0m>7neXB*5pskg~p4BGH=N)3z)YZyD z!ukiLGEF`t@U7=>BnfIPAN$O(I(luEMXy!8)V-=WMRa4;scsRw%xHLLQc!V)p!GQk zUUSYeM7>gms8`Cub#+IHm1W9*X?nqFinee@M7XXVKm~zi>)Yz;$v^WoISjJ*?m(nl z6~Rn@-C5**(#SHzM7<1QX&J)ORD`9e2ur&VmUba5jb>-5r?RhIlsF{=ZCjE&SBRZ% z^^y&Akx~sTRFhja(dBtZ-m#aX6k|0VRo&G^_mECA5+Z;VHA+qBor_7B|LNAuYT~|cT;k1zx@nlJMS}dMeIla z7&BIw!SV=Pau?z=I2!@qS)D)Ol=Fk+1+350^>Oy9`*%XpLpkahPx(4( z-Ni|1#7B@N2?%bg0U>ne6aZ9!_~2b6;!9#eL|i5jak&E#mk)&&m+7gdmL=b3CBh&3 zW#2BSSd_T7f zF-EOK(6j?V)5{2&9!AhK7C=)Sf~GT-0DWdeaNmsJz5)Td9N|#y2#4xHIFt>5jN=3Mo2;ovR!lm9r(DVR;rttup+LERoYJDO4tr0=f zJOoV@th3Mol$4|h?oT7QZ$f~!AslKyz@cbF+?OF7su|%>=?I4sBe-wjf~J(d|6ax^ z=@W&pl;FZrcOlh_aHt}LLm|=rjz1O!d{5j0gJKnD=qF9C3$mLfnAabJdT zC;`HuR0xNPK{!+|g8SdP+P-`yPyDH4{3j&{heD(!7{n}U1~H4uoEzx*vVpm)@h?Lp zCQ1>0T7&S@al{z42f%*GCV)QURRg9GO2kfsXar3w5Hzhr&~y?((@X?S`2d5w`Q#}*d22fx`8BHTlfMhA zQ;tWeusZb?6@w3|VRh;jVuO|Wi()FQPC52_n`8~E)1~q<#8wWg)6iYreKHkRr`*%@ zE3Zx+gEGT$Y2P%zu9rrXqAIO?=LN$YjeyT1>Lwo}COlbyx`{*pC`9rQn~ar+@?ICB z8bKne5l0X-y^5e|HiD*z^X_yAni_+lDXHIX&egv7fyv#GT0%>itd zVi{F+vBR_OG9vitoP8ET3~ZpdS2sx!G+^Va24SlCm<+J9LeV+x80@+0G6KOWW;epr z7>KFa2vZv%re-2c6+=wTLzqe-OqH$YJOV~4qo}wjYm<&9_KTY~lvxsrhCZ6eHRisVZTe;lOq(H{*ZDFV-atP1U^DeRwt1 zGuoj1+bgb&MW@H~K1&*`852{xFSb1X_-pTV>@D7V*)XP^JkV0vC>|gEC(HYr z8yb^8&E|hRez36Q0F}REU71!~OqSL~jrUwG|6=^J%`@`J`%83FKh&omEfiVTov5RG zDx~zQe@KX2x9miFdHdwh@yo*(6?Yp4nq^7H?j6Z3j5}rSX&H-+7K+yomdxG$$EW|A LSNPq(yY2r0)0lSN8C{jh_2pAa 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 JQvo6y{vV@&QZ4`h literal 0 HcmV?d00001 diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 25c120e..9cf0300 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -1,12 +1,12 @@ name: UsefulSkyblock version: '1.0-SNAPSHOT' -main: com.ncguy.usefulSkyblock.UsefulSkyblock +main: com.ncguy.usefulskyblock.UsefulSkyblock description: A useful skyblock plugin api-version: '1.21' -bootstrapper: com.ncguy.usefulSkyblock.UsefulSkyblockBootstrap -loader: com.ncguy.usefulSkyblock.UsefulSkyblockLoader +bootstrapper: com.ncguy.usefulskyblock.UsefulSkyblockBootstrap +loader: com.ncguy.usefulskyblock.UsefulSkyblockLoader data-pack: load: true name: usefulskyblock - description: "UsefulSkyblock Structures" + description: "UsefulSkyblock" \ No newline at end of file diff --git a/src/test/java/com/ncguy/usefulskyblock/SimpleTests.java b/src/test/java/com/ncguy/usefulskyblock/SimpleTests.java new file mode 100644 index 0000000..4a531ea --- /dev/null +++ b/src/test/java/com/ncguy/usefulskyblock/SimpleTests.java @@ -0,0 +1,57 @@ +package com.ncguy.usefulskyblock; + +import com.ncguy.usefulskyblock.utils.MathsUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class SimpleTests { + + public static class Datum { + public int count; + public int ring; + public int slot; + + public Datum(int count, int ring, int slot) { + this.count = count; + this.ring = ring; + this.slot = slot; + } + } + + @Test + public void testCirclePlacement() { + Datum[] data = new Datum[] { + new Datum(0, 0, 0), + new Datum(1, 1, 0), + new Datum(2, 1, 1), + new Datum(3, 1, 2), + new Datum(4, 1, 3), + new Datum(5, 2, 0), + new Datum(6, 2, 1), + new Datum(7, 2, 2), + new Datum(8, 2, 3), + new Datum(9, 2, 4), + new Datum(10, 2, 5), + new Datum(11, 2, 6), + new Datum(12, 2, 7), + }; + + for(int i = 0; i < data.length; i++) { + Datum datum = data[i]; + int count = datum.count; + int ring = MathsUtils.getRing(count); + int slot = MathsUtils.getSlot(count); + + System.out.printf("Count: %d, Ring: %d, Slot: %d\n", count, ring, slot); + Assertions.assertEquals(datum.ring, ring); + Assertions.assertEquals(datum.slot, slot); + } + + } + + @Test + public void t() { + Assertions.assertEquals(1, Integer.highestOneBit(1)); + } + +}