(Skoro) hotový island systém

island-experimenty
jakub 3 weeks ago
parent ab0b7495a3
commit 67d0ec7def
  1. 14
      pom.xml
  2. 142
      src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java
  3. 17
      src/main/java/xyz/soukup/ecoCraftCore/database/DaoRegistry.java
  4. 34
      src/main/java/xyz/soukup/ecoCraftCore/database/objects/ActiveServer.java
  5. 15
      src/main/java/xyz/soukup/ecoCraftCore/database/objects/Island.java
  6. 96
      src/main/java/xyz/soukup/ecoCraftCore/database/objects/TeleportRequest.java
  7. 2
      src/main/java/xyz/soukup/ecoCraftCore/islands/DatabaseIslandLoader.java
  8. 269
      src/main/java/xyz/soukup/ecoCraftCore/islands/FakeWater.java
  9. 72
      src/main/java/xyz/soukup/ecoCraftCore/islands/FileIslandLoader.java
  10. 208
      src/main/java/xyz/soukup/ecoCraftCore/islands/IslandCommand.java
  11. 238
      src/main/java/xyz/soukup/ecoCraftCore/islands/IslandManager.java
  12. 2
      src/main/java/xyz/soukup/ecoCraftCore/islands/UnloadIsland.java
  13. 44
      src/main/java/xyz/soukup/ecoCraftCore/islands/generators/FlatGrass.java
  14. 40
      src/main/java/xyz/soukup/ecoCraftCore/player/TeleportRequestsHandler.java
  15. 3
      src/main/resources/plugin.yml

@ -87,6 +87,10 @@
</build> </build>
<repositories> <repositories>
<repository>
<id>codemc-releases</id>
<url>https://repo.codemc.io/repository/maven-releases/</url>
</repository>
<repository> <repository>
<id>is-releases</id> <id>is-releases</id>
<url>https://repo.infernalsuite.com/repository/maven-releases/</url> <url>https://repo.infernalsuite.com/repository/maven-releases/</url>
@ -103,6 +107,10 @@
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io</url> <url>https://jitpack.io</url>
</repository> </repository>
<!-- PacketEvents is commonly consumed via CodeMC. If this repo isn't in your environment,
tell me and I’ll give you the exact repo you prefer (jitpack/shade/plugin). -->
</repositories> </repositories>
<dependencies> <dependencies>
@ -143,5 +151,11 @@
<artifactId>MatrixColorAPI</artifactId> <artifactId>MatrixColorAPI</artifactId>
<version>v1.0.7</version> <version>v1.0.7</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.retrooper</groupId>
<artifactId>packetevents-spigot</artifactId>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -1,21 +1,31 @@
package xyz.soukup.ecoCraftCore; package xyz.soukup.ecoCraftCore;
import com.github.retrooper.packetevents.event.EventManager;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI;
import com.infernalsuite.asp.api.world.SlimeWorldInstance;
import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import xyz.soukup.ecoCraftCore.database.objects.*;
import xyz.soukup.ecoCraftCore.islands.IslandCommand;
import xyz.soukup.ecoCraftCore.money.MoneyCommand; import xyz.soukup.ecoCraftCore.money.MoneyCommand;
import xyz.soukup.ecoCraftCore.player.PreparePlayer; import xyz.soukup.ecoCraftCore.player.PreparePlayer;
import xyz.soukup.ecoCraftCore.player.TeleportRequestsHandler;
import xyz.soukup.ecoCraftCore.positionMarker.RulerCommand; import xyz.soukup.ecoCraftCore.positionMarker.RulerCommand;
import xyz.soukup.ecoCraftCore.shop.ShopCommand; import xyz.soukup.ecoCraftCore.shop.ShopCommand;
import xyz.soukup.ecoCraftCore.database.objects.Account;
import xyz.soukup.ecoCraftCore.database.objects.Shop;
import xyz.soukup.ecoCraftCore.database.objects.Transaction;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import xyz.soukup.ecoCraftCore.inventory.VirtualChest; import xyz.soukup.ecoCraftCore.inventory.VirtualChest;
import xyz.soukup.ecoCraftCore.positionMarker.RulerMarking; import xyz.soukup.ecoCraftCore.positionMarker.RulerMarking;
@ -29,23 +39,38 @@ import java.sql.SQLException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.github.retrooper.packetevents.PacketEvents;
import xyz.soukup.ecoCraftCore.islands.FakeWater;
public final class EcoCraftCore extends JavaPlugin { public final class EcoCraftCore extends JavaPlugin {
public static EcoCraftCore plugin; public static EcoCraftCore plugin;
public static ConnectionSource connectionSource; public static ConnectionSource connectionSource;
public static FileConfiguration config;
@Override @Override
public void onEnable() { public void onEnable() {
this.getLogger().info("plugin starting out"); this.getLogger().info("plugin starting out");
plugin = this; plugin = this;
config = getConfig();
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
PacketEvents.getAPI().load();
PacketEvents.getAPI().init();
try { try {
saveDefaultConfig();
Messages.init(); Messages.init();
prepareDatabase(); prepareDatabase();
registerCommands(); registerCommands();
registerEvents(); registerEvents();
prepareSlimeWorldsSaver();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
getLogger().severe("Failed to initialize database."); getLogger().severe("Failed to initialize database.");
@ -63,13 +88,81 @@ public final class EcoCraftCore extends JavaPlugin {
public void onDisable() { public void onDisable() {
VirtualChest.saveCache(); VirtualChest.saveCache();
saveSlimeWorlds();
adiosDatabase();
try { PacketEvents.getAPI().terminate();
if (connectionSource != null) {
connectionSource.close(); }
private void prepareSlimeWorldsSaver(){
Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, () -> {
AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance();
for (SlimeWorldInstance slimeWorldInstance : asp.getLoadedWorlds()){
try {
asp.saveWorld(slimeWorldInstance);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} catch (Exception e) { }, 12000L, 12000L);
e.printStackTrace(); }
private void prepareWorldInactivityUnloader(){
Bukkit.getScheduler().runTaskTimer(plugin, () -> {
long timeoutMillis = 30 * 60 * 1000;
long now = System.currentTimeMillis();
AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance();
for (SlimeWorldInstance slimeWorldInstance : asp.getLoadedWorlds()) {
World world = slimeWorldInstance.getBukkitWorld();
if (!world.getPlayers().isEmpty()){
world.removeMetadata("last_empty_time", plugin);
continue;
}
if (!world.hasMetadata("last_empty_time")) {
world.setMetadata("last_empty_time", new FixedMetadataValue(plugin, now));
continue;
}
long emptySince = world.getMetadata("last_empty_time").get(0).asLong();
if ((now - emptySince) >= timeoutMillis) {
Bukkit.unloadWorld(world, true);
}
}
}, 1200L, 1200L);
}
private void saveSlimeWorlds(){
AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance();
for (SlimeWorldInstance slimeWorldInstance : asp.getLoadedWorlds()){
try {
asp.saveWorld(slimeWorldInstance);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try {
UpdateBuilder<Island, Integer> updateBuilder = DaoRegistry.getIslandDao().updateBuilder();
updateBuilder.where().eq("active_on", config.getString("server.name"));
updateBuilder.updateColumnValue("active_on", "");
updateBuilder.update();
} catch (SQLException e) {
throw new RuntimeException(e);
} }
} }
@ -78,17 +171,40 @@ public final class EcoCraftCore extends JavaPlugin {
connectionSource = new JdbcConnectionSource(databaseUrl, "ecc", "ecc"); connectionSource = new JdbcConnectionSource(databaseUrl, "ecc", "ecc");
Logger.getLogger("com.j256.ormlite.table.TableUtils").setLevel(Level.OFF); Logger.getLogger("com.j256.ormlite.table.TableUtils").setLevel(Level.OFF);
TableUtils.createTableIfNotExists(connectionSource, ActiveServer.class);
TableUtils.createTableIfNotExists(connectionSource, Transaction.class); TableUtils.createTableIfNotExists(connectionSource, Transaction.class);
TableUtils.createTableIfNotExists(connectionSource, Shop.class); TableUtils.createTableIfNotExists(connectionSource, Shop.class);
TableUtils.createTableIfNotExists(connectionSource, VirtualChest.class); TableUtils.createTableIfNotExists(connectionSource, VirtualChest.class);
TableUtils.createTableIfNotExists(connectionSource, Account.class); TableUtils.createTableIfNotExists(connectionSource, Account.class);
TableUtils.createTableIfNotExists(connectionSource, Island.class);
TableUtils.createTableIfNotExists(connectionSource, TeleportRequest.class);
DaoRegistry.setActiveServerDao(DaoManager.createDao(connectionSource, ActiveServer.class));
DaoRegistry.setTransactionDao(DaoManager.createDao(connectionSource, Transaction.class)); DaoRegistry.setTransactionDao(DaoManager.createDao(connectionSource, Transaction.class));
DaoRegistry.setIslandDaoo(DaoManager.createDao(connectionSource, Island.class));
DaoRegistry.setShopDao(DaoManager.createDao(connectionSource, Shop.class)); DaoRegistry.setShopDao(DaoManager.createDao(connectionSource, Shop.class));
DaoRegistry.setVirtualChestDao(DaoManager.createDao(connectionSource, VirtualChest.class)); DaoRegistry.setVirtualChestDao(DaoManager.createDao(connectionSource, VirtualChest.class));
DaoRegistry.setAccountDao(DaoManager.createDao(connectionSource, Account.class)); DaoRegistry.setAccountDao(DaoManager.createDao(connectionSource, Account.class));
DaoRegistry.setTeleportRequestsDao(DaoManager.createDao(connectionSource, TeleportRequest.class));
ActiveServer activeServer = new ActiveServer(config.getString("server.name"));
activeServer.save();
}
private void adiosDatabase(){
try {
ActiveServer activeServer = new ActiveServer(config.getString("server.name"));
activeServer.delete();
if (connectionSource != null) {
connectionSource.close();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
private void registerCommands() { private void registerCommands() {
@ -97,19 +213,21 @@ public final class EcoCraftCore extends JavaPlugin {
lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(ShopCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(ShopCommand.createCommand().build()));
lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(RulerCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(RulerCommand.createCommand().build()));
lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MoneyCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MoneyCommand.createCommand().build()));
lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(IslandCommand.createCommand().build()));
} }
private void registerEvents(){ private void registerEvents(){
PluginManager pm = this.getServer().getPluginManager(); PluginManager pm = this.getServer().getPluginManager();
pm.registerEvents(new TeleportRequestsHandler(), this);
pm.registerEvents(new RulerMarking(), this); pm.registerEvents(new RulerMarking(), this);
pm.registerEvents(new VirtualChestLogic(), this); pm.registerEvents(new VirtualChestLogic(), this);
pm.registerEvents(new ShopLogic(), this); pm.registerEvents(new ShopLogic(), this);
pm.registerEvents(new PreparePlayer(), this); pm.registerEvents(new PreparePlayer(), this);
}
EventManager events = PacketEvents.getAPI().getEventManager();
events.registerListener(new FakeWater(this), PacketListenerPriority.NORMAL);
}
} }

@ -10,7 +10,24 @@ public class DaoRegistry {
private static Dao<VirtualChest, Integer> virtualChestDao; private static Dao<VirtualChest, Integer> virtualChestDao;
private static Dao<Account, Integer> accountDao; private static Dao<Account, Integer> accountDao;
private static Dao<Island, Integer> islandDao; private static Dao<Island, Integer> islandDao;
private static Dao<TeleportRequest, Integer> teleportRequestsDao;
private static Dao<ActiveServer, Integer> activeServerDao;
public static Dao<TeleportRequest, Integer> getTeleportRequestsDao() {
return teleportRequestsDao;
}
public static void setTeleportRequestsDao(Dao<TeleportRequest, Integer> teleportRequestsDao) {
DaoRegistry.teleportRequestsDao = teleportRequestsDao;
}
public static Dao<ActiveServer, Integer> getActiveServerDao() {
return activeServerDao;
}
public static void setActiveServerDao(Dao<ActiveServer, Integer> activeServerDao) {
DaoRegistry.activeServerDao = activeServerDao;
}
public static Dao<Shop, Integer> getShopDao() { public static Dao<Shop, Integer> getShopDao() {
return shopDao; return shopDao;

@ -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;
}
}

@ -15,9 +15,8 @@ public class Island {
@DatabaseField(canBeNull = false, unique = true) @DatabaseField(canBeNull = false, unique = true)
private String uuid; private String uuid;
@DatabaseField(canBeNull = false, unique = true) @DatabaseField(canBeNull = false)
private String name; private String type;
@DatabaseField(columnName = "display_name") @DatabaseField(columnName = "display_name")
private String displayName; private String displayName;
@ -37,12 +36,14 @@ public class Island {
@DatabaseField(defaultValue = "", columnName = "active_on") @DatabaseField(defaultValue = "", columnName = "active_on")
private String activeOn; private String activeOn;
public Island(){ public Island(){
} }
public Island(String name, String uuid, String displayName, String descritpion, String owner, String ownerType, byte[] data) { public Island(String type, String uuid, String displayName, String descritpion, String owner, String ownerType, byte[] data) {
this.name = name; this.type = type;
this.uuid = uuid; this.uuid = uuid;
this.displayName = displayName; this.displayName = displayName;
this.descritpion = descritpion; this.descritpion = descritpion;
@ -60,8 +61,8 @@ public class Island {
return id; return id;
} }
public String getName() { public String getType() {
return name; return type;
} }
public String getDisplayName() { public String getDisplayName() {

@ -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);
}
}

@ -10,7 +10,7 @@ import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class IslandLoader implements SlimeLoader { public class DatabaseIslandLoader implements SlimeLoader {
@Override @Override

@ -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; return 0;
} }
private static int loadTemplate(CommandContext<CommandSourceStack> context) {
IslandManager islandManager = new IslandManager();
islandManager.loadIslandTemplate(context.getArgument("name", String.class));
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,85 +1,253 @@
package xyz.soukup.ecoCraftCore.islands; package xyz.soukup.ecoCraftCore.islands;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; import com.infernalsuite.asp.api.AdvancedSlimePaperAPI;
import com.infernalsuite.asp.api.exceptions.CorruptedWorldException;
import com.infernalsuite.asp.api.exceptions.NewerFormatException;
import com.infernalsuite.asp.api.exceptions.UnknownWorldException;
import com.infernalsuite.asp.api.exceptions.WorldAlreadyExistsException;
import com.infernalsuite.asp.api.world.SlimeWorld; import com.infernalsuite.asp.api.world.SlimeWorld;
import com.infernalsuite.asp.api.world.properties.SlimeProperties; import com.infernalsuite.asp.api.world.properties.SlimeProperties;
import com.infernalsuite.asp.api.world.properties.SlimePropertyMap; import com.infernalsuite.asp.api.world.properties.SlimePropertyMap;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.UpdateBuilder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import xyz.soukup.ecoCraftCore.database.objects.Island; import xyz.soukup.ecoCraftCore.database.objects.Island;
import xyz.soukup.ecoCraftCore.database.DaoRegistry; import xyz.soukup.ecoCraftCore.database.DaoRegistry;
import xyz.soukup.ecoCraftCore.database.objects.TeleportRequest;
import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import static xyz.soukup.ecoCraftCore.EcoCraftCore.config;
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin;
public class IslandManager { public class IslandManager {
private final AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); private final AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance();
private final IslandLoader loader = new IslandLoader(); private final DatabaseIslandLoader databaseLoader = new DatabaseIslandLoader();
public final FileIslandLoader fileLoader = new FileIslandLoader();
private final Dao<Island, Integer> dao = DaoRegistry.getIslandDao();
public void createIslandTemplate(String uuid, String templateName){
try {
SlimeWorld slimeWorld = asp.getLoadedWorld(uuid).clone(templateName, fileLoader);
asp.saveWorld(slimeWorld);
} catch (WorldAlreadyExistsException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void createIsland(String name, String displayName, String descritpion, String owner, String ownerType) { public String createIsland(String type, String displayName, String descritpion, String owner, String ownerType) {
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
SlimePropertyMap props = new SlimePropertyMap();
props.setValue(SlimeProperties.ENVIRONMENT, "overworld");
props.setValue(SlimeProperties.WORLD_TYPE, "flat");
// Create empty world in ASWM
try { try {
// Note: createEmptyWorld is fast, so we can run some parts sync if needed,
// but it's best to run the whole chain async.
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
// Create the database entry first so the loader has a row to update SlimePropertyMap props = new SlimePropertyMap();
props.setValue(SlimeProperties.ENVIRONMENT, "normal");
props.setValue(SlimeProperties.WORLD_TYPE, "flat");
props.setValue(SlimeProperties.ALLOW_ANIMALS, false);
props.setValue(SlimeProperties.ALLOW_MONSTERS, false);
props.setValue(SlimeProperties.SPAWN_X, 0);
props.setValue(SlimeProperties.SPAWN_Y, 2);
props.setValue(SlimeProperties.SPAWN_Z, 0);
Island island = new Island(name, uuid, displayName, descritpion, owner, ownerType, null);
Island island = new Island(type, uuid, displayName, descritpion, owner, ownerType, null);
island.save(); island.save();
SlimeWorld slimeWorld = asp.createEmptyWorld(uuid, false, props, loader);
SlimeWorld slimeWorld;
slimeWorld = asp.createEmptyWorld(uuid, false, props, databaseLoader);
asp.saveWorld(slimeWorld);
Bukkit.getScheduler().runTask(plugin, () -> {
asp.loadWorld(slimeWorld, true);
});
} catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); }
}); });
} catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); }
return uuid;
} }
// 2. Retrieve and Load existing island
public int loadIsland(String uuid) {
if (Bukkit.getWorld(uuid) != null) {
return 0; public void teleport(Player player, String uuid) throws Exception {
teleport(player, uuid, null, null, null, null, null);
}
public void teleport(Player player, String uuid, Integer x, Integer y, Integer z, Float yaw, Float pitch) throws Exception {
if (Bukkit.getWorld(uuid) != null){
teleportLocally(player, uuid, x, y, z, yaw, pitch);
} }
try { String whereIsActive = whereIsActive(uuid);
Island island = DaoRegistry.getIslandDao().queryBuilder() if (whereIsActive != null){
.selectColumns("active_on") sendPlayerAway(player, whereIsActive, uuid, x, y, z, yaw, pitch);
.where() }
.eq("uuid", uuid)
.queryForFirst(); QueryBuilder<Island, Integer> queryBuilder = dao.queryBuilder().setCountOf(true);
queryBuilder.where().eq("uuid", uuid);
if (!island.getActiveOn().isEmpty()){
return 1; if (dao.countOf(queryBuilder.prepare()) < 1){
return;
}
if (player.getVirtualHost() != null){
String emptiestServer = getEmptiestServer();
if (!Objects.equals(emptiestServer, config.getString("server.name"))){
sendPlayerAway(player, emptiestServer, uuid, x, y, z, yaw, pitch);
} }
} catch (SQLException e) {
return 2;
} }
teleportLocally(player, uuid, x, y, z, yaw, pitch);
}
public void teleportLocally(Player player, String uuid,
Integer x, Integer y, Integer z,
Float yaw, Float pitch) {
loadIsland(uuid).thenAccept(world -> {
Location location = world.getSpawnLocation();
if (x != null) {
location = new Location(world, x, y, z, yaw, pitch);
}
player.teleport(location);
}).exceptionally(ex -> {
ex.printStackTrace();
player.sendMessage("§cFailed to load island.");
return null;
});
}
private String whereIsActive(String uuid) throws SQLException {
Island island = dao.queryBuilder()
.selectColumns("active_on")
.where()
.eq("uuid", uuid)
.queryForFirst();
if (island == null){
return null;
}
if (island.getActiveOn() == null){
return null;
}
return island.getActiveOn();
}
private void sendPlayerAway(Player player, String server, String uuid, Integer x, Integer y, Integer z, Float yaw, Float pitch) throws SQLException {
TeleportRequest teleportRequest = new TeleportRequest(player.getName(), server, uuid, x, y, z, yaw, pitch);
teleportRequest.save();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(server);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
public void loadIslandTemplate(String name){
SlimeWorld slimeWorld = null;
try {
slimeWorld = asp.readWorld(fileLoader, name, false, new SlimePropertyMap());
asp.loadWorld(slimeWorld, true);
} catch (UnknownWorldException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (CorruptedWorldException e) {
throw new RuntimeException(e);
} catch (NewerFormatException e) {
throw new RuntimeException(e);
}
}
public CompletableFuture<World> loadIsland(String uuid) {
CompletableFuture<World> future = new CompletableFuture<>();
if (Bukkit.getWorld(uuid) != null) {
future.complete(Bukkit.getWorld(uuid));
return future;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
SlimeWorld slimeWorld = asp.readWorld(loader, uuid, false, new SlimePropertyMap()); SlimeWorld slimeWorld = asp.readWorld(databaseLoader, uuid, false, new SlimePropertyMap());
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
asp.loadWorld(slimeWorld, true); try {
UpdateBuilder updateBuilder = dao.updateBuilder();
updateBuilder.where().eq("uuid", uuid);
updateBuilder.updateColumnValue("active_on", config.getString("server.name"));
updateBuilder.update();
asp.loadWorld(slimeWorld, true);
World world = Bukkit.getWorld(uuid);
if (world != null) {
future.complete(world);
} else {
future.completeExceptionally(
new IllegalStateException("World loaded but Bukkit returned null"));
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}); });
} catch (Exception e) { e.printStackTrace(); }
} catch (Exception e) {
future.completeExceptionally(e);
}
}); });
return 0;
return future;
}
private String getEmptiestServer() throws Exception {
String query = "SELECT active_servers.name " +
"FROM active_servers " +
"LEFT JOIN islands ON active_servers.name = islands.active_on " +
"GROUP BY active_servers.name " +
"ORDER BY COUNT(islands.uuid) ASC " +
"LIMIT 1";
GenericRawResults<String[]> rawResults =
DaoRegistry.getActiveServerDao().queryRaw(query);
String[] firstResult = rawResults.getFirstResult();
rawResults.close();
if (firstResult != null && firstResult.length > 0) {
String serverName = firstResult[0];
return firstResult[0];
}
return null;
} }

@ -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);
}
}
}

@ -2,3 +2,6 @@ name: EcoCraftCore
version: '1.0-SNAPSHOT' version: '1.0-SNAPSHOT'
main: xyz.soukup.ecoCraftCore.EcoCraftCore main: xyz.soukup.ecoCraftCore.EcoCraftCore
api-version: '1.21' api-version: '1.21'
depend:
- packetevents

Loading…
Cancel
Save