From 890cfe46222e45e2c1351ee5a912b9a2073dbd69 Mon Sep 17 00:00:00 2001 From: themode Date: Wed, 23 Sep 2020 21:08:36 +0200 Subject: [PATCH] Removed the reader classes, deplaced them into SerializableData and Chunk respectively. It allows for developers to make their own deserialization AND serialization implementation --- .../server/data/SerializableData.java | 47 +++++++- .../server/data/SerializableDataImpl.java | 84 +++++++++++++ .../data/type/SerializableDataData.java | 6 +- .../net/minestom/server/instance/Chunk.java | 28 ++++- .../server/instance/DynamicChunk.java | 69 ++++++++++- .../minestom/server/instance/Instance.java | 4 +- .../server/instance/InstanceContainer.java | 4 +- .../instance/MinestomBasicChunkLoader.java | 6 +- .../minestom/server/instance/StaticChunk.java | 11 +- .../server/instance/batch/ChunkBatch.java | 14 +-- .../minestom/server/reader/ChunkReader.java | 93 -------------- .../minestom/server/reader/DataReader.java | 113 ------------------ .../server/storage/StorageLocation.java | 25 +--- 13 files changed, 242 insertions(+), 262 deletions(-) delete mode 100644 src/main/java/net/minestom/server/reader/ChunkReader.java delete mode 100644 src/main/java/net/minestom/server/reader/DataReader.java diff --git a/src/main/java/net/minestom/server/data/SerializableData.java b/src/main/java/net/minestom/server/data/SerializableData.java index 581040f41..00bebd9fa 100644 --- a/src/main/java/net/minestom/server/data/SerializableData.java +++ b/src/main/java/net/minestom/server/data/SerializableData.java @@ -1,13 +1,13 @@ package net.minestom.server.data; import it.unimi.dsi.fastutil.objects.Object2ShortMap; +import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; import net.minestom.server.MinecraftServer; -import net.minestom.server.reader.DataReader; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; /** - * Represent a {@link Data} object which can be serialized and read back by the {@link DataReader} + * Represent a {@link Data} object which can be serialized and read back */ public interface SerializableData extends Data { @@ -16,8 +16,8 @@ public interface SerializableData extends Data { /** * Serialize the data into an array of bytes *

- * Use {@link DataReader#readIndexedData(BinaryReader)} if {@code indexed} is true, - * {@link DataReader#readData(Object2ShortMap, BinaryReader)} otherwise with the index map + * Use {@link #readIndexedSerializedData(BinaryReader)} if {@code indexed} is true, + * {@link #readSerializedData(BinaryReader, Object2ShortMap)} otherwise with the index map * to convert it back to a {@link SerializableData} * * @param typeToIndexMap the type to index map, will create entries if new types are discovered. @@ -30,7 +30,7 @@ public interface SerializableData extends Data { /** * Serialize the data into an array of bytes *

- * Use {@link net.minestom.server.reader.DataReader#readIndexedData(BinaryReader)} + * Use {@link #readIndexedSerializedData(BinaryReader)} * to convert it back to a {@link SerializableData} *

* This will create a type index map which will be present in the header @@ -40,7 +40,23 @@ public interface SerializableData extends Data { byte[] getIndexedSerializedData(); /** - * Get the index info (class name -> class index) + * Read the data of a {@link SerializableData} when you already have the index map + * + * @param reader the binary reader + * @param typeToIndexMap the index map + */ + void readSerializedData(BinaryReader reader, Object2ShortMap typeToIndexMap); + + /** + * Read the index map and the data of a serialized {@link SerializableData} + * Got from {@link #getIndexedSerializedData()} + * + * @param reader the binary reader + */ + void readIndexedSerializedData(BinaryReader reader); + + /** + * Get the index info (class name -> class index) *

* Sized by a var-int * @@ -61,4 +77,23 @@ public interface SerializableData extends Data { } } + /** + * Get a map containing the indexes of your data (type name -> type index) + * + * @param binaryReader the reader + * @return a map containing the indexes of your data + */ + static Object2ShortMap readDataIndexes(BinaryReader binaryReader) { + Object2ShortMap typeToIndexMap = new Object2ShortOpenHashMap<>(); + { + final int dataIndexSize = binaryReader.readVarInt(); + for (int i = 0; i < dataIndexSize; i++) { + final String className = binaryReader.readSizedString(); + final short classIndex = binaryReader.readShort(); + typeToIndexMap.put(className, classIndex); + } + } + return typeToIndexMap; + } + } diff --git a/src/main/java/net/minestom/server/data/SerializableDataImpl.java b/src/main/java/net/minestom/server/data/SerializableDataImpl.java index 22b2009fc..566646b16 100644 --- a/src/main/java/net/minestom/server/data/SerializableDataImpl.java +++ b/src/main/java/net/minestom/server/data/SerializableDataImpl.java @@ -2,7 +2,10 @@ package net.minestom.server.data; import it.unimi.dsi.fastutil.objects.Object2ShortMap; import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.minestom.server.utils.PrimitiveConversion; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import java.util.Map; @@ -15,6 +18,12 @@ public class SerializableDataImpl extends DataImpl implements SerializableData { private ConcurrentHashMap dataType = new ConcurrentHashMap<>(); + /** + * Class name -> Class + * Used to cache data so we don't load class by name each time + */ + private static ConcurrentHashMap nameToClassMap = new ConcurrentHashMap<>(); + /** * Set a value to a specific key *

@@ -104,4 +113,79 @@ public class SerializableDataImpl extends DataImpl implements SerializableData { return getSerializedData(new Object2ShortOpenHashMap<>(), true); } + @Override + public void readSerializedData(BinaryReader reader, Object2ShortMap typeToIndexMap) { + readIndexedData(this, typeToIndexMap, reader); + } + + @Override + public void readIndexedSerializedData(BinaryReader reader) { + readData(this, reader); + } + + /** + * Read the indexes of the data + the data + * + * @param data the object to append the data + * @param reader the reader + * @return the deserialized {@link SerializableData} + */ + private static void readData(SerializableData data, BinaryReader reader) { + final Object2ShortMap typeToIndexMap = SerializableData.readDataIndexes(reader); + readIndexedData(data, typeToIndexMap, reader); + } + + /** + * Convert a buffer into a {@link SerializableData}, this will not read the data index header. + * Use {@link #readData(SerializableData, BinaryReader)} to read the whole data object (if your data contains the indexes) + *

+ * WARNING: the {@link DataManager} needs to have all the required types as the {@link SerializableData} has + * + * @param data the object to append the data + * @param typeToIndexMap the map which index all the type contained in the data (className->classIndex) + * @param reader the reader + */ + private static void readIndexedData(SerializableData data, Object2ShortMap typeToIndexMap, BinaryReader reader) { + final Short2ObjectMap indexToTypeMap = new Short2ObjectOpenHashMap<>(typeToIndexMap.size()); + { + // Fill the indexToType map + for (Object2ShortMap.Entry entry : typeToIndexMap.object2ShortEntrySet()) { + final String type = entry.getKey(); + final short index = entry.getShortValue(); + indexToTypeMap.put(index, type); + } + } + + while (true) { + // Get the class index + final short typeIndex = reader.readShort(); + + if (typeIndex == 0) { + // End of data + break; + } + + final Class type; + { + final String className = indexToTypeMap.get(typeIndex); + type = nameToClassMap.computeIfAbsent(className, s -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + }); + } + + // Get the key + final String name = reader.readSizedString(); + + // Get the data + final Object value = DATA_MANAGER.getDataType(type).decode(reader); + + // Set the data + data.set(name, value, type); + } + } } diff --git a/src/main/java/net/minestom/server/data/type/SerializableDataData.java b/src/main/java/net/minestom/server/data/type/SerializableDataData.java index 09223d4fd..3507e872e 100644 --- a/src/main/java/net/minestom/server/data/type/SerializableDataData.java +++ b/src/main/java/net/minestom/server/data/type/SerializableDataData.java @@ -2,7 +2,7 @@ package net.minestom.server.data.type; import net.minestom.server.data.DataType; import net.minestom.server.data.SerializableData; -import net.minestom.server.reader.DataReader; +import net.minestom.server.data.SerializableDataImpl; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; @@ -16,6 +16,8 @@ public class SerializableDataData extends DataType { @Override public SerializableData decode(BinaryReader reader) { - return DataReader.readIndexedData(reader); + SerializableData serializableData = new SerializableDataImpl(); + serializableData.readIndexedSerializedData(reader); + return serializableData; } } diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 7af168410..0fb3cef54 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -20,12 +20,15 @@ import net.minestom.server.network.packet.server.play.UpdateLightPacket; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.player.PlayerUtils; import net.minestom.server.utils.time.CooldownUtils; import net.minestom.server.utils.time.UpdateOption; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.biomes.Biome; +import net.minestom.server.world.biomes.BiomeManager; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; @@ -35,6 +38,7 @@ import java.util.function.Consumer; public abstract class Chunk implements Viewable { protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); + protected static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager(); public static final int CHUNK_SIZE_X = 16; public static final int CHUNK_SIZE_Y = 256; @@ -45,6 +49,7 @@ public abstract class Chunk implements Viewable { public static final int BIOME_COUNT = 1024; // 4x4x4 blocks + protected final Instance instance; protected Biome[] biomes; protected int chunkX, chunkZ; @@ -70,10 +75,16 @@ public abstract class Chunk implements Viewable { protected Set viewers = new CopyOnWriteArraySet<>(); protected ByteBuf fullDataPacket; - public Chunk(Biome[] biomes, int chunkX, int chunkZ) { - this.biomes = biomes; + public Chunk(Instance instance, Biome[] biomes, int chunkX, int chunkZ) { + this.instance = instance; this.chunkX = chunkX; this.chunkZ = chunkZ; + + if (biomes != null && biomes.length == BIOME_COUNT) { + this.biomes = biomes; + } else { + this.biomes = new Biome[BIOME_COUNT]; + } } /** @@ -314,12 +325,23 @@ public abstract class Chunk implements Viewable { } /** - * Serialize the chunk + * Serialize the chunk into bytes * * @return the serialized chunk, can potentially be null if this chunk cannot be serialized */ public abstract byte[] getSerializedData(); + /** + * Read the chunk from binary + *

+ * Used if the chunk is loaded from file + * + * @param reader the data reader + * @param callback the callback to execute once the chunk is done reading + * WARNING: this need to be called to notify the instance + */ + public abstract void readChunk(BinaryReader reader, ChunkCallback callback); + /** * Get a {@link ChunkDataPacket} which should contain the full chunk * diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 03d0f863a..359858e25 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -6,16 +6,18 @@ import it.unimi.dsi.fastutil.objects.Object2ShortMap; import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; import net.minestom.server.data.Data; import net.minestom.server.data.SerializableData; +import net.minestom.server.data.SerializableDataImpl; import net.minestom.server.entity.pathfinding.PFBlockDescription; +import net.minestom.server.instance.batch.ChunkBatch; import net.minestom.server.network.packet.server.play.ChunkDataPacket; -import net.minestom.server.reader.ChunkReader; import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.chunk.ChunkCallback; +import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.function.Consumer; public class DynamicChunk extends Chunk { @@ -25,8 +27,8 @@ public class DynamicChunk extends Chunk { protected final short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z]; protected final short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z]; - public DynamicChunk(Biome[] biomes, int chunkX, int chunkZ) { - super(biomes, chunkX, chunkZ); + public DynamicChunk(Instance instance, Biome[] biomes, int chunkX, int chunkZ) { + super(instance, biomes, chunkX, chunkZ); } @Override @@ -130,7 +132,7 @@ public class DynamicChunk extends Chunk { } /** - * Serialize this {@link Chunk} based on {@link ChunkReader#readChunk(byte[], Instance, int, int, ChunkCallback)} + * Serialize this {@link Chunk} based on {@link #readChunk(BinaryReader, ChunkCallback)} *

* It is also used by the default {@link IChunkLoader} which is {@link MinestomBasicChunkLoader} * @@ -197,6 +199,63 @@ public class DynamicChunk extends Chunk { return binaryWriter.toByteArray(); } + @Override + public void readChunk(BinaryReader reader, ChunkCallback callback) { + // Used for blocks data + Object2ShortMap typeToIndexMap = null; + + ChunkBatch chunkBatch = instance.createChunkBatch(this); + try { + + // Get if the chunk has data indexes (used for blocks data) + final boolean hasIndex = reader.readBoolean(); + if (hasIndex) { + // Get the data indexes which will be used to read all the individual data + typeToIndexMap = SerializableData.readDataIndexes(reader); + } + + for (int i = 0; i < BIOME_COUNT; i++) { + final byte id = reader.readByte(); + this.biomes[i] = BIOME_MANAGER.getById(id); + } + + while (true) { + // Position + final short index = reader.readShort(); + final byte x = ChunkUtils.blockIndexToChunkPositionX(index); + final short y = ChunkUtils.blockIndexToChunkPositionY(index); + final byte z = ChunkUtils.blockIndexToChunkPositionZ(index); + + // Block type + final short blockStateId = reader.readShort(); + final short customBlockId = reader.readShort(); + + // Data + SerializableData data = null; + { + final boolean hasData = reader.readBoolean(); + // Data deserializer + if (hasData) { + // Read the data with the deserialized index map + data = new SerializableDataImpl(); + data.readSerializedData(reader, typeToIndexMap); + } + } + + if (customBlockId != 0) { + chunkBatch.setSeparateBlocks(x, y, z, blockStateId, customBlockId, data); + } else { + chunkBatch.setBlockStateId(x, y, z, blockStateId, data); + } + } + } catch (IndexOutOfBoundsException e) { + // Finished reading + } + + // Place all the blocks from the batch + chunkBatch.unsafeFlush(callback); // Success, null if file isn't properly encoded + } + @Override protected ChunkDataPacket getFreshPacket() { ChunkDataPacket fullDataPacket = new ChunkDataPacket(); diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index ca49cd069..fa77391dc 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -103,7 +103,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta * @param callback the task to execute during the next instance tick */ public void scheduleNextTick(Consumer callback) { - nextTick.add(callback); + this.nextTick.add(callback); } /** @@ -375,7 +375,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta /** * Get a {@link TimeUpdatePacket} with the current age and time of this instance * - * @return the {@link TimeUpdatePacket} with this instance datal + * @return the {@link TimeUpdatePacket} with this instance data */ private TimeUpdatePacket getTimePacket() { TimeUpdatePacket timeUpdatePacket = new TimeUpdatePacket(); diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index dfb62893b..f12872ebe 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -491,10 +491,10 @@ public class InstanceContainer extends Instance { final BlockProvider blockProvider = chunkDecider != null ? chunkDecider.apply(chunkX, chunkZ) : null; if (blockProvider != null) { // Use static chunk - chunk = new StaticChunk(biomes, chunkX, chunkZ, blockProvider); + chunk = new StaticChunk(this, biomes, chunkX, chunkZ, blockProvider); } else { // Use dynamic chunk - chunk = new DynamicChunk(biomes, chunkX, chunkZ); + chunk = new DynamicChunk(this, biomes, chunkX, chunkZ); } cacheChunk(chunk); diff --git a/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java b/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java index dd70f39cd..6dc4388bd 100644 --- a/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java +++ b/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java @@ -1,7 +1,7 @@ package net.minestom.server.instance; -import net.minestom.server.reader.ChunkReader; import net.minestom.server.storage.StorageLocation; +import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.chunk.ChunkCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +48,9 @@ public class MinestomBasicChunkLoader implements IChunkLoader { return false; } else { // Found, load from result bytes - ChunkReader.readChunk(bytes, instance, chunkX, chunkZ, callback); + BinaryReader reader = new BinaryReader(bytes); + Chunk chunk = new DynamicChunk(instance, null, chunkX, chunkZ); + chunk.readChunk(reader, callback); return true; } } diff --git a/src/main/java/net/minestom/server/instance/StaticChunk.java b/src/main/java/net/minestom/server/instance/StaticChunk.java index 2c04aa8cb..e23d22b7c 100644 --- a/src/main/java/net/minestom/server/instance/StaticChunk.java +++ b/src/main/java/net/minestom/server/instance/StaticChunk.java @@ -4,6 +4,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minestom.server.data.Data; import net.minestom.server.instance.block.BlockProvider; import net.minestom.server.network.packet.server.play.ChunkDataPacket; +import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; @@ -13,8 +15,8 @@ public class StaticChunk extends Chunk { protected final BlockProvider blockProvider; - public StaticChunk(Biome[] biomes, int chunkX, int chunkZ, BlockProvider blockProvider) { - super(biomes, chunkX, chunkZ); + public StaticChunk(Instance instance, Biome[] biomes, int chunkX, int chunkZ, BlockProvider blockProvider) { + super(instance, biomes, chunkX, chunkZ); this.blockProvider = blockProvider; } @@ -49,6 +51,11 @@ public class StaticChunk extends Chunk { return null; } + @Override + public void readChunk(BinaryReader reader, ChunkCallback callback) { + callback.accept(this); + } + @Override protected ChunkDataPacket getFreshPacket() { ChunkDataPacket fullDataPacket = new ChunkDataPacket(); diff --git a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java index 8e0e47a8e..17047c1c3 100644 --- a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java @@ -22,7 +22,7 @@ public class ChunkBatch implements InstanceBatch { private final Chunk chunk; // Give it the max capacity by default (avoid resizing) - private List dataList = + private final List dataList = Collections.synchronizedList(new ArrayList<>( Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Y * Chunk.CHUNK_SIZE_Z)); @@ -88,9 +88,7 @@ public class ChunkBatch implements InstanceBatch { * @param callback the callback to execute once the blocks are placed */ public void flush(ChunkCallback callback) { - batchesPool.execute(() -> { - singleThreadFlush(callback, true); - }); + batchesPool.execute(() -> singleThreadFlush(callback, true)); } /** @@ -99,9 +97,7 @@ public class ChunkBatch implements InstanceBatch { * @param callback the callback to execute once the blocks are placed */ public void unsafeFlush(ChunkCallback callback) { - batchesPool.execute(() -> { - singleThreadFlush(callback, false); - }); + batchesPool.execute(() -> singleThreadFlush(callback, false)); } public void clearData() { @@ -129,9 +125,7 @@ public class ChunkBatch implements InstanceBatch { if (callback != null) { if (safeCallback) { - instance.scheduleNextTick(inst -> { - callback.accept(chunk); - }); + instance.scheduleNextTick(inst -> callback.accept(chunk)); } else { callback.accept(chunk); } diff --git a/src/main/java/net/minestom/server/reader/ChunkReader.java b/src/main/java/net/minestom/server/reader/ChunkReader.java deleted file mode 100644 index f1bbceaf4..000000000 --- a/src/main/java/net/minestom/server/reader/ChunkReader.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.minestom.server.reader; - -import it.unimi.dsi.fastutil.objects.Object2ShortMap; -import net.minestom.server.MinecraftServer; -import net.minestom.server.data.Data; -import net.minestom.server.instance.Chunk; -import net.minestom.server.instance.DynamicChunk; -import net.minestom.server.instance.Instance; -import net.minestom.server.instance.batch.ChunkBatch; -import net.minestom.server.utils.binary.BinaryReader; -import net.minestom.server.utils.chunk.ChunkCallback; -import net.minestom.server.utils.chunk.ChunkUtils; -import net.minestom.server.world.biomes.Biome; -import net.minestom.server.world.biomes.BiomeManager; - -public class ChunkReader { - - private static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager(); - - /** - * Read a chunk from a byte array, the array should contain the whole chunk and only it - *

- * By default you can retrieve this byte array using {@link DynamicChunk#getSerializedData()} - * - * @param b the byte array containing the chunk - * @param instance the instance of the chunk - * @param chunkX the chunk X - * @param chunkZ the chunk Z - * @param callback the consumer called once the chunk has been read - */ - public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, ChunkCallback callback) { - BinaryReader binaryReader = new BinaryReader(b); - - // Used for blocks data - Object2ShortMap typeToIndexMap = null; - - ChunkBatch chunkBatch = null; - try { - - // Get if the chunk has data indexes (used for blocks data) - final boolean hasIndex = binaryReader.readBoolean(); - if (hasIndex) { - // Get the data indexes which will be used to read all the individual data - typeToIndexMap = DataReader.readDataIndexes(binaryReader); - } - - Biome[] biomes = new Biome[Chunk.BIOME_COUNT]; - for (int i = 0; i < biomes.length; i++) { - final byte id = binaryReader.readByte(); - biomes[i] = BIOME_MANAGER.getById(id); - } - - final Chunk chunk = new DynamicChunk(biomes, chunkX, chunkZ); - - chunkBatch = instance.createChunkBatch(chunk); - - while (true) { - // Position - final short index = binaryReader.readShort(); - final byte x = ChunkUtils.blockIndexToChunkPositionX(index); - final short y = ChunkUtils.blockIndexToChunkPositionY(index); - final byte z = ChunkUtils.blockIndexToChunkPositionZ(index); - - // Block type - final short blockStateId = binaryReader.readShort(); - final short customBlockId = binaryReader.readShort(); - - // Data - Data data = null; - { - final boolean hasData = binaryReader.readBoolean(); - // Data deserializer - if (hasData) { - // Read the data with the deserialized index map - data = DataReader.readData(typeToIndexMap, binaryReader); - } - } - - if (customBlockId != 0) { - chunkBatch.setSeparateBlocks(x, y, z, blockStateId, customBlockId, data); - } else { - chunkBatch.setBlockStateId(x, y, z, blockStateId, data); - } - } - } catch (IndexOutOfBoundsException e) { - // Finished reading - } - - // Place all the blocks from the batch - chunkBatch.flush(c -> callback.accept(c)); // Success, null if file isn't properly encoded - } - -} diff --git a/src/main/java/net/minestom/server/reader/DataReader.java b/src/main/java/net/minestom/server/reader/DataReader.java deleted file mode 100644 index 914b7a8a8..000000000 --- a/src/main/java/net/minestom/server/reader/DataReader.java +++ /dev/null @@ -1,113 +0,0 @@ -package net.minestom.server.reader; - -import it.unimi.dsi.fastutil.objects.Object2ShortMap; -import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; -import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; -import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; -import net.minestom.server.MinecraftServer; -import net.minestom.server.data.DataManager; -import net.minestom.server.data.SerializableData; -import net.minestom.server.data.SerializableDataImpl; -import net.minestom.server.utils.binary.BinaryReader; - -import java.util.concurrent.ConcurrentHashMap; - -/** - * Class used to convert an array of bytes to a {@link SerializableData} - *

- * WARNING: the {@link DataManager} needs to have all the required types as the {@link SerializableData} has - */ -public class DataReader { - - private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager(); - - private static ConcurrentHashMap nameToClassMap = new ConcurrentHashMap<>(); - - /** - * Convert a buffer into a {@link SerializableData}, this will not read the data index header. - * Use {@link #readIndexedData(BinaryReader)} to read the whole data object (if your data contains the indexes) - *

- * WARNING: the {@link DataManager} needs to have all the required types as the {@link SerializableData} has - * - * @param typeToIndexMap the map which index all the type contained in the data (className->classIndex) - * @param reader the reader - * @return a {@link SerializableData} based on the data input - */ - public static SerializableData readData(Object2ShortMap typeToIndexMap, BinaryReader reader) { - final Short2ObjectMap indexToTypeMap = new Short2ObjectOpenHashMap<>(typeToIndexMap.size()); - { - // Fill the indexToType map - for (Object2ShortMap.Entry entry : typeToIndexMap.object2ShortEntrySet()) { - final String type = entry.getKey(); - final short index = entry.getShortValue(); - indexToTypeMap.put(index, type); - } - } - - SerializableData data = new SerializableDataImpl(); - while (true) { - // Get the class index - final short typeIndex = reader.readShort(); - - if (typeIndex == 0) { - // End of data - break; - } - - final Class type; - { - final String className = indexToTypeMap.get(typeIndex); - type = nameToClassMap.computeIfAbsent(className, s -> { - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - return null; - } - }); - } - - // Get the key - final String name = reader.readSizedString(); - - // Get the data - final Object value = DATA_MANAGER.getDataType(type).decode(reader); - - // Set the data - data.set(name, value, type); - } - - return data; - } - - /** - * Read the indexes of the data + the data - * - * @param reader the reader - * @return the deserialized {@link SerializableData} - */ - public static SerializableData readIndexedData(BinaryReader reader) { - final Object2ShortMap typeToIndexMap = readDataIndexes(reader); - return readData(typeToIndexMap, reader); - } - - /** - * Get a map containing the indexes of your data (type name -> type index) - * - * @param binaryReader the reader - * @return a map containing the indexes of your data - */ - public static Object2ShortMap readDataIndexes(BinaryReader binaryReader) { - Object2ShortMap typeToIndexMap = new Object2ShortOpenHashMap<>(); - { - final int dataIndexSize = binaryReader.readVarInt(); - for (int i = 0; i < dataIndexSize; i++) { - final String className = binaryReader.readSizedString(); - final short classIndex = binaryReader.readShort(); - typeToIndexMap.put(className, classIndex); - } - } - return typeToIndexMap; - } - -} diff --git a/src/main/java/net/minestom/server/storage/StorageLocation.java b/src/main/java/net/minestom/server/storage/StorageLocation.java index 587baf670..7f9e4d90d 100644 --- a/src/main/java/net/minestom/server/storage/StorageLocation.java +++ b/src/main/java/net/minestom/server/storage/StorageLocation.java @@ -1,12 +1,7 @@ package net.minestom.server.storage; import net.minestom.server.MinecraftServer; -import net.minestom.server.data.DataContainer; -import net.minestom.server.data.DataManager; -import net.minestom.server.data.DataType; -import net.minestom.server.data.SerializableData; -import net.minestom.server.data.SerializableDataImpl; -import net.minestom.server.reader.DataReader; +import net.minestom.server.data.*; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.validate.Check; @@ -147,14 +142,7 @@ public class StorageLocation { } // Load it from the storage system - final byte[] bytes = get(key); - SerializableData data; - - if (bytes != null) { - data = DataReader.readIndexedData(new BinaryReader(bytes)); - } else { - data = new SerializableDataImpl(); - } + SerializableData data = getOrDefault(key, SerializableData.class, new SerializableDataImpl()); dataContainer.setData(data); @@ -178,14 +166,7 @@ public class StorageLocation { } // Load it from the storage system and cache it - final byte[] bytes = get(key); - SerializableData data; - - if (bytes != null) { - data = DataReader.readIndexedData(new BinaryReader(bytes)); - } else { - data = new SerializableDataImpl(); - } + SerializableData data = getOrDefault(key, SerializableData.class, new SerializableDataImpl()); dataContainer.setData(data);