mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-07 19:31:37 +01:00
Merge pull request #45 from Nesaak/master
Make Data and SerializableData interfaces
This commit is contained in:
commit
74cfc1994d
@ -4,6 +4,7 @@ import de.articdive.jnoise.JNoise;
|
||||
import de.articdive.jnoise.interpolation.InterpolationType;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.SerializableData;
|
||||
import net.minestom.server.data.SerializableDataImpl;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.ChunkGenerator;
|
||||
import net.minestom.server.instance.ChunkPopulator;
|
||||
@ -46,7 +47,7 @@ public class NoiseTestGenerator implements ChunkGenerator {
|
||||
batch.setBlock(x, y, z, Block.GRASS_BLOCK);
|
||||
} else if (y > height - 7) {
|
||||
// Data for debugging purpose
|
||||
SerializableData serializableData = new SerializableData();
|
||||
SerializableData serializableData = new SerializableDataImpl();
|
||||
serializableData.set("test", 55, Integer.class);
|
||||
batch.setBlockStateId(x, y, z, Block.DIRT.getBlockId(), serializableData);
|
||||
} else {
|
||||
|
@ -2,14 +2,12 @@ package net.minestom.server.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class Data {
|
||||
public interface Data {
|
||||
|
||||
public static final Data EMPTY = new Data() {
|
||||
Data EMPTY = new Data() {
|
||||
@Override
|
||||
public <T> void set(String key, T value, Class<T> type) {
|
||||
}
|
||||
public <T> void set(String key, T value, Class<T> type) { }
|
||||
|
||||
@Override
|
||||
public <T> T get(String key) {
|
||||
@ -21,14 +19,27 @@ public class Data {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Data clone() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOrDefault(String key, T defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
protected final ConcurrentHashMap<String, Object> data = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Set a value to a specific key
|
||||
*
|
||||
@ -37,21 +48,16 @@ public class Data {
|
||||
* @param type the value type
|
||||
* @param <T> the value generic
|
||||
*/
|
||||
public <T> void set(String key, T value, Class<T> type) {
|
||||
this.data.put(key, value);
|
||||
}
|
||||
<T> void set(String key, T value, Class<T> type);
|
||||
|
||||
/**
|
||||
* Retrieve a value based on its key
|
||||
*
|
||||
* @param key the key
|
||||
* @param <T> the value type
|
||||
* @return the data associated with the key
|
||||
* @throws NullPointerException if the key is not found
|
||||
* @return the data associated with the key or null
|
||||
*/
|
||||
public <T> T get(String key) {
|
||||
return (T) data.get(key);
|
||||
}
|
||||
<T> T get(String key);
|
||||
|
||||
/**
|
||||
* Retrieve a value based on its key, give a default value if not found
|
||||
@ -61,9 +67,7 @@ public class Data {
|
||||
* @param <T> the value type
|
||||
* @return {@link #get(String)} if found, {@code defaultValue} otherwise
|
||||
*/
|
||||
public <T> T getOrDefault(String key, T defaultValue) {
|
||||
return (T) data.getOrDefault(key, defaultValue);
|
||||
}
|
||||
<T> T getOrDefault(String key, T defaultValue);
|
||||
|
||||
/**
|
||||
* Get if the data has a key
|
||||
@ -71,37 +75,27 @@ public class Data {
|
||||
* @param key the key to check
|
||||
* @return true if the data contains the key
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
return data.containsKey(key);
|
||||
}
|
||||
boolean hasKey(String key);
|
||||
|
||||
/**
|
||||
* Get the list of data keys
|
||||
*
|
||||
* @return an unmodifiable set containing all keys
|
||||
*/
|
||||
public Set<String> getKeys() {
|
||||
return Collections.unmodifiableSet(data.keySet());
|
||||
}
|
||||
Set<String> getKeys();
|
||||
|
||||
/**
|
||||
* Get if the data is empty or not
|
||||
*
|
||||
* @return true if the data does not contain anything, false otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return data.isEmpty();
|
||||
}
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Clone this data
|
||||
*
|
||||
* @return a cloned data object
|
||||
*/
|
||||
public Data clone() {
|
||||
Data data = new Data();
|
||||
data.data.putAll(this.data);
|
||||
return data;
|
||||
}
|
||||
Data clone();
|
||||
|
||||
}
|
||||
|
48
src/main/java/net/minestom/server/data/DataImpl.java
Normal file
48
src/main/java/net/minestom/server/data/DataImpl.java
Normal file
@ -0,0 +1,48 @@
|
||||
package net.minestom.server.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DataImpl implements Data {
|
||||
|
||||
protected final ConcurrentHashMap<String, Object> data = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public <T> void set(String key, T value, Class<T> type) {
|
||||
this.data.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(String key) {
|
||||
return (T) data.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOrDefault(String key, T defaultValue) {
|
||||
return (T) data.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return data.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
return Collections.unmodifiableSet(data.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return data.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Data clone() {
|
||||
DataImpl data = new DataImpl();
|
||||
data.data.putAll(this.data);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@ -1,52 +1,14 @@
|
||||
package net.minestom.server.data;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
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.PrimitiveConversion;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
public interface SerializableData extends Data {
|
||||
|
||||
public class SerializableData extends Data {
|
||||
|
||||
private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager();
|
||||
|
||||
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Set a value to a specific key
|
||||
* <p>
|
||||
* WARNING: the type needs to be registered in {@link DataManager}
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value object
|
||||
* @param type the value type
|
||||
* @param <T> the value generic
|
||||
* @throws UnsupportedOperationException if {@code type} is not registered in {@link DataManager}
|
||||
*/
|
||||
@Override
|
||||
public <T> void set(String key, T value, Class<T> type) {
|
||||
if (DATA_MANAGER.getDataType(type) == null) {
|
||||
throw new UnsupportedOperationException("Type " + type.getName() + " hasn't been registered in DataManager#registerType");
|
||||
}
|
||||
|
||||
super.set(key, value, type);
|
||||
this.dataType.put(key, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Data clone() {
|
||||
SerializableData data = new SerializableData();
|
||||
data.data.putAll(this.data);
|
||||
data.dataType.putAll(this.dataType);
|
||||
return data;
|
||||
}
|
||||
DataManager DATA_MANAGER = MinecraftServer.getDataManager();
|
||||
|
||||
/**
|
||||
* Serialize the data into an array of bytes
|
||||
@ -60,61 +22,7 @@ public class SerializableData extends Data {
|
||||
* @param indexed true to add the types index in the header
|
||||
* @return the array representation of this data object
|
||||
*/
|
||||
public byte[] getSerializedData(Object2ShortMap<String> typeToIndexMap, boolean indexed) {
|
||||
// Get the current max index, it supposes that the index keep being incremented by 1
|
||||
short lastIndex = (short) typeToIndexMap.size();
|
||||
|
||||
// Main buffer containing the data
|
||||
BinaryWriter binaryWriter = new BinaryWriter();
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
|
||||
final Class type = dataType.get(key);
|
||||
final short typeIndex;
|
||||
{
|
||||
// Find the type name
|
||||
final String encodedType = PrimitiveConversion.getObjectClassString(type.getName()); // Data type (fix for primitives)
|
||||
|
||||
// Find the type index
|
||||
if (typeToIndexMap.containsKey(encodedType)) {
|
||||
// Get index
|
||||
typeIndex = typeToIndexMap.getShort(encodedType);
|
||||
} else {
|
||||
// Create new index
|
||||
typeToIndexMap.put(encodedType, ++lastIndex);
|
||||
// Set index
|
||||
typeIndex = lastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the data type index
|
||||
binaryWriter.writeShort(typeIndex);
|
||||
|
||||
// Write the data key
|
||||
binaryWriter.writeSizedString(key);
|
||||
|
||||
// Write the data (no length)
|
||||
final DataType dataType = DATA_MANAGER.getDataType(type);
|
||||
dataType.encode(binaryWriter, value);
|
||||
}
|
||||
|
||||
binaryWriter.writeShort((short) 0); // End of data object
|
||||
|
||||
// Header for type indexes
|
||||
if (indexed) {
|
||||
// The buffer containing all the index info (class name to class index)
|
||||
BinaryWriter indexWriter = new BinaryWriter();
|
||||
writeDataIndexHeader(indexWriter, typeToIndexMap);
|
||||
// Merge the index buffer & the main data buffer
|
||||
final ByteBuf finalBuffer = Unpooled.wrappedBuffer(indexWriter.getBuffer(), binaryWriter.getBuffer());
|
||||
// Change the main writer buffer, so it contains both the indexes and the data
|
||||
binaryWriter.setBuffer(finalBuffer);
|
||||
}
|
||||
|
||||
return binaryWriter.toByteArray();
|
||||
}
|
||||
byte[] getSerializedData(Object2ShortMap<String> typeToIndexMap, boolean indexed);
|
||||
|
||||
/**
|
||||
* Serialize the data into an array of bytes
|
||||
@ -126,9 +34,7 @@ public class SerializableData extends Data {
|
||||
*
|
||||
* @return the array representation of this data object
|
||||
*/
|
||||
public byte[] getIndexedSerializedData() {
|
||||
return getSerializedData(new Object2ShortOpenHashMap<>(), true);
|
||||
}
|
||||
byte[] getIndexedSerializedData();
|
||||
|
||||
/**
|
||||
* Get the index info (class name -> class index)
|
||||
@ -137,7 +43,7 @@ public class SerializableData extends Data {
|
||||
*
|
||||
* @param typeToIndexMap the data index map
|
||||
*/
|
||||
public static void writeDataIndexHeader(BinaryWriter indexWriter, Object2ShortMap<String> typeToIndexMap) {
|
||||
static void writeDataIndexHeader(BinaryWriter indexWriter, Object2ShortMap<String> typeToIndexMap) {
|
||||
// Write the size of the following index list (class name-> class index)
|
||||
indexWriter.writeVarInt(typeToIndexMap.size());
|
||||
|
||||
|
108
src/main/java/net/minestom/server/data/SerializableDataImpl.java
Normal file
108
src/main/java/net/minestom/server/data/SerializableDataImpl.java
Normal file
@ -0,0 +1,108 @@
|
||||
package net.minestom.server.data;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ShortMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
|
||||
import net.minestom.server.utils.PrimitiveConversion;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SerializableDataImpl extends DataImpl implements SerializableData {
|
||||
|
||||
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Set a value to a specific key
|
||||
* <p>
|
||||
* WARNING: the type needs to be registered in {@link DataManager}
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value object
|
||||
* @param type the value type
|
||||
* @param <T> the value generic
|
||||
* @throws UnsupportedOperationException if {@code type} is not registered in {@link DataManager}
|
||||
*/
|
||||
@Override
|
||||
public <T> void set(String key, T value, Class<T> type) {
|
||||
if (DATA_MANAGER.getDataType(type) == null) {
|
||||
throw new UnsupportedOperationException("Type " + type.getName() + " hasn't been registered in DataManager#registerType");
|
||||
}
|
||||
|
||||
super.set(key, value, type);
|
||||
this.dataType.put(key, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Data clone() {
|
||||
SerializableDataImpl data = new SerializableDataImpl();
|
||||
data.data.putAll(this.data);
|
||||
data.dataType.putAll(this.dataType);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSerializedData(Object2ShortMap<String> typeToIndexMap, boolean indexed) {
|
||||
// Get the current max index, it supposes that the index keep being incremented by 1
|
||||
short lastIndex = (short) typeToIndexMap.size();
|
||||
|
||||
// Main buffer containing the data
|
||||
BinaryWriter binaryWriter = new BinaryWriter();
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
|
||||
final Class type = dataType.get(key);
|
||||
final short typeIndex;
|
||||
{
|
||||
// Find the type name
|
||||
final String encodedType = PrimitiveConversion.getObjectClassString(type.getName()); // Data type (fix for primitives)
|
||||
|
||||
// Find the type index
|
||||
if (typeToIndexMap.containsKey(encodedType)) {
|
||||
// Get index
|
||||
typeIndex = typeToIndexMap.getShort(encodedType);
|
||||
} else {
|
||||
// Create new index
|
||||
typeToIndexMap.put(encodedType, ++lastIndex);
|
||||
// Set index
|
||||
typeIndex = lastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the data type index
|
||||
binaryWriter.writeShort(typeIndex);
|
||||
|
||||
// Write the data key
|
||||
binaryWriter.writeSizedString(key);
|
||||
|
||||
// Write the data (no length)
|
||||
final DataType dataType = DATA_MANAGER.getDataType(type);
|
||||
dataType.encode(binaryWriter, value);
|
||||
}
|
||||
|
||||
binaryWriter.writeShort((short) 0); // End of data object
|
||||
|
||||
// Header for type indexes
|
||||
if (indexed) {
|
||||
// The buffer containing all the index info (class name to class index)
|
||||
BinaryWriter indexWriter = new BinaryWriter();
|
||||
SerializableData.writeDataIndexHeader(indexWriter, typeToIndexMap);
|
||||
// Merge the index buffer & the main data buffer
|
||||
final ByteBuf finalBuffer = Unpooled.wrappedBuffer(indexWriter.getBuffer(), binaryWriter.getBuffer());
|
||||
// Change the main writer buffer, so it contains both the indexes and the data
|
||||
binaryWriter.setBuffer(finalBuffer);
|
||||
}
|
||||
|
||||
return binaryWriter.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getIndexedSerializedData() {
|
||||
return getSerializedData(new Object2ShortOpenHashMap<>(), true);
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ 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;
|
||||
@ -43,7 +44,7 @@ public class DataReader {
|
||||
}
|
||||
}
|
||||
|
||||
SerializableData data = new SerializableData();
|
||||
SerializableData data = new SerializableDataImpl();
|
||||
while (true) {
|
||||
// Get the class index
|
||||
final short typeIndex = reader.readShort();
|
||||
|
@ -5,6 +5,7 @@ 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.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
@ -152,7 +153,7 @@ public class StorageLocation {
|
||||
if (bytes != null) {
|
||||
data = DataReader.readIndexedData(new BinaryReader(bytes));
|
||||
} else {
|
||||
data = new SerializableData();
|
||||
data = new SerializableDataImpl();
|
||||
}
|
||||
|
||||
dataContainer.setData(data);
|
||||
@ -183,7 +184,7 @@ public class StorageLocation {
|
||||
if (bytes != null) {
|
||||
data = DataReader.readIndexedData(new BinaryReader(bytes));
|
||||
} else {
|
||||
data = new SerializableData();
|
||||
data = new SerializableDataImpl();
|
||||
}
|
||||
|
||||
dataContainer.setData(data);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package loottables;
|
||||
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.DataImpl;
|
||||
import net.minestom.server.gamedata.conditions.SurvivesExplosionCondition;
|
||||
import net.minestom.server.gamedata.loottables.LootTable;
|
||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||
@ -94,7 +95,7 @@ public class TestLootTables {
|
||||
@Test
|
||||
public void simpleGenerate() throws FileNotFoundException {
|
||||
LootTable lootTable = tableManager.load(NamespaceID.from("blocks/acacia_button"));
|
||||
Data arguments = new Data();
|
||||
Data arguments = new DataImpl();
|
||||
List<ItemStack> stacks = lootTable.generate(arguments);
|
||||
Assertions.assertEquals(1, stacks.size());
|
||||
Assertions.assertEquals(Material.ACACIA_BUTTON, stacks.get(0).getMaterial());
|
||||
@ -103,7 +104,7 @@ public class TestLootTables {
|
||||
@Test
|
||||
public void testExplosion() throws FileNotFoundException {
|
||||
LootTable lootTable = tableManager.load(NamespaceID.from("blocks/acacia_button"));
|
||||
Data arguments = new Data();
|
||||
Data arguments = new DataImpl();
|
||||
// negative value will force the condition to fail
|
||||
arguments.set("explosionPower", -1.0, Double.class);
|
||||
List<ItemStack> stacks = lootTable.generate(arguments);
|
||||
|
Loading…
Reference in New Issue
Block a user