parent
ab0b7495a3
commit
67d0ec7def
15 changed files with 1135 additions and 63 deletions
@ -0,0 +1,34 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.database.objects; |
||||||
|
|
||||||
|
|
||||||
|
import com.j256.ormlite.field.DatabaseField; |
||||||
|
import com.j256.ormlite.table.DatabaseTable; |
||||||
|
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
|
||||||
|
@DatabaseTable(tableName = "active_servers") |
||||||
|
public class ActiveServer { |
||||||
|
@DatabaseField(unique = true, id = true) |
||||||
|
private String name; |
||||||
|
|
||||||
|
public ActiveServer(){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public ActiveServer(String name){ |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
public void save() throws SQLException { |
||||||
|
DaoRegistry.getActiveServerDao().createIfNotExists(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void delete() throws SQLException { |
||||||
|
DaoRegistry.getActiveServerDao().delete(this); |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,96 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.database.objects; |
||||||
|
|
||||||
|
import com.j256.ormlite.field.DatabaseField; |
||||||
|
import com.j256.ormlite.table.DatabaseTable; |
||||||
|
import org.bukkit.Location; |
||||||
|
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
|
||||||
|
@DatabaseTable(tableName = "teleport_requests") |
||||||
|
public class TeleportRequest { |
||||||
|
|
||||||
|
@DatabaseField(unique = true, id = true) |
||||||
|
private String player; |
||||||
|
|
||||||
|
@DatabaseField(canBeNull = false) |
||||||
|
private String server; |
||||||
|
|
||||||
|
@DatabaseField(canBeNull = false) |
||||||
|
private String world; |
||||||
|
|
||||||
|
@DatabaseField |
||||||
|
private Integer x; |
||||||
|
|
||||||
|
@DatabaseField |
||||||
|
private Integer y; |
||||||
|
|
||||||
|
@DatabaseField |
||||||
|
private Integer z; |
||||||
|
|
||||||
|
@DatabaseField |
||||||
|
private Float yaw; |
||||||
|
|
||||||
|
@DatabaseField |
||||||
|
private Float pitch; |
||||||
|
|
||||||
|
public TeleportRequest() { |
||||||
|
} |
||||||
|
|
||||||
|
public TeleportRequest(String player, String server, String world) { |
||||||
|
this.player = player; |
||||||
|
this.server = server; |
||||||
|
this.world = world; |
||||||
|
} |
||||||
|
|
||||||
|
public TeleportRequest(String player, String server, String world, Integer x, Integer y, Integer z, Float yaw, Float pitch) { |
||||||
|
this.player = player; |
||||||
|
this.server = server; |
||||||
|
this.world = world; |
||||||
|
this.x = x; |
||||||
|
this.y = y; |
||||||
|
this.z = z; |
||||||
|
this.yaw = yaw; |
||||||
|
this.pitch = pitch; |
||||||
|
} |
||||||
|
|
||||||
|
public String getServer() { |
||||||
|
return server; |
||||||
|
} |
||||||
|
|
||||||
|
public String getWorld() { |
||||||
|
return world; |
||||||
|
} |
||||||
|
|
||||||
|
public String getPlayer() { |
||||||
|
return player; |
||||||
|
} |
||||||
|
|
||||||
|
public Integer getX() { |
||||||
|
return x; |
||||||
|
} |
||||||
|
|
||||||
|
public Integer getY() { |
||||||
|
return y; |
||||||
|
} |
||||||
|
|
||||||
|
public Integer getZ() { |
||||||
|
return z; |
||||||
|
} |
||||||
|
|
||||||
|
public Float getYaw() { |
||||||
|
return yaw; |
||||||
|
} |
||||||
|
|
||||||
|
public Float getPitch() { |
||||||
|
return pitch; |
||||||
|
} |
||||||
|
|
||||||
|
public void save() throws SQLException { |
||||||
|
DaoRegistry.getTeleportRequestsDao().createOrUpdate(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void delete() throws SQLException { |
||||||
|
DaoRegistry.getTeleportRequestsDao().delete(this); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,269 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.event.PacketListener; |
||||||
|
import com.github.retrooper.packetevents.event.PacketSendEvent; |
||||||
|
import com.github.retrooper.packetevents.protocol.packettype.PacketType; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.Column; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.LightData; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.TileEntity; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v_1_18.Chunk_v1_18; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.palette.DataPalette; |
||||||
|
import com.github.retrooper.packetevents.protocol.world.chunk.palette.PaletteType; |
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkData; |
||||||
|
import org.bukkit.Bukkit; |
||||||
|
import org.bukkit.NamespacedKey; |
||||||
|
import org.bukkit.World; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import org.bukkit.persistence.PersistentDataContainer; |
||||||
|
import org.bukkit.persistence.PersistentDataType; |
||||||
|
import org.bukkit.plugin.java.JavaPlugin; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.BitSet; |
||||||
|
import java.util.Arrays; |
||||||
|
|
||||||
|
public class FakeWater implements PacketListener { |
||||||
|
private static final int FALLBACK_WATER_STATE_ID_1_21_1 = 12015; |
||||||
|
|
||||||
|
private final JavaPlugin plugin; |
||||||
|
private final NamespacedKey keyX1, keyX2, keyZ1, keyZ2, keyType; |
||||||
|
|
||||||
|
// Resolved once (reflection), cached afterwards
|
||||||
|
private volatile Integer cachedWaterStateId; |
||||||
|
|
||||||
|
public FakeWater(JavaPlugin plugin) { |
||||||
|
this.plugin = plugin; |
||||||
|
this.keyX1 = new NamespacedKey(plugin, "borderx1"); |
||||||
|
this.keyX2 = new NamespacedKey(plugin, "borderx2"); |
||||||
|
this.keyZ1 = new NamespacedKey(plugin, "bordery1"); // Based on your spec
|
||||||
|
this.keyZ2 = new NamespacedKey(plugin, "borderx2"); // Based on your spec
|
||||||
|
this.keyType = new NamespacedKey(plugin, "island_type"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onPacketSend(PacketSendEvent event) { |
||||||
|
if (event.getPacketType() != PacketType.Play.Server.CHUNK_DATA) return; |
||||||
|
|
||||||
|
Player bukkitPlayer = Bukkit.getPlayer(event.getUser().getUUID()); |
||||||
|
if (bukkitPlayer == null) return; |
||||||
|
|
||||||
|
World world = bukkitPlayer.getWorld(); |
||||||
|
PersistentDataContainer pdc = world.getPersistentDataContainer(); |
||||||
|
|
||||||
|
String type = pdc.get(keyType, PersistentDataType.STRING); |
||||||
|
if (!"flat_grass".equals(type)) return; |
||||||
|
|
||||||
|
Integer x1 = pdc.get(keyX1, PersistentDataType.INTEGER); |
||||||
|
Integer x2 = pdc.get(keyX2, PersistentDataType.INTEGER); |
||||||
|
Integer z1 = pdc.get(keyZ1, PersistentDataType.INTEGER); |
||||||
|
Integer z2 = pdc.get(keyZ2, PersistentDataType.INTEGER); |
||||||
|
if (x1 == null || x2 == null || z1 == null || z2 == null) return; |
||||||
|
|
||||||
|
int minCX = Math.min(x1 >> 4, x2 >> 4) - 1; |
||||||
|
int maxCX = Math.max(x1 >> 4, x2 >> 4) + 1; |
||||||
|
int minCZ = Math.min(z1 >> 4, z2 >> 4) - 1; |
||||||
|
int maxCZ = Math.max(z1 >> 4, z2 >> 4) + 1; |
||||||
|
|
||||||
|
WrapperPlayServerChunkData wrapper = new WrapperPlayServerChunkData(event); |
||||||
|
|
||||||
|
Column original = wrapper.getColumn(); |
||||||
|
if (original == null) return; |
||||||
|
|
||||||
|
int chunkX = original.getX(); |
||||||
|
int chunkZ = original.getZ(); |
||||||
|
if (chunkX >= minCX && chunkX <= maxCX && chunkZ >= minCZ && chunkZ <= maxCZ) return; |
||||||
|
|
||||||
|
Column fake = createFakeWaterColumn(world, original, resolveWaterStateId()); |
||||||
|
if (fake == null) return; |
||||||
|
|
||||||
|
wrapper.setColumn(fake); |
||||||
|
|
||||||
|
// Force full-bright lighting for fake chunks to avoid "goes dark after radius"
|
||||||
|
wrapper.setLightData(buildFullBrightLightData(world)); |
||||||
|
} |
||||||
|
|
||||||
|
private static LightData buildFullBrightLightData(World world) { |
||||||
|
int sections = (world.getMaxHeight() - world.getMinHeight()) >> 4; |
||||||
|
if (sections <= 0) sections = 24; |
||||||
|
|
||||||
|
// 1.17+ light data uses sectionCount + 2 (one below min, one above max)
|
||||||
|
int lightCount = sections + 2; |
||||||
|
|
||||||
|
// Each light array entry is 16*16*16 nibbles = 4096 nibbles = 2048 bytes
|
||||||
|
byte[] fullSky = new byte[2048]; |
||||||
|
Arrays.fill(fullSky, (byte) 0xFF); // 0xF in every nibble => light level 15
|
||||||
|
|
||||||
|
byte[] noBlock = new byte[2048]; // default 0 => block light 0
|
||||||
|
|
||||||
|
// If your dimension can ever be no-skylight, handle it:
|
||||||
|
boolean hasSkyLight = world.getEnvironment() != World.Environment.NETHER |
||||||
|
&& world.getEnvironment() != World.Environment.THE_END; // adjust if you have custom dims
|
||||||
|
|
||||||
|
BitSet skyMask = new BitSet(lightCount); |
||||||
|
BitSet blockMask = new BitSet(lightCount); |
||||||
|
BitSet emptySkyMask = new BitSet(lightCount); |
||||||
|
BitSet emptyBlockMask = new BitSet(lightCount); |
||||||
|
|
||||||
|
byte[][] skyArray; |
||||||
|
int skyCount; |
||||||
|
if (hasSkyLight) { |
||||||
|
skyMask.set(0, lightCount); |
||||||
|
skyCount = lightCount; |
||||||
|
skyArray = new byte[skyCount][]; |
||||||
|
for (int i = 0; i < skyCount; i++) { |
||||||
|
skyArray[i] = fullSky; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// no skylight dimension
|
||||||
|
emptySkyMask.set(0, lightCount); |
||||||
|
skyCount = 0; |
||||||
|
skyArray = new byte[0][]; |
||||||
|
} |
||||||
|
|
||||||
|
blockMask.set(0, lightCount); |
||||||
|
int blockCount = lightCount; |
||||||
|
byte[][] blockArray = new byte[blockCount][]; |
||||||
|
for (int i = 0; i < blockCount; i++) { |
||||||
|
blockArray[i] = noBlock; |
||||||
|
} |
||||||
|
|
||||||
|
LightData ld = new LightData(); |
||||||
|
ld.setTrustEdges(true); |
||||||
|
ld.setSkyLightMask(skyMask); |
||||||
|
ld.setBlockLightMask(blockMask); |
||||||
|
ld.setEmptySkyLightMask(emptySkyMask); |
||||||
|
ld.setEmptyBlockLightMask(emptyBlockMask); |
||||||
|
ld.setSkyLightCount(skyCount); |
||||||
|
ld.setBlockLightCount(blockCount); |
||||||
|
ld.setSkyLightArray(skyArray); |
||||||
|
ld.setBlockLightArray(blockArray); |
||||||
|
return ld; |
||||||
|
} |
||||||
|
|
||||||
|
private Column createFakeWaterColumn(World world, Column original, int waterStateId) { |
||||||
|
int sections = (world.getMaxHeight() - world.getMinHeight()) >> 4; |
||||||
|
if (sections <= 0) sections = 24; |
||||||
|
|
||||||
|
BaseChunk[] originalChunks = original.getChunks(); |
||||||
|
|
||||||
|
// Find any existing biome palette from the original packet; we will reuse it.
|
||||||
|
DataPalette fallbackBiomePalette = null; |
||||||
|
if (originalChunks != null) { |
||||||
|
for (BaseChunk bc : originalChunks) { |
||||||
|
if (bc instanceof Chunk_v1_18 c) { |
||||||
|
fallbackBiomePalette = c.getBiomeData(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
BaseChunk[] chunks = new BaseChunk[sections]; |
||||||
|
|
||||||
|
for (int sectionIndex = 0; sectionIndex < sections; sectionIndex++) { |
||||||
|
DataPalette biomePalette = fallbackBiomePalette; |
||||||
|
|
||||||
|
if (originalChunks != null && sectionIndex < originalChunks.length && originalChunks[sectionIndex] instanceof Chunk_v1_18 c) { |
||||||
|
// Prefer the matching section's biome palette if present
|
||||||
|
biomePalette = c.getBiomeData(); |
||||||
|
} |
||||||
|
|
||||||
|
DataPalette blockPalette = PaletteType.CHUNK.create(); |
||||||
|
|
||||||
|
Chunk_v1_18 section = new Chunk_v1_18(0, blockPalette, biomePalette); |
||||||
|
section.set(0, 0, 0, 0); |
||||||
|
|
||||||
|
chunks[sectionIndex] = section; |
||||||
|
} |
||||||
|
|
||||||
|
// Section 0 == world Y -64..-49. Set only local y=0 and y=1 to water.
|
||||||
|
if (chunks[0] instanceof Chunk_v1_18 section0) { |
||||||
|
for (int localY = 0; localY <= 1; localY++) { |
||||||
|
for (int x = 0; x < 16; x++) { |
||||||
|
for (int z = 0; z < 16; z++) { |
||||||
|
section0.set(x, localY, z, waterStateId); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return new Column( |
||||||
|
original.getX(), |
||||||
|
original.getZ(), |
||||||
|
true, |
||||||
|
chunks, |
||||||
|
new TileEntity[0], |
||||||
|
original.getHeightMaps() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
private int resolveWaterStateId() { |
||||||
|
Integer cached = cachedWaterStateId; |
||||||
|
if (cached != null) return cached; |
||||||
|
|
||||||
|
int resolved = FALLBACK_WATER_STATE_ID_1_21_1; |
||||||
|
|
||||||
|
try { |
||||||
|
Object waterState = resolveNmsWaterBlockState(); |
||||||
|
if (waterState != null) { |
||||||
|
Integer id = tryGetBlockStateIdViaBlockGetId(waterState); |
||||||
|
if (id == null) { |
||||||
|
id = tryGetBlockStateIdViaBuiltInRegistry(waterState); |
||||||
|
} |
||||||
|
if (id != null && id > 0) { |
||||||
|
resolved = id; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (ReflectiveOperationException ignored) { |
||||||
|
// fallback
|
||||||
|
} |
||||||
|
|
||||||
|
cachedWaterStateId = resolved; |
||||||
|
plugin.getLogger().info("[FakeWater] Using water block-state id: " + resolved); |
||||||
|
return resolved; |
||||||
|
} |
||||||
|
|
||||||
|
private static Object resolveNmsWaterBlockState() throws ReflectiveOperationException { |
||||||
|
Class<?> blocksClass = Class.forName("net.minecraft.world.level.block.Blocks"); |
||||||
|
Field waterField = blocksClass.getField("WATER"); |
||||||
|
Object waterBlock = waterField.get(null); |
||||||
|
|
||||||
|
Method defaultBlockState = waterBlock.getClass().getMethod("defaultBlockState"); |
||||||
|
return defaultBlockState.invoke(waterBlock); |
||||||
|
} |
||||||
|
|
||||||
|
private static Integer tryGetBlockStateIdViaBlockGetId(Object blockState) throws ReflectiveOperationException { |
||||||
|
// Block.getId(BlockState) exists on many modern versions
|
||||||
|
Class<?> blockClass = Class.forName("net.minecraft.world.level.block.Block"); |
||||||
|
Class<?> blockStateClass = Class.forName("net.minecraft.world.level.block.state.BlockState"); |
||||||
|
|
||||||
|
try { |
||||||
|
Method getId = blockClass.getMethod("getId", blockStateClass); |
||||||
|
Object idObj = getId.invoke(null, blockState); |
||||||
|
return (idObj instanceof Integer i) ? i : null; |
||||||
|
} catch (NoSuchMethodException ignored) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static Integer tryGetBlockStateIdViaBuiltInRegistry(Object blockState) throws ReflectiveOperationException { |
||||||
|
Class<?> blockStateClass = Class.forName("net.minecraft.world.level.block.state.BlockState"); |
||||||
|
Class<?> builtInRegistriesClass = Class.forName("net.minecraft.core.registries.BuiltInRegistries"); |
||||||
|
|
||||||
|
Field blockStateRegistryField = builtInRegistriesClass.getField("BLOCK_STATE"); |
||||||
|
Object blockStateRegistry = blockStateRegistryField.get(null); |
||||||
|
|
||||||
|
Method getId = blockStateRegistry.getClass().getMethod("getId", Object.class); |
||||||
|
try { |
||||||
|
// Prefer exact signature if present: getId(BlockState)
|
||||||
|
Method exact = blockStateRegistry.getClass().getMethod("getId", blockStateClass); |
||||||
|
Object idObj = exact.invoke(blockStateRegistry, blockState); |
||||||
|
return (idObj instanceof Integer i) ? i : null; |
||||||
|
} catch (NoSuchMethodException ignored) { |
||||||
|
Object idObj = getId.invoke(blockStateRegistry, blockState); |
||||||
|
return (idObj instanceof Integer i) ? i : null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
|
import com.infernalsuite.asp.api.exceptions.UnknownWorldException; |
||||||
|
import com.infernalsuite.asp.api.loaders.SlimeLoader; |
||||||
|
import xyz.soukup.ecoCraftCore.EcoCraftCore; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
public class FileIslandLoader implements SlimeLoader { |
||||||
|
|
||||||
|
private final Path storagePath; |
||||||
|
private static final String EXTENSION = ".slime"; |
||||||
|
|
||||||
|
public FileIslandLoader() { |
||||||
|
// Creates a directory named 'islands' inside your plugin folder
|
||||||
|
this.storagePath = EcoCraftCore.plugin.getDataFolder().toPath().resolve("island_templates"); |
||||||
|
|
||||||
|
if (!Files.exists(storagePath)) { |
||||||
|
storagePath.toFile().mkdirs(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Path getWorldPath(String worldName) { |
||||||
|
return storagePath.resolve(worldName + EXTENSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public byte[] readWorld(String worldName) throws UnknownWorldException, IOException { |
||||||
|
Path path = getWorldPath(worldName); |
||||||
|
if (!Files.exists(path)) { |
||||||
|
throw new UnknownWorldException(worldName); |
||||||
|
} |
||||||
|
return Files.readAllBytes(path); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean worldExists(String worldName) throws IOException { |
||||||
|
return Files.exists(getWorldPath(worldName)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void saveWorld(String worldName, byte[] serializedWorld) throws IOException { |
||||||
|
// Files.write will create or overwrite the file automatically
|
||||||
|
Files.write(getWorldPath(worldName), serializedWorld); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void deleteWorld(String worldName) throws IOException { |
||||||
|
Files.deleteIfExists(getWorldPath(worldName)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> listWorlds() throws IOException { |
||||||
|
File folder = storagePath.toFile(); |
||||||
|
File[] files = folder.listFiles((dir, name) -> name.endsWith(EXTENSION)); |
||||||
|
|
||||||
|
if (files == null) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
return Arrays.stream(files) |
||||||
|
.map(file -> file.getName().replace(EXTENSION, "")) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} |
||||||
|
} |
||||||
@ -1,32 +1,228 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
|
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; |
||||||
|
import com.infernalsuite.asp.api.world.SlimeWorld; |
||||||
|
import com.j256.ormlite.stmt.QueryBuilder; |
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType; |
||||||
import com.mojang.brigadier.arguments.StringArgumentType; |
import com.mojang.brigadier.arguments.StringArgumentType; |
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
||||||
import com.mojang.brigadier.context.CommandContext; |
import com.mojang.brigadier.context.CommandContext; |
||||||
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 org.bukkit.NamespacedKey; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import org.bukkit.persistence.PersistentDataContainer; |
||||||
|
import org.bukkit.persistence.PersistentDataType; |
||||||
|
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
||||||
|
import xyz.soukup.ecoCraftCore.database.objects.Island; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
||||||
|
|
||||||
public class IslandCommand { |
public class IslandCommand { |
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> tp = Commands.literal("tp") |
public static LiteralArgumentBuilder<CommandSourceStack> createCommand() { |
||||||
.then(Commands.argument("uuid", StringArgumentType.word()) |
|
||||||
.executes(IslandCommand::teleport)); |
LiteralArgumentBuilder<CommandSourceStack> tp = Commands.literal("tp") |
||||||
|
.then(Commands.argument("uuid", StringArgumentType.word()) |
||||||
|
.executes(IslandCommand::teleport) |
||||||
|
.suggests(((context, builder) -> { |
||||||
|
try { |
||||||
|
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
||||||
|
queryBuilder.selectColumns("uuid"); |
||||||
|
List<Island> islands = queryBuilder.query(); |
||||||
|
for (Island island : islands) { |
||||||
|
builder.suggest(island.getUuid()); |
||||||
|
} |
||||||
|
return builder.buildFuture(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
}))); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> create = Commands.literal("create") |
||||||
|
.then(Commands.argument("type", StringArgumentType.word()) |
||||||
|
.then(Commands.argument("display_name", StringArgumentType.string()) |
||||||
|
.then(Commands.argument("description", StringArgumentType.greedyString()) |
||||||
|
.executes(IslandCommand::createWorld)))); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> load = Commands.literal("load") |
||||||
|
.then(Commands.argument("uuid", StringArgumentType.word()) |
||||||
|
.suggests(((context, builder) -> { |
||||||
|
try { |
||||||
|
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
||||||
|
queryBuilder.selectColumns("uuid"); |
||||||
|
List<Island> islands = queryBuilder.query(); |
||||||
|
for (Island island : islands) { |
||||||
|
builder.suggest(island.getUuid()); |
||||||
|
} |
||||||
|
return builder.buildFuture(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
})) |
||||||
|
.executes(IslandCommand::loadWorld)); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> loadTemplate = Commands.literal("loadTemplate") |
||||||
|
.then(Commands.argument("name", StringArgumentType.word()) |
||||||
|
.suggests(((context, builder) -> { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
FileIslandLoader fileLoader = islandManager.fileLoader; |
||||||
|
|
||||||
|
try { |
||||||
|
for (String world: fileLoader.listWorlds()){ |
||||||
|
builder.suggest(world); |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
return builder.buildFuture(); |
||||||
|
})) |
||||||
|
.executes(IslandCommand::loadTemplate)); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> template = Commands.literal("template") |
||||||
|
.then(Commands.argument("uuid", StringArgumentType.word()) |
||||||
|
.suggests((context, builder) -> { |
||||||
|
try { |
||||||
|
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
||||||
|
queryBuilder.selectColumns("uuid"); |
||||||
|
List<Island> islands = queryBuilder.query(); |
||||||
|
for (Island island : islands) { |
||||||
|
builder.suggest(island.getUuid()); |
||||||
|
} |
||||||
|
return builder.buildFuture(); |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
}) |
||||||
|
.then(Commands.argument("templateName", StringArgumentType.word()) |
||||||
|
.executes(IslandCommand::createTemplate))); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> metadata = Commands.literal("metadata") |
||||||
|
.then(Commands.argument("key", StringArgumentType.word()) |
||||||
|
.then(Commands.argument("value", IntegerArgumentType.integer()) |
||||||
|
.executes(IslandCommand::setMetadata))); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> metadataString = Commands.literal("metadataString") |
||||||
|
.then(Commands.argument("key", StringArgumentType.word()) |
||||||
|
.then(Commands.argument("value", StringArgumentType.string()) |
||||||
|
.executes(IslandCommand::setMetadataString))); |
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> create = Commands.literal("create") |
// NEW: Branch to read all metadata
|
||||||
.then(Commands.argument("name", StringArgumentType.word()) |
LiteralArgumentBuilder<CommandSourceStack> listMetadata = Commands.literal("listMetadata") |
||||||
.then(Commands.argument("display_name", StringArgumentType.string()))); |
.executes(IslandCommand::readAllMetadata); |
||||||
|
|
||||||
|
return Commands.literal("island") |
||||||
|
.then(tp) |
||||||
|
.then(create) |
||||||
|
.then(load) |
||||||
|
.then(template) |
||||||
|
.then(metadata) |
||||||
|
.then(metadataString) |
||||||
|
.then(listMetadata) |
||||||
|
.then(loadTemplate); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
private static int teleport(CommandContext<CommandSourceStack> context) { |
private static int teleport(CommandContext<CommandSourceStack> context) { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
try { |
||||||
|
islandManager.teleport((Player) context.getSource().getSender(), context.getArgument("uuid", String.class)); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
return 0; |
return 0; |
||||||
} |
} |
||||||
|
|
||||||
private static int createWorld(CommandContext<CommandSourceStack> context) { |
private static int createWorld(CommandContext<CommandSourceStack> context) { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
String type = context.getArgument("type", String.class); |
||||||
|
String displayName = context.getArgument("display_name", String.class); |
||||||
|
String description = context.getArgument("description", String.class); |
||||||
|
islandManager.createIsland(type, displayName, description, "n", "n"); |
||||||
return 0; |
return 0; |
||||||
} |
} |
||||||
|
|
||||||
private static int loadWorld(CommandContext<CommandSourceStack> context) { |
private static int loadWorld(CommandContext<CommandSourceStack> context) { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
islandManager.loadIsland(context.getArgument("uuid", String.class)); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private static int loadTemplate(CommandContext<CommandSourceStack> context) { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
islandManager.loadIslandTemplate(context.getArgument("name", String.class)); |
||||||
return 0; |
return 0; |
||||||
} |
} |
||||||
|
|
||||||
} |
private static int createTemplate(CommandContext<CommandSourceStack> context) { |
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
String uuid = StringArgumentType.getString(context, "uuid"); |
||||||
|
String templateName = StringArgumentType.getString(context, "templateName"); |
||||||
|
context.getSource().getSender().sendMessage("§aCreating template '" + templateName + "' from world '" + uuid + "'..."); |
||||||
|
islandManager.createIslandTemplate(uuid, templateName); |
||||||
|
context.getSource().getSender().sendMessage("§aTemplate created successfully!"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static int setMetadata(CommandContext<CommandSourceStack> context) { |
||||||
|
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
||||||
|
|
||||||
|
String keyName = StringArgumentType.getString(context, "key"); |
||||||
|
Integer value = IntegerArgumentType.getInteger(context, "value"); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
player.getWorld().getPersistentDataContainer().set(new NamespacedKey(plugin, keyName), PersistentDataType.INTEGER, value); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static int setMetadataString(CommandContext<CommandSourceStack> context) { |
||||||
|
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
||||||
|
|
||||||
|
String keyName = StringArgumentType.getString(context, "key"); |
||||||
|
String value = StringArgumentType.getString(context, "value"); |
||||||
|
|
||||||
|
player.getWorld().getPersistentDataContainer().set(new NamespacedKey(plugin, keyName), PersistentDataType.STRING, value); |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static int readAllMetadata(CommandContext<CommandSourceStack> context) { |
||||||
|
if (!(context.getSource().getSender() instanceof Player player)) { |
||||||
|
context.getSource().getSender().sendMessage("§cOnly players can use this."); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
PersistentDataContainer pdc = player.getWorld().getPersistentDataContainer(); |
||||||
|
if (pdc.getKeys().isEmpty()) { |
||||||
|
player.sendMessage("§eNo metadata found."); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
player.sendMessage("§6--- World Metadata ---"); |
||||||
|
for (NamespacedKey key : pdc.getKeys()) { |
||||||
|
String val = "unknown"; |
||||||
|
// Logic to determine type for display
|
||||||
|
if (pdc.has(key, PersistentDataType.STRING)) val = pdc.get(key, PersistentDataType.STRING); |
||||||
|
else if (pdc.has(key, PersistentDataType.INTEGER)) val = String.valueOf(pdc.get(key, PersistentDataType.INTEGER)); |
||||||
|
|
||||||
|
player.sendMessage("§b" + key.getKey() + "§7: §f" + val); |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static void saveSlimeWorld(SlimeWorld world, Player player, String key, String val) { |
||||||
|
try { |
||||||
|
AdvancedSlimePaperAPI.instance().saveWorld(world); |
||||||
|
player.sendMessage("§aMetadata set: §f" + key + " §7= §f" + val); |
||||||
|
} catch (IOException e) { |
||||||
|
player.sendMessage("§cFailed to save world metadata!"); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,4 +1,4 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
public class UnloadWorld { |
public class UnloadIsland { |
||||||
} |
} |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.islands.generators; |
||||||
|
|
||||||
|
import org.bukkit.Material; |
||||||
|
import org.bukkit.generator.ChunkGenerator; |
||||||
|
import org.bukkit.generator.WorldInfo; |
||||||
|
import org.jetbrains.annotations.NotNull; |
||||||
|
|
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
public class FlatGrass extends ChunkGenerator { |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, @NotNull ChunkData chunkData) { |
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) { |
||||||
|
for (int z = 0; z < 16; z++) { |
||||||
|
for (int y = worldInfo.getMinHeight(); y < 0; y++) { |
||||||
|
chunkData.setBlock(x, y, z, Material.WATER); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, @NotNull ChunkData chunkData) { |
||||||
|
for (int x = 0; x < 16; x++) { |
||||||
|
for (int z = 0; z < 16; z++) { |
||||||
|
|
||||||
|
int worldX = (chunkX * 16) + x; |
||||||
|
int worldZ = (chunkZ * 16) + z; |
||||||
|
|
||||||
|
if (worldX >= -50 && worldX < 50 && worldZ >= -50 && worldZ < 50) { |
||||||
|
chunkData.setBlock(x, 1, z, Material.STONE); |
||||||
|
} |
||||||
|
if (worldX >= -51 && worldX < 51 && worldZ >= -51 && worldZ < 51) { |
||||||
|
chunkData.setBlock(x, 0, z, Material.STONE); |
||||||
|
chunkData.setBlock(x, -1, z, Material.STONE); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.player; |
||||||
|
|
||||||
|
import com.j256.ormlite.stmt.QueryBuilder; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import org.bukkit.event.EventHandler; |
||||||
|
import org.bukkit.event.Listener; |
||||||
|
import org.bukkit.event.player.PlayerJoinEvent; |
||||||
|
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
||||||
|
import xyz.soukup.ecoCraftCore.database.objects.TeleportRequest; |
||||||
|
import xyz.soukup.ecoCraftCore.islands.IslandManager; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
|
||||||
|
public class TeleportRequestsHandler implements Listener { |
||||||
|
|
||||||
|
@EventHandler |
||||||
|
public void teleportRequestHandler(PlayerJoinEvent event){ |
||||||
|
try { |
||||||
|
Player player = event.getPlayer(); |
||||||
|
|
||||||
|
QueryBuilder<TeleportRequest, Integer> queryBuilder = DaoRegistry.getTeleportRequestsDao().queryBuilder(); |
||||||
|
queryBuilder.where().eq("player", player.getName()); |
||||||
|
|
||||||
|
TeleportRequest teleportRequest = queryBuilder.queryForFirst(); |
||||||
|
|
||||||
|
if (teleportRequest == null){ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
IslandManager islandManager = new IslandManager(); |
||||||
|
|
||||||
|
islandManager.teleportLocally(player, teleportRequest.getWorld(), teleportRequest.getX(), teleportRequest.getY(), teleportRequest.getY(), teleportRequest.getYaw(), teleportRequest.getPitch()); |
||||||
|
|
||||||
|
teleportRequest.delete(); |
||||||
|
|
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue