mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-20 15:11:22 +01:00
SerializableData data types can now be indexed
This commit is contained in:
parent
daf835dd53
commit
38dbaecb8f
@ -30,12 +30,13 @@ import net.minestom.server.item.metadata.MapMeta;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.scoreboard.Sidebar;
|
||||
import net.minestom.server.storage.StorageFolder;
|
||||
import net.minestom.server.storage.StorageOptions;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -47,11 +48,11 @@ public class PlayerInit {
|
||||
private static volatile Inventory inventory;
|
||||
|
||||
static {
|
||||
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("instance_data", new StorageOptions().setCompression(true));
|
||||
StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("instance_data", new StorageOptions().setCompression(true));
|
||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();
|
||||
//instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(storageFolder);
|
||||
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD);
|
||||
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(storageFolder);
|
||||
//instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD);
|
||||
instanceContainer.enableAutoChunkLoad(true);
|
||||
//instanceContainer.setChunkDecider((x,y) -> (pos) -> pos.getY()>40?(short)0:(short)1);
|
||||
instanceContainer.setChunkGenerator(noiseTestGenerator);
|
||||
|
@ -69,7 +69,7 @@ public class SimpleCommand implements CommandProcessor {
|
||||
|
||||
System.gc();
|
||||
|
||||
//player.getInstance().saveChunksToStorageFolder(() -> System.out.println("end save"));
|
||||
player.getInstance().saveChunksToStorageFolder(() -> System.out.println("end save"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package fr.themode.demo.generator;
|
||||
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.instance.Chunk;
|
||||
import net.minestom.server.instance.ChunkGenerator;
|
||||
import net.minestom.server.instance.ChunkPopulator;
|
||||
@ -11,168 +12,174 @@ import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class NoiseTestGenerator extends ChunkGenerator {
|
||||
|
||||
private Random random = new Random();
|
||||
private JNoise jNoise = JNoise.newBuilder().perlin().setInterpolation(InterpolationType.LINEAR).setSeed(random.nextInt()).setFrequency(0.4).build();
|
||||
private JNoise jNoise2 = JNoise.newBuilder().perlin().setInterpolation(InterpolationType.LINEAR).setSeed(random.nextInt()).setFrequency(0.6).build();
|
||||
private TreePopulator treeGen = new TreePopulator();
|
||||
private Random random = new Random();
|
||||
private JNoise jNoise = JNoise.newBuilder().perlin().setInterpolation(InterpolationType.LINEAR).setSeed(random.nextInt()).setFrequency(0.4).build();
|
||||
private JNoise jNoise2 = JNoise.newBuilder().perlin().setInterpolation(InterpolationType.LINEAR).setSeed(random.nextInt()).setFrequency(0.6).build();
|
||||
private TreePopulator treeGen = new TreePopulator();
|
||||
|
||||
public int getHeight(int x, int z) {
|
||||
double preHeight = jNoise.getNoise(x / 16.0, z / 16.0);
|
||||
return (int) ((preHeight > 0 ? preHeight * 6 : preHeight * 4) + 64);
|
||||
}
|
||||
public int getHeight(int x, int z) {
|
||||
double preHeight = jNoise.getNoise(x / 16.0, z / 16.0);
|
||||
return (int) ((preHeight > 0 ? preHeight * 6 : preHeight * 4) + 64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
|
||||
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
|
||||
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
|
||||
int height = getHeight(x + chunkX * 16, z + chunkZ * 16);
|
||||
for (int y = 0; y < height; y++) {
|
||||
//if (random.nextInt(100) > 10) {
|
||||
// batch.setBlock(x, y, z, Block.DIAMOND_BLOCK);
|
||||
//} else {
|
||||
// batch.setBlock(x, y, z, Block.GOLD_BLOCK);
|
||||
//}
|
||||
if (y == 0) {
|
||||
batch.setBlock(x, y, z, Block.BEDROCK);
|
||||
} else if (y == height-1) {
|
||||
batch.setBlock(x, y, z, Block.GRASS_BLOCK);
|
||||
} else if (y > height-7) {
|
||||
batch.setBlock(x, y, z, Block.DIRT);
|
||||
} else {
|
||||
batch.setBlock(x, y, z, Block.STONE);
|
||||
}
|
||||
}
|
||||
if (height < 61) {
|
||||
batch.setBlock(x, height-1, z, Block.DIRT);
|
||||
for (int y = 0; y < 61 - height; y++) {
|
||||
batch.setBlock(x, y + height, z, Block.WATER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
|
||||
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
|
||||
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
|
||||
final int height = getHeight(x + chunkX * 16, z + chunkZ * 16);
|
||||
for (int y = 0; y < height; y++) {
|
||||
//if (random.nextInt(100) > 10) {
|
||||
// batch.setBlock(x, y, z, Block.DIAMOND_BLOCK);
|
||||
//} else {
|
||||
// batch.setBlock(x, y, z, Block.GOLD_BLOCK);
|
||||
//}
|
||||
if (y == 0) {
|
||||
batch.setBlock(x, y, z, Block.BEDROCK);
|
||||
} else if (y == height - 1) {
|
||||
batch.setBlock(x, y, z, Block.GRASS_BLOCK);
|
||||
} else if (y > height - 7) {
|
||||
// Data for debugging purpose
|
||||
SerializableData serializableData = new SerializableData();
|
||||
serializableData.set("test", 55, Integer.class);
|
||||
batch.setBlockStateId(x, y, z, Block.DIRT.getBlockId(), serializableData);
|
||||
} else {
|
||||
batch.setBlock(x, y, z, Block.STONE);
|
||||
}
|
||||
}
|
||||
if (height < 61) {
|
||||
batch.setBlock(x, height - 1, z, Block.DIRT);
|
||||
for (int y = 0; y < 61 - height; y++) {
|
||||
batch.setBlock(x, y + height, z, Block.WATER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillBiomes(Biome[] biomes, int chunkX, int chunkZ) {
|
||||
Arrays.fill(biomes, MinecraftServer.getBiomeManager().getById(0));
|
||||
}
|
||||
@Override
|
||||
public void fillBiomes(Biome[] biomes, int chunkX, int chunkZ) {
|
||||
Arrays.fill(biomes, MinecraftServer.getBiomeManager().getById(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChunkPopulator> getPopulators() {
|
||||
List<ChunkPopulator> list = new ArrayList<>();
|
||||
list.add(treeGen);
|
||||
return list;
|
||||
}
|
||||
@Override
|
||||
public List<ChunkPopulator> getPopulators() {
|
||||
List<ChunkPopulator> list = new ArrayList<>();
|
||||
list.add(treeGen);
|
||||
return list;
|
||||
}
|
||||
|
||||
private class TreePopulator implements ChunkPopulator {
|
||||
private class TreePopulator implements ChunkPopulator {
|
||||
|
||||
final Structure tree;
|
||||
final Structure tree;
|
||||
|
||||
public TreePopulator() {
|
||||
tree = new Structure();
|
||||
tree.addBlock(Block.DIRT, 0, -1, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 0, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 1, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 2, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 3, 0);
|
||||
public TreePopulator() {
|
||||
tree = new Structure();
|
||||
tree.addBlock(Block.DIRT, 0, -1, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 0, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 1, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 2, 0);
|
||||
tree.addBlock(Block.OAK_LOG, 0, 3, 0);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 0);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, 2);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, -1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 1, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 1, -2);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 0);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, 2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, 2);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, -1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 2, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 2, -2);
|
||||
tree.addBlock(Block.OAK_LEAVES, -2, 2, -2);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, 0);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 3, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 3, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, 1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 3, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 3, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 3, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 3, -1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 4, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 4, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 1, 4, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, 0);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 4, 0);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, 1);
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, 1);
|
||||
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 4, -1);
|
||||
}
|
||||
tree.addBlock(Block.OAK_LEAVES, 0, 4, -1);
|
||||
tree.addBlock(Block.OAK_LEAVES, -1, 4, -1);
|
||||
}
|
||||
|
||||
//todo improve
|
||||
@Override
|
||||
public void populateChunk(ChunkBatch batch, Chunk chunk) {
|
||||
for (int i = -2; i < 18; i++) {
|
||||
for (int j = -2; j < 18; j++) {
|
||||
if (jNoise2.getNoise(i + chunk.getChunkX() * 16, j + chunk.getChunkZ() * 16) > 0.75) {
|
||||
//todo improve
|
||||
@Override
|
||||
public void populateChunk(ChunkBatch batch, Chunk chunk) {
|
||||
for (int i = -2; i < 18; i++) {
|
||||
for (int j = -2; j < 18; j++) {
|
||||
if (jNoise2.getNoise(i + chunk.getChunkX() * 16, j + chunk.getChunkZ() * 16) > 0.75) {
|
||||
int y = getHeight(i + chunk.getChunkX() * 16, j + chunk.getChunkZ() * 16);
|
||||
tree.build(batch, new BlockPosition(i, y, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
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 class SerializableData extends Data {
|
||||
@ -44,32 +51,105 @@ public class SerializableData extends Data {
|
||||
/**
|
||||
* Serialize the data into an array of bytes
|
||||
* <p>
|
||||
* Use {@link net.minestom.server.reader.DataReader#readData(byte[])}
|
||||
* to convert it back
|
||||
* Use {@link DataReader#readIndexedData(BinaryReader)} if {@code indexed} is true,
|
||||
* {@link DataReader#readData(Object2ShortMap, BinaryReader)} 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.
|
||||
* The map is not thread-safe
|
||||
* @param indexed true to add the types index in the header
|
||||
* @return the array representation of this data object
|
||||
*/
|
||||
public byte[] getSerializedData() {
|
||||
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();
|
||||
|
||||
data.forEach((key, value) -> {
|
||||
final Class type = dataType.get(key);
|
||||
final DataType dataType = DATA_MANAGER.getDataType(type);
|
||||
final short typeIndex;
|
||||
{
|
||||
// Find the type name
|
||||
final String encodedType = PrimitiveConversion.getObjectClassString(type.getName()); // Data type (fix for primitives)
|
||||
|
||||
// Write the data type
|
||||
final String encodedType = PrimitiveConversion.getObjectClassString(type.getName()); // Data type (fix for primitives)
|
||||
binaryWriter.writeSizedString(encodedType);
|
||||
// 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.writeVarInt(0); // End of data object
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the data into an array of bytes
|
||||
* <p>
|
||||
* Use {@link net.minestom.server.reader.DataReader#readIndexedData(BinaryReader)}
|
||||
* to convert it back to a {@link SerializableData}
|
||||
* <p>
|
||||
* This will create a type index map which will be present in the header
|
||||
*
|
||||
* @return the array representation of this data object
|
||||
*/
|
||||
public byte[] getIndexedSerializedData() {
|
||||
return getSerializedData(new Object2ShortOpenHashMap<>(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index info (class name -> class index)
|
||||
* <p>
|
||||
* Sized by a var-int
|
||||
*
|
||||
* @param typeToIndexMap the data index map
|
||||
*/
|
||||
public static void writeDataIndexHeader(BinaryWriter indexWriter, Object2ShortMap<String> typeToIndexMap) {
|
||||
// Write the size of the following index list (class name-> class index)
|
||||
indexWriter.writeVarInt(typeToIndexMap.size());
|
||||
|
||||
for (Object2ShortMap.Entry<String> entry : typeToIndexMap.object2ShortEntrySet()) {
|
||||
final String className = entry.getKey();
|
||||
final short classIndex = entry.getShortValue();
|
||||
|
||||
// Write className -> class index
|
||||
indexWriter.writeSizedString(className);
|
||||
indexWriter.writeShort(classIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ public class SerializableDataData extends DataType<SerializableData> {
|
||||
|
||||
@Override
|
||||
public void encode(BinaryWriter writer, SerializableData value) {
|
||||
writer.writeBytes(value.getSerializedData());
|
||||
writer.writeBytes(value.getIndexedSerializedData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializableData decode(BinaryReader reader) {
|
||||
return DataReader.readData(reader);
|
||||
return DataReader.readIndexedData(reader);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
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.entity.pathfinding.PFBlockDescription;
|
||||
@ -145,6 +149,10 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
@Override
|
||||
protected byte[] getSerializedData() {
|
||||
|
||||
// Used for blocks data
|
||||
Object2ShortMap<String> typeToIndexMap = new Object2ShortOpenHashMap<>();
|
||||
|
||||
BinaryWriter binaryWriter = new BinaryWriter();
|
||||
|
||||
// Write the biomes id
|
||||
@ -179,13 +187,28 @@ public class DynamicChunk extends Chunk {
|
||||
final boolean hasData = data instanceof SerializableData;
|
||||
binaryWriter.writeBoolean(hasData);
|
||||
if (hasData) {
|
||||
final byte[] serializedData = ((SerializableData) data).getSerializedData();
|
||||
// Get the un-indexed data
|
||||
final byte[] serializedData = ((SerializableData) data).getSerializedData(typeToIndexMap, false);
|
||||
binaryWriter.writeBytes(serializedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the chunk data contains SerializableData type, it needs to be added in the header
|
||||
BinaryWriter indexWriter = new BinaryWriter();
|
||||
final boolean hasIndex = !typeToIndexMap.isEmpty();
|
||||
indexWriter.writeBoolean(hasIndex);
|
||||
if (hasIndex) {
|
||||
// Get the index buffer (prefixed by true to say that the chunk contains data indexes)
|
||||
SerializableData.writeDataIndexHeader(indexWriter, typeToIndexMap);
|
||||
}
|
||||
|
||||
// Create the final buffer (data index buffer followed by the chunk buffer)
|
||||
final ByteBuf finalBuffer = Unpooled.wrappedBuffer(indexWriter.getBuffer(), binaryWriter.getBuffer());
|
||||
// Change the main writer buffer
|
||||
binaryWriter.setBuffer(finalBuffer);
|
||||
|
||||
return binaryWriter.toByteArray();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
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;
|
||||
@ -19,9 +20,17 @@ public class ChunkReader {
|
||||
public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, Consumer<Chunk> callback) {
|
||||
BinaryReader binaryReader = new BinaryReader(b);
|
||||
|
||||
// Used for blocks data
|
||||
Object2ShortMap<String> typeToIndexMap = null;
|
||||
|
||||
ChunkBatch chunkBatch = null;
|
||||
try {
|
||||
|
||||
final boolean hasIndex = binaryReader.readBoolean();
|
||||
if (hasIndex) {
|
||||
typeToIndexMap = DataReader.readDataIndexes(binaryReader);
|
||||
}
|
||||
|
||||
Biome[] biomes = new Biome[Chunk.BIOME_COUNT];
|
||||
for (int i = 0; i < biomes.length; i++) {
|
||||
final byte id = binaryReader.readByte();
|
||||
@ -48,7 +57,8 @@ public class ChunkReader {
|
||||
final boolean hasData = binaryReader.readBoolean();
|
||||
// Data deserializer
|
||||
if (hasData) {
|
||||
data = DataReader.readData(binaryReader);
|
||||
// Read the data with the deserialized index map
|
||||
data = DataReader.readData(typeToIndexMap, binaryReader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
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.utils.binary.BinaryReader;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Class used to convert an array of bytes to a {@link SerializableData}
|
||||
* <p>
|
||||
@ -14,60 +20,93 @@ 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}
|
||||
* 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 reader the reader
|
||||
* @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(BinaryReader reader) {
|
||||
SerializableData data = new SerializableData();
|
||||
try {
|
||||
while (true) {
|
||||
final int typeLength = reader.readVarInt();
|
||||
|
||||
if (typeLength == 0) {
|
||||
// End of data
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the class type
|
||||
final Class type;
|
||||
{
|
||||
final byte[] typeCache = reader.readBytes(typeLength);
|
||||
|
||||
final String className = new String(typeCache);
|
||||
|
||||
type = Class.forName(className);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
SerializableData data = new SerializableData();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a bytes array to a {@link SerializableData}
|
||||
* Read the indexes of the data + the data
|
||||
*
|
||||
* @param data the data
|
||||
* @return a {@link SerializableData} based on the data input
|
||||
* @see #readData(BinaryReader)
|
||||
* @param reader the reader
|
||||
* @return the deserialized {@link SerializableData}
|
||||
*/
|
||||
public static SerializableData readData(byte[] data) {
|
||||
return readData(new BinaryReader(data));
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public class StorageFolder {
|
||||
SerializableData data;
|
||||
|
||||
if (bytes != null) {
|
||||
data = DataReader.readData(new BinaryReader(bytes));
|
||||
data = DataReader.readIndexedData(new BinaryReader(bytes));
|
||||
} else {
|
||||
data = new SerializableData();
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class StorageFolder {
|
||||
SerializableData data;
|
||||
|
||||
if (bytes != null) {
|
||||
data = DataReader.readData(new BinaryReader(bytes));
|
||||
data = DataReader.readIndexedData(new BinaryReader(bytes));
|
||||
} else {
|
||||
data = new SerializableData();
|
||||
}
|
||||
@ -153,7 +153,7 @@ public class StorageFolder {
|
||||
return;
|
||||
|
||||
// Save the data
|
||||
set(key, serializableData.getSerializedData());
|
||||
set(key, serializableData.getIndexedSerializedData());
|
||||
|
||||
// Remove from map
|
||||
this.cachedData.remove(key);
|
||||
@ -166,7 +166,7 @@ public class StorageFolder {
|
||||
public void saveCachedData() {
|
||||
synchronized (cachedData) {
|
||||
cachedData.forEach((key, data) -> {
|
||||
set(key, data.getSerializedData());
|
||||
set(key, data.getIndexedSerializedData());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -179,7 +179,7 @@ public class StorageFolder {
|
||||
public void saveCachedData(String key) {
|
||||
synchronized (cachedData) {
|
||||
final SerializableData data = cachedData.get(key);
|
||||
set(key, data.getSerializedData());
|
||||
set(key, data.getIndexedSerializedData());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public class BinaryWriter extends OutputStream {
|
||||
|
||||
private final ByteBuf buffer;
|
||||
private ByteBuf buffer;
|
||||
private final NBTWriter nbtWriter = new NBTWriter(this, false);
|
||||
|
||||
/**
|
||||
@ -261,6 +261,15 @@ public class BinaryWriter extends OutputStream {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the buffer used by this binary writer
|
||||
*
|
||||
* @param buffer the new buffer used by this binary writer
|
||||
*/
|
||||
public void setBuffer(ByteBuf buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
writeByte((byte) b);
|
||||
|
Loading…
Reference in New Issue
Block a user