mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-23 00:49:20 +00:00
add slime world support
This commit is contained in:
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld;
|
|||||||
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI;
|
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI;
|
||||||
import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent;
|
import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent;
|
||||||
import com.infernalsuite.asp.api.world.SlimeWorld;
|
import com.infernalsuite.asp.api.world.SlimeWorld;
|
||||||
|
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||||
import net.momirealms.craftengine.core.world.World;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
import net.momirealms.craftengine.core.world.WorldManager;
|
import net.momirealms.craftengine.core.world.WorldManager;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
|
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
|
||||||
@@ -12,13 +13,18 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener {
|
public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener {
|
||||||
private final WorldManager worldManager;
|
private final WorldManager worldManager;
|
||||||
|
private final Class<?> byteArrayTagClass = ReflectionUtils.getClazz("net{}kyori{}adventure{}nbt{}ByteArrayBinaryTag".replace("{}", "."));
|
||||||
|
private final Method method$ByteArrayBinaryTag$byteArrayBinaryTag = ReflectionUtils.getStaticMethod(byteArrayTagClass, byteArrayTagClass, byte.class.arrayType());
|
||||||
|
private final Method method$ByteArrayBinaryTag$value = ReflectionUtils.getMethod(byteArrayTagClass, byte.class.arrayType());
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onWorldLoad(LoadSlimeWorldEvent event) {
|
public void onWorldLoad(LoadSlimeWorldEvent event) {
|
||||||
org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName());
|
org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName());
|
||||||
this.worldManager.loadWorld(this.worldManager.wrap(world));
|
this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), new SlimeWorldDataStorage(event.getSlimeWorld(), this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SlimeFormatStorageAdaptor(WorldManager worldManager) {
|
public SlimeFormatStorageAdaptor(WorldManager worldManager) {
|
||||||
@@ -29,12 +35,29 @@ public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements
|
|||||||
return AdvancedSlimePaperAPI.instance().getLoadedWorld(name);
|
return AdvancedSlimePaperAPI.instance().getLoadedWorld(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 请注意,在加载事件的时候,无法通过AdvancedSlimePaperAPI.instance().getLoadedWorld来判断是否为slime世界
|
||||||
@Override
|
@Override
|
||||||
public @NotNull WorldDataStorage adapt(@NotNull World world) {
|
public @NotNull WorldDataStorage adapt(@NotNull World world) {
|
||||||
SlimeWorld slimeWorld = getWorld(world.name());
|
SlimeWorld slimeWorld = getWorld(world.name());
|
||||||
if (slimeWorld == null) {
|
if (slimeWorld == null) {
|
||||||
return super.adapt(world);
|
return super.adapt(world);
|
||||||
}
|
}
|
||||||
return new SlimeWorldDataStorage(slimeWorld);
|
return new SlimeWorldDataStorage(slimeWorld, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] byteArrayTagToBytes(Object byteArrayTag) {
|
||||||
|
try {
|
||||||
|
return (byte[]) method$ByteArrayBinaryTag$value.invoke(byteArrayTag);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException("Failed to convert byte array tag to byte[]", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object bytesToByteArrayTag(byte[] bytes) {
|
||||||
|
try {
|
||||||
|
return method$ByteArrayBinaryTag$byteArrayBinaryTag.invoke(null, (Object) bytes);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException("Failed to convert byte array tag to byte[]", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld;
|
|||||||
|
|
||||||
import com.infernalsuite.asp.api.world.SlimeChunk;
|
import com.infernalsuite.asp.api.world.SlimeChunk;
|
||||||
import com.infernalsuite.asp.api.world.SlimeWorld;
|
import com.infernalsuite.asp.api.world.SlimeWorld;
|
||||||
import net.kyori.adventure.nbt.BinaryTag;
|
|
||||||
import net.kyori.adventure.nbt.ByteArrayBinaryTag;
|
|
||||||
import net.momirealms.craftengine.core.world.ChunkPos;
|
import net.momirealms.craftengine.core.world.ChunkPos;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
|
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
|
||||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||||
@@ -14,12 +12,15 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class SlimeWorldDataStorage implements WorldDataStorage {
|
public class SlimeWorldDataStorage implements WorldDataStorage {
|
||||||
private final WeakReference<SlimeWorld> slimeWorld;
|
private final WeakReference<SlimeWorld> slimeWorld;
|
||||||
|
private final SlimeFormatStorageAdaptor adaptor;
|
||||||
|
|
||||||
public SlimeWorldDataStorage(SlimeWorld slimeWorld) {
|
public SlimeWorldDataStorage(SlimeWorld slimeWorld, SlimeFormatStorageAdaptor adaptor) {
|
||||||
this.slimeWorld = new WeakReference<>(slimeWorld);
|
this.slimeWorld = new WeakReference<>(slimeWorld);
|
||||||
|
this.adaptor = adaptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SlimeWorld getWorld() {
|
public SlimeWorld getWorld() {
|
||||||
@@ -31,16 +32,16 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
|
|||||||
public CompoundTag readChunkTagAt(ChunkPos pos) {
|
public CompoundTag readChunkTagAt(ChunkPos pos) {
|
||||||
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
||||||
if (slimeChunk == null) return null;
|
if (slimeChunk == null) return null;
|
||||||
BinaryTag tag = slimeChunk.getExtraData().get("craftengine");
|
Object tag = slimeChunk.getExtraData().get("craftengine");
|
||||||
if (tag == null) return null;
|
if (tag == null) return null;
|
||||||
ByteArrayBinaryTag byteArrayBinaryTag = (ByteArrayBinaryTag) tag;
|
|
||||||
try {
|
try {
|
||||||
return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(byteArrayBinaryTag.value())));
|
return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(adaptor.byteArrayTagToBytes(tag))));
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e);
|
throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) {
|
public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) {
|
||||||
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
||||||
@@ -48,13 +49,14 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
|
|||||||
if (nbt == null) {
|
if (nbt == null) {
|
||||||
slimeChunk.getExtraData().remove("craftengine");
|
slimeChunk.getExtraData().remove("craftengine");
|
||||||
} else {
|
} else {
|
||||||
slimeChunk.getExtraData().computeIfAbsent("craftengine", l -> {
|
try {
|
||||||
try {
|
Object tag = adaptor.bytesToByteArrayTag(NBT.toBytes(nbt));
|
||||||
return ByteArrayBinaryTag.byteArrayBinaryTag(NBT.toBytes(nbt));
|
Map<String, ?> data1 = slimeChunk.getExtraData();
|
||||||
} catch (IOException e) {
|
Map<String, Object> data2 = (Map<String, Object>) data1;
|
||||||
throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e);
|
data2.put("craftengine", tag);
|
||||||
}
|
} catch (Exception e) {
|
||||||
});
|
throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.util.SectionPosUtils;
|
|||||||
import net.momirealms.craftengine.core.world.CEWorld;
|
import net.momirealms.craftengine.core.world.CEWorld;
|
||||||
import net.momirealms.craftengine.core.world.World;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
|
||||||
|
|
||||||
public class BukkitCEWorld extends CEWorld {
|
public class BukkitCEWorld extends CEWorld {
|
||||||
|
|
||||||
@@ -13,6 +14,10 @@ public class BukkitCEWorld extends CEWorld {
|
|||||||
super(world, adaptor);
|
super(world, adaptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BukkitCEWorld(World world, WorldDataStorage dataStorage) {
|
||||||
|
super(world, dataStorage);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if (ConfigManager.enableLightSystem()) {
|
if (ConfigManager.enableLightSystem()) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.world.chunk.CESection;
|
|||||||
import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer;
|
import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
|
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
|
||||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
@@ -168,6 +169,26 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadWorld(CEWorld world) {
|
||||||
|
this.worldMapLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
if (this.worlds.containsKey(world.world().uuid())) return;
|
||||||
|
this.worlds.put(world.world().uuid(), world);
|
||||||
|
this.resetWorldArray();
|
||||||
|
for (Chunk chunk : ((World) world.world().platformWorld()).getLoadedChunks()) {
|
||||||
|
handleChunkLoad(world, chunk);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.worldMapLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CEWorld createWorld(net.momirealms.craftengine.core.world.World world, WorldDataStorage storage) {
|
||||||
|
return new BukkitCEWorld(world, storage);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||||
public void onWorldUnload(WorldUnloadEvent event) {
|
public void onWorldUnload(WorldUnloadEvent event) {
|
||||||
unloadWorld(new BukkitWorld(event.getWorld()));
|
unloadWorld(new BukkitWorld(event.getWorld()));
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ public abstract class CEWorld {
|
|||||||
this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS;
|
this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CEWorld(World world, WorldDataStorage dataStorage) {
|
||||||
|
this.world = world;
|
||||||
|
this.loadedChunkMap = new Long2ObjectOpenHashMap<>(1024, 0.5f);
|
||||||
|
this.worldDataStorage = dataStorage;
|
||||||
|
this.worldHeightAccessor = world.worldHeight();
|
||||||
|
this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS;
|
||||||
|
}
|
||||||
|
|
||||||
public World world() {
|
public World world() {
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.world;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.core.plugin.Reloadable;
|
import net.momirealms.craftengine.core.plugin.Reloadable;
|
||||||
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -16,6 +17,10 @@ public interface WorldManager extends Reloadable {
|
|||||||
|
|
||||||
void loadWorld(World world);
|
void loadWorld(World world);
|
||||||
|
|
||||||
|
void loadWorld(CEWorld world);
|
||||||
|
|
||||||
|
CEWorld createWorld(World world, WorldDataStorage storage);
|
||||||
|
|
||||||
void unloadWorld(World world);
|
void unloadWorld(World world);
|
||||||
|
|
||||||
<T> World wrap(T world);
|
<T> World wrap(T world);
|
||||||
|
|||||||
Reference in New Issue
Block a user