diff --git a/src/main/java/net/minestom/server/data/Data.java b/src/main/java/net/minestom/server/data/Data.java index cdf080132..db06a817f 100644 --- a/src/main/java/net/minestom/server/data/Data.java +++ b/src/main/java/net/minestom/server/data/Data.java @@ -1,28 +1,20 @@ package net.minestom.server.data; import net.minestom.server.MinecraftServer; -import net.minestom.server.utils.PrimitiveConversion; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Data { - private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager(); + protected static final DataManager DATA_MANAGER = MinecraftServer.getDataManager(); - // TODO replace maps to something more memory-friendly - private ConcurrentHashMap data = new ConcurrentHashMap(); - private ConcurrentHashMap dataType = new ConcurrentHashMap<>(); + protected ConcurrentHashMap data = new ConcurrentHashMap(); public void set(String key, T value, Class type) { if (DATA_MANAGER.getDataType(type) == null) { throw new UnsupportedOperationException("Type " + type.getName() + " hasn't been registered in DataManager#registerType"); } this.data.put(key, value); - this.dataType.put(key, type); } public T get(String key) { @@ -36,36 +28,7 @@ public class Data { public Data clone() { Data data = new Data(); data.data = new ConcurrentHashMap<>(this.data); - data.dataType = new ConcurrentHashMap<>(dataType); return data; } - public byte[] getSerializedData() throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(output); - - for (Map.Entry entry : data.entrySet()) { - String key = entry.getKey(); - Class type = dataType.get(key); - Object value = entry.getValue(); - DataType dataType = DATA_MANAGER.getDataType(type); - - byte[] encodedType = PrimitiveConversion.getObjectClassString(type.getName()).getBytes(); // Data type (fix for primitives) - dos.writeShort(encodedType.length); - dos.write(encodedType); - - byte[] encodedName = key.getBytes(); // Data name - dos.writeShort(encodedName.length); - dos.write(encodedName); - - byte[] encodedValue = dataType.encode(value); // Data - dos.writeInt(encodedValue.length); - dos.write(encodedValue); - } - - dos.writeShort(0xff); // End of data object - - return output.toByteArray(); - } - } diff --git a/src/main/java/net/minestom/server/data/DataContainer.java b/src/main/java/net/minestom/server/data/DataContainer.java index ef34acb69..629aac6f2 100644 --- a/src/main/java/net/minestom/server/data/DataContainer.java +++ b/src/main/java/net/minestom/server/data/DataContainer.java @@ -22,9 +22,12 @@ public interface DataContainer { Data data = getData(); if (data == null) throw new NullPointerException("You cannot save null data!"); + if (!(data instanceof SerializableData)) + throw new IllegalArgumentException("Only SerializableData can be serialized"); + SerializableData serializableData = (SerializableData) data; try (FileOutputStream fos = new FileOutputStream(file)) { - byte[] serializedData = data.getSerializedData(); + byte[] serializedData = serializableData.getSerializedData(); fos.write(CompressionUtils.getCompressedData(serializedData)); } catch (FileNotFoundException e) { e.printStackTrace(); @@ -59,7 +62,7 @@ public interface DataContainer { return; } - Data data = DataReader.readData(array, true); + SerializableData data = DataReader.readData(array, true); setData(data); if (callback != null) diff --git a/src/main/java/net/minestom/server/data/DataManager.java b/src/main/java/net/minestom/server/data/DataManager.java index 9e5897c95..e2b2ad444 100644 --- a/src/main/java/net/minestom/server/data/DataManager.java +++ b/src/main/java/net/minestom/server/data/DataManager.java @@ -23,7 +23,7 @@ public class DataManager { registerType(String.class, new StringData()); - registerType(Data.class, new DataData()); + registerType(SerializableData.class, new SerializableDataData()); } public void registerType(Class clazz, DataType dataType) { diff --git a/src/main/java/net/minestom/server/data/SerializableData.java b/src/main/java/net/minestom/server/data/SerializableData.java new file mode 100644 index 000000000..93ec4cb26 --- /dev/null +++ b/src/main/java/net/minestom/server/data/SerializableData.java @@ -0,0 +1,56 @@ +package net.minestom.server.data; + +import net.minestom.server.utils.PrimitiveConversion; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class SerializableData extends Data { + + private ConcurrentHashMap dataType = new ConcurrentHashMap<>(); + + @Override + public void set(String key, T value, Class type) { + super.set(key, value, type); + this.dataType.put(key, type); + } + + @Override + public Data clone() { + SerializableData cloned = (SerializableData) super.clone(); + cloned.dataType = new ConcurrentHashMap<>(dataType); + return super.clone(); + } + + public byte[] getSerializedData() throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(output); + + for (Map.Entry entry : data.entrySet()) { + String key = entry.getKey(); + Class type = dataType.get(key); + Object value = entry.getValue(); + DataType dataType = DATA_MANAGER.getDataType(type); + + byte[] encodedType = PrimitiveConversion.getObjectClassString(type.getName()).getBytes(); // Data type (fix for primitives) + dos.writeShort(encodedType.length); + dos.write(encodedType); + + byte[] encodedName = key.getBytes(); // Data name + dos.writeShort(encodedName.length); + dos.write(encodedName); + + byte[] encodedValue = dataType.encode(value); // Data + dos.writeInt(encodedValue.length); + dos.write(encodedValue); + } + + dos.writeShort(0xff); // End of data object + + return output.toByteArray(); + } + +} diff --git a/src/main/java/net/minestom/server/data/type/DataData.java b/src/main/java/net/minestom/server/data/type/SerializableDataData.java similarity index 68% rename from src/main/java/net/minestom/server/data/type/DataData.java rename to src/main/java/net/minestom/server/data/type/SerializableDataData.java index 5534ea6ed..a86151645 100644 --- a/src/main/java/net/minestom/server/data/type/DataData.java +++ b/src/main/java/net/minestom/server/data/type/SerializableDataData.java @@ -1,15 +1,16 @@ package net.minestom.server.data.type; -import net.minestom.server.data.Data; import net.minestom.server.data.DataType; +import net.minestom.server.data.SerializableData; import net.minestom.server.io.DataReader; import java.io.IOException; // Pretty weird name huh? -public class DataData extends DataType { +public class SerializableDataData extends DataType { + @Override - public byte[] encode(Data value) { + public byte[] encode(SerializableData value) { try { return value.getSerializedData(); } catch (IOException e) { @@ -19,7 +20,7 @@ public class DataData extends DataType { } @Override - public Data decode(byte[] value) { + public SerializableData decode(byte[] value) { return DataReader.readData(value, false); } } diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 164973a3b..984bfa753 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.*; import net.minestom.server.MinecraftServer; import net.minestom.server.Viewable; import net.minestom.server.data.Data; +import net.minestom.server.data.SerializableData; import net.minestom.server.entity.Player; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockManager; @@ -141,7 +142,7 @@ public class Chunk implements Viewable { public short getBlockId(int x, int y, int z) { int index = getBlockIndex(x, y, z); - if(index < 0 || index >= blocksId.length) { + if (index < 0 || index >= blocksId.length) { return 0; // TODO: custom invalid block } short id = blocksId[index]; @@ -150,7 +151,7 @@ public class Chunk implements Viewable { public short getCustomBlockId(int x, int y, int z) { int index = getBlockIndex(x, y, z); - if(index < 0 || index >= blocksId.length) { + if (index < 0 || index >= blocksId.length) { return 0; // TODO: custom invalid block } short id = customBlocksId[index]; @@ -159,7 +160,7 @@ public class Chunk implements Viewable { public CustomBlock getCustomBlock(int x, int y, int z) { int index = getBlockIndex(x, y, z); - if(index < 0 || index >= blocksId.length) { + if (index < 0 || index >= blocksId.length) { return null; // TODO: custom invalid block } short id = customBlocksId[index]; @@ -173,7 +174,7 @@ public class Chunk implements Viewable { protected void refreshBlockValue(int x, int y, int z, short blockId, short customId) { int blockIndex = getBlockIndex(x, y, z); - if(blockIndex < 0 || blockIndex >= blocksId.length) { + if (blockIndex < 0 || blockIndex >= blocksId.length) { return; } @@ -287,11 +288,13 @@ public class Chunk implements Viewable { dos.writeBoolean(isCustomBlock); // Determine the type of the ID dos.writeShort(id); - dos.writeBoolean(hasData); - if (hasData) { - byte[] d = data.getSerializedData(); - dos.writeInt(d.length); - dos.write(d); + if (data instanceof SerializableData) { + dos.writeBoolean(hasData); + if (hasData) { + byte[] d = ((SerializableData) data).getSerializedData(); + dos.writeInt(d.length); + dos.write(d); + } } } } diff --git a/src/main/java/net/minestom/server/io/DataReader.java b/src/main/java/net/minestom/server/io/DataReader.java index 74e50b337..c0ff92e4f 100644 --- a/src/main/java/net/minestom/server/io/DataReader.java +++ b/src/main/java/net/minestom/server/io/DataReader.java @@ -1,8 +1,8 @@ package net.minestom.server.io; import net.minestom.server.MinecraftServer; -import net.minestom.server.data.Data; import net.minestom.server.data.DataManager; +import net.minestom.server.data.SerializableData; import net.minestom.server.utils.CompressionUtils; import java.io.ByteArrayInputStream; @@ -13,12 +13,12 @@ public class DataReader { private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager(); - public static Data readData(byte[] b, boolean shouldDecompress) { + public static SerializableData readData(byte[] b, boolean shouldDecompress) { b = shouldDecompress ? CompressionUtils.getDecompressedData(b) : b; DataInputStream stream = new DataInputStream(new ByteArrayInputStream(b)); - Data data = new Data(); + SerializableData data = new SerializableData(); try { while (true) { short typeLength = stream.readShort();