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.
This commit is contained in:
parent
3e21e35757
commit
e6f5230c58
25 changed files with 559 additions and 208 deletions
|
@ -18,13 +18,19 @@ repositories {
|
||||||
name = "sonatype"
|
name = "sonatype"
|
||||||
url = "https://oss.sonatype.org/content/groups/public/"
|
url = "https://oss.sonatype.org/content/groups/public/"
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
name = "multiverseMultiverseReleases"
|
||||||
|
url = uri("https://repo.onarandombox.com/multiverse-releases")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT")
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
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 {
|
tasks {
|
||||||
|
@ -52,6 +58,7 @@ tasks.withType(JavaCompile).configureEach {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
def props = [version: version]
|
def props = [version: version]
|
||||||
inputs.properties props
|
inputs.properties props
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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() + "!"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 extends Enum<?>> T randomEnum(Class<T> enumCls) {
|
|
||||||
assert(enumCls.isEnum());
|
|
||||||
return randomElement(enumCls.getEnumConstants());
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> 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<Float> 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<CommandSourceStack> 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<CommandSourceStack> create() {
|
|
||||||
var root = Commands.literal("skyblock");
|
|
||||||
|
|
||||||
var cmd = Get(SkyblockGenCommand.class);
|
|
||||||
root.then(Commands.literal("generate").executes(cmd::executeGenerate));
|
|
||||||
|
|
||||||
return root.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ncguy.usefulSkyblock;
|
package com.ncguy.usefulskyblock;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
104
src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java
Normal file
104
src/main/java/com/ncguy/usefulskyblock/UsefulSkyblock.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package com.ncguy.usefulSkyblock;
|
package com.ncguy.usefulskyblock;
|
||||||
|
|
||||||
import com.ncguy.usefulSkyblock.command.SkyblockAdminCommand;
|
import com.ncguy.usefulskyblock.command.SkyblockAdminCommand;
|
||||||
import com.ncguy.usefulSkyblock.command.SkyblockGenCommand;
|
import com.ncguy.usefulskyblock.command.SkyblockGenCommand;
|
||||||
import com.ncguy.usefulSkyblock.hexagon.HexagonRenderer;
|
import com.ncguy.usefulskyblock.hexagon.HexagonRenderer;
|
||||||
import io.papermc.paper.datapack.DatapackRegistrar;
|
import io.papermc.paper.datapack.DatapackRegistrar;
|
||||||
import io.papermc.paper.datapack.DiscoveredDatapack;
|
import io.papermc.paper.datapack.DiscoveredDatapack;
|
||||||
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
|
@ -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.PluginClasspathBuilder;
|
||||||
import io.papermc.paper.plugin.loader.PluginLoader;
|
import io.papermc.paper.plugin.loader.PluginLoader;
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ncguy.usefulSkyblock.command;
|
package com.ncguy.usefulskyblock.command;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ncguy.usefulSkyblock.command;
|
package com.ncguy.usefulskyblock.command;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
|
@ -1,42 +1,33 @@
|
||||||
package com.ncguy.usefulSkyblock.command;
|
package com.ncguy.usefulskyblock.command;
|
||||||
|
|
||||||
import com.mojang.brigadier.StringReader;
|
import com.mojang.brigadier.StringReader;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
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.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.CommandSourceStack;
|
||||||
import io.papermc.paper.command.brigadier.Commands;
|
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.command.brigadier.argument.CustomArgumentType;
|
||||||
import io.papermc.paper.math.BlockPosition;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.structure.Mirror;
|
import org.bukkit.block.structure.Mirror;
|
||||||
import org.bukkit.block.structure.StructureRotation;
|
import org.bukkit.block.structure.StructureRotation;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.structure.Structure;
|
import org.bukkit.structure.Structure;
|
||||||
import org.bukkit.structure.StructureManager;
|
import org.bukkit.structure.StructureManager;
|
||||||
import org.bukkit.util.BlockVector;
|
|
||||||
import org.bukkit.util.RayTraceResult;
|
import org.bukkit.util.RayTraceResult;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.codehaus.plexus.util.cli.Arg;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.xml.stream.events.Namespace;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -45,6 +36,8 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SkyblockAdminCommand.class);
|
private static final Logger log = LoggerFactory.getLogger(SkyblockAdminCommand.class);
|
||||||
|
|
||||||
|
private BoxVisualizer box = new BoxVisualizer();
|
||||||
|
|
||||||
public int executeStructuresList(CommandContext<CommandSourceStack> ctx) {
|
public int executeStructuresList(CommandContext<CommandSourceStack> ctx) {
|
||||||
|
|
||||||
StructureManager structureManager = getServer().getStructureManager();
|
StructureManager structureManager = getServer().getStructureManager();
|
||||||
|
@ -131,7 +124,19 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand {
|
||||||
RayTraceResult rayTraceResult = p.rayTraceBlocks(8);
|
RayTraceResult rayTraceResult = p.rayTraceBlocks(8);
|
||||||
|
|
||||||
Vector hitPosition = rayTraceResult.getHitPosition();
|
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;
|
return 0;
|
||||||
|
@ -146,7 +151,20 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand {
|
||||||
RayTraceResult rayTraceResult = p.rayTraceBlocks(8);
|
RayTraceResult rayTraceResult = p.rayTraceBlocks(8);
|
||||||
|
|
||||||
Vector hitPosition = rayTraceResult.getHitPosition();
|
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;
|
return 0;
|
||||||
|
@ -160,8 +178,9 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand {
|
||||||
if (!(executor instanceof Player)) return 0;
|
if (!(executor instanceof Player)) return 0;
|
||||||
Player p = (Player) executor;
|
Player p = (Player) executor;
|
||||||
|
|
||||||
int[] p0 = p.getPersistentDataContainer().get(key("_p0"), PersistentDataType.INTEGER_ARRAY);
|
PersistentDataContainer pdc = p.getPersistentDataContainer();
|
||||||
int[] p1 = p.getPersistentDataContainer().get(key("_p1"), PersistentDataType.INTEGER_ARRAY);
|
int[] p0 = pdc.get(key("_p0"), PersistentDataType.INTEGER_ARRAY);
|
||||||
|
int[] p1 = pdc.get(key("_p1"), PersistentDataType.INTEGER_ARRAY);
|
||||||
|
|
||||||
if (p0 == null) {
|
if (p0 == null) {
|
||||||
executor.sendMessage("No P0 found");
|
executor.sendMessage("No P0 found");
|
||||||
|
@ -190,6 +209,9 @@ public class SkyblockAdminCommand extends AbstractSkyblockCommand {
|
||||||
f.getParentFile().mkdirs();
|
f.getParentFile().mkdirs();
|
||||||
getServer().getStructureManager().saveStructure(f, structure);
|
getServer().getStructureManager().saveStructure(f, structure);
|
||||||
log.info("Saved structure {} to {}", name, f.getAbsolutePath());
|
log.info("Saved structure {} to {}", name, f.getAbsolutePath());
|
||||||
|
pdc.remove(key("_p0"));
|
||||||
|
pdc.remove(key("_p1"));
|
||||||
|
box.cleanup();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
|
@ -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 extends Enum<?>> T randomEnum(Class<T> enumCls) {
|
||||||
|
assert(enumCls.isEnum());
|
||||||
|
return randomElement(enumCls.getEnumConstants());
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> 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<Float> 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<Float> 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<CommandSourceStack> 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<CommandSourceStack> create() {
|
||||||
|
var root = Commands.literal("skyblock");
|
||||||
|
|
||||||
|
var cmd = Get(SkyblockGenCommand.class);
|
||||||
|
root.then(Commands.literal("generate").executes(cmd::executeGenerate));
|
||||||
|
|
||||||
|
return root.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ncguy.usefulSkyblock.hexagon;
|
package com.ncguy.usefulskyblock.hexagon;
|
||||||
|
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
|
@ -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.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
@ -32,12 +33,12 @@ public class BoxVisualizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get min and max coordinates
|
// Get min and max coordinates
|
||||||
double minX = Math.min(corner1.getX(), corner2.getX());
|
double minX = Math.min(corner1.getBlockX(), corner2.getBlockX());
|
||||||
double minY = Math.min(corner1.getY(), corner2.getY());
|
double minY = Math.min(corner1.getBlockY(), corner2.getBlockY());
|
||||||
double minZ = Math.min(corner1.getZ(), corner2.getZ());
|
double minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
|
||||||
double maxX = Math.max(corner1.getX(), corner2.getX());
|
double maxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
|
||||||
double maxY = Math.max(corner1.getY(), corner2.getY());
|
double maxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
|
||||||
double maxZ = Math.max(corner1.getZ(), corner2.getZ());
|
double maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());
|
||||||
|
|
||||||
// Create the 12 edges of the box
|
// Create the 12 edges of the box
|
||||||
// Bottom rectangle
|
// Bottom rectangle
|
||||||
|
@ -58,6 +59,31 @@ public class BoxVisualizer {
|
||||||
createEdge(world, minX, minY, maxZ, minX, maxY, maxZ); // Back left
|
createEdge(world, minX, minY, maxZ, minX, maxY, maxZ); // Back left
|
||||||
createEdge(world, maxX, minY, maxZ, maxX, maxY, maxZ); // Back right
|
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);
|
return new ArrayList<>(displays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,19 +112,17 @@ public class BoxVisualizer {
|
||||||
double dy = y2 - y1;
|
double dy = y2 - y1;
|
||||||
double dz = z2 - z1;
|
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
|
// Create transformation
|
||||||
Transformation transformation = new Transformation(
|
Transformation transformation = new Transformation(
|
||||||
new Vector3f(0, 0, 0), // Translation (already at center)
|
new Vector3f(0, 0, 0),
|
||||||
new AxisAngle4f((float)pitch, 0, 1, 0), // Pitch rotation
|
new AxisAngle4f(0, 0, 0, 1),
|
||||||
new Vector3f((float)length, LINE_THICKNESS, LINE_THICKNESS), // Scale
|
new Vector3f(LINE_THICKNESS, LINE_THICKNESS, (float) length),
|
||||||
new AxisAngle4f(0, 0, 0, 1) // No additional rotation
|
new AxisAngle4f(0, 0, 0, 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
entity.setTransformation(transformation);
|
entity.setTransformation(transformation);
|
||||||
|
entity.lookAt(centerX + dx, centerY + dy, centerZ + dz, LookAnchor.FEET);
|
||||||
entity.setBrightness(new Display.Brightness(15, 15)); // Full brightness
|
entity.setBrightness(new Display.Brightness(15, 15)); // Full brightness
|
||||||
entity.setViewRange(64f); // Visible up to 64 blocks away
|
entity.setViewRange(64f); // Visible up to 64 blocks away
|
||||||
entity.setPersistent(false); // Will be removed when chunk unloads
|
entity.setPersistent(false); // Will be removed when chunk unloads
|
|
@ -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.Random;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class MathsUtils {
|
public class MathsUtils {
|
||||||
|
@ -45,5 +42,32 @@ public class MathsUtils {
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:overworld",
|
||||||
|
"generator": {
|
||||||
|
"type": "flat",
|
||||||
|
"settings":{
|
||||||
|
"layers": [],
|
||||||
|
"biome": "minecraft:void",
|
||||||
|
"structure_overrides": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:the_nether",
|
||||||
|
"generator": {
|
||||||
|
"type": "flat",
|
||||||
|
"settings":{
|
||||||
|
"layers": [],
|
||||||
|
"biome": "minecraft:void",
|
||||||
|
"structure_overrides": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,15 @@
|
||||||
{
|
{
|
||||||
"type": "minecraft:overworld",
|
"type": "usefulskyblock:skyblock",
|
||||||
"generator": {
|
"generator": {
|
||||||
"type": "flat",
|
"type": "flat",
|
||||||
"settings":{
|
"settings":{
|
||||||
"layers": [],
|
"layers": [
|
||||||
"biome": "minecraft:void",
|
{
|
||||||
|
"block": "minecraft:grass",
|
||||||
|
"height": 64
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"biome": "minecraft:plains",
|
||||||
"structure_overrides": []
|
"structure_overrides": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,12 +1,12 @@
|
||||||
name: UsefulSkyblock
|
name: UsefulSkyblock
|
||||||
version: '1.0-SNAPSHOT'
|
version: '1.0-SNAPSHOT'
|
||||||
main: com.ncguy.usefulSkyblock.UsefulSkyblock
|
main: com.ncguy.usefulskyblock.UsefulSkyblock
|
||||||
description: A useful skyblock plugin
|
description: A useful skyblock plugin
|
||||||
api-version: '1.21'
|
api-version: '1.21'
|
||||||
bootstrapper: com.ncguy.usefulSkyblock.UsefulSkyblockBootstrap
|
bootstrapper: com.ncguy.usefulskyblock.UsefulSkyblockBootstrap
|
||||||
loader: com.ncguy.usefulSkyblock.UsefulSkyblockLoader
|
loader: com.ncguy.usefulskyblock.UsefulSkyblockLoader
|
||||||
|
|
||||||
data-pack:
|
data-pack:
|
||||||
load: true
|
load: true
|
||||||
name: usefulskyblock
|
name: usefulskyblock
|
||||||
description: "UsefulSkyblock Structures"
|
description: "UsefulSkyblock"
|
57
src/test/java/com/ncguy/usefulskyblock/SimpleTests.java
Normal file
57
src/test/java/com/ncguy/usefulskyblock/SimpleTests.java
Normal file
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue