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 54d5384..1730d8a 100644 Binary files a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic-sand.nbt and b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic-sand.nbt differ 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 6812fba..5dcf63b 100644 Binary files a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic.nbt and b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/classic.nbt differ diff --git a/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/spawn.nbt b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/spawn.nbt new file mode 100644 index 0000000..88d82c2 Binary files /dev/null and b/src/main/resources/datapacks/usefulskyblock/data/usefulskyblock/structures/spawn.nbt differ 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)); + } + +}