mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-05 23:11:36 +01:00
Removed the reader classes, deplaced them into SerializableData and Chunk respectively. It allows for developers to make their own deserialization AND serialization implementation
This commit is contained in:
parent
81db2dbdf9
commit
890cfe4622
@ -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
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* Use {@link net.minestom.server.reader.DataReader#readIndexedData(BinaryReader)}
|
||||
* Use {@link #readIndexedSerializedData(BinaryReader)}
|
||||
* to convert it back to a {@link SerializableData}
|
||||
* <p>
|
||||
* 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<String> 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)
|
||||
* <p>
|
||||
* 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<String> readDataIndexes(BinaryReader binaryReader) {
|
||||
Object2ShortMap<String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String, Class> dataType = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Class name -> Class
|
||||
* Used to cache data so we don't load class by name each time
|
||||
*/
|
||||
private static ConcurrentHashMap<String, Class> nameToClassMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Set a value to a specific key
|
||||
* <p>
|
||||
@ -104,4 +113,79 @@ public class SerializableDataImpl extends DataImpl implements SerializableData {
|
||||
return getSerializedData(new Object2ShortOpenHashMap<>(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSerializedData(BinaryReader reader, Object2ShortMap<String> 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<String> 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)
|
||||
* <p>
|
||||
* 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<String> typeToIndexMap, BinaryReader reader) {
|
||||
final Short2ObjectMap<String> indexToTypeMap = new Short2ObjectOpenHashMap<>(typeToIndexMap.size());
|
||||
{
|
||||
// Fill the indexToType map
|
||||
for (Object2ShortMap.Entry<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<SerializableData> {
|
||||
|
||||
@Override
|
||||
public SerializableData decode(BinaryReader reader) {
|
||||
return DataReader.readIndexedData(reader);
|
||||
SerializableData serializableData = new SerializableDataImpl();
|
||||
serializableData.readIndexedSerializedData(reader);
|
||||
return serializableData;
|
||||
}
|
||||
}
|
||||
|
@ -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<Player> 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
|
||||
* <p>
|
||||
* 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
|
||||
*
|
||||
|
@ -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)}
|
||||
* <p>
|
||||
* 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<String> 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();
|
||||
|
@ -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<Instance> 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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -22,7 +22,7 @@ public class ChunkBatch implements InstanceBatch {
|
||||
private final Chunk chunk;
|
||||
|
||||
// Give it the max capacity by default (avoid resizing)
|
||||
private List<BlockData> dataList =
|
||||
private final List<BlockData> 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);
|
||||
}
|
||||
|
@ -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
|
||||
* <p>
|
||||
* 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<String> 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
|
||||
}
|
||||
|
||||
}
|
@ -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}
|
||||
* <p>
|
||||
* 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<String, Class> 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)
|
||||
* <p>
|
||||
* 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<String> typeToIndexMap, BinaryReader reader) {
|
||||
final Short2ObjectMap<String> indexToTypeMap = new Short2ObjectOpenHashMap<>(typeToIndexMap.size());
|
||||
{
|
||||
// Fill the indexToType map
|
||||
for (Object2ShortMap.Entry<String> 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<String> 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<String> readDataIndexes(BinaryReader binaryReader) {
|
||||
Object2ShortMap<String> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user