WIP per block data

This commit is contained in:
TheMode 2019-09-15 13:42:36 +02:00
parent be6cdf8e72
commit 972ed294d3
19 changed files with 341 additions and 149 deletions

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.data;
import fr.themode.minestom.Main;
import fr.themode.minestom.utils.PrimitiveConversion;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@ -10,13 +11,14 @@ import java.util.concurrent.ConcurrentHashMap;
public class Data {
private DataManager dataManager = Main.getDataManager();
private static final DataManager DATA_MANAGER = Main.getDataManager();
// TODO replace maps for something more memory-friendly
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
public <T> void set(String key, T value, Class<T> type) {
if (dataManager.getDataType(type) == null) {
if (DATA_MANAGER.getDataType(type) == null) {
throw new UnsupportedOperationException("Type " + type.getName() + " hasn't been registered in DataManager#registerType");
}
this.data.put(key, value);
@ -41,7 +43,7 @@ public class Data {
Object value = entry.getValue();
DataType dataType = Main.getDataManager().getDataType(type);
byte[] encodedType = type.getName().getBytes(); // Data type
byte[] encodedType = PrimitiveConversion.getObjectClassString(type.getName()).getBytes(); // Data type (fix for primitives)
dos.writeShort(encodedType.length);
dos.write(encodedType);

View File

@ -1,10 +1,13 @@
package fr.themode.minestom.data;
import fr.themode.minestom.Main;
import fr.themode.minestom.io.DataReader;
import fr.themode.minestom.io.IOManager;
import fr.themode.minestom.utils.CompressionUtils;
import java.io.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Consumer;
@ -58,46 +61,7 @@ public interface DataContainer {
return;
}
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(CompressionUtils.getDecompressedData(array)));
Data data = new Data();
try {
while (true) {
short typeLength = stream.readShort();
if (typeLength == 0xff) {
// End of data
break;
}
byte[] typeCache = new byte[typeLength];
for (int i = 0; i < typeLength; i++) {
typeCache[i] = stream.readByte();
}
short nameLength = stream.readShort();
byte[] nameCache = new byte[nameLength];
for (int i = 0; i < nameLength; i++) {
nameCache[i] = stream.readByte();
}
int valueLength = stream.readInt();
byte[] valueCache = new byte[valueLength];
for (int i = 0; i < valueLength; i++) {
valueCache[i] = stream.readByte();
}
Class type = Class.forName(new String(typeCache));
String name = new String(nameCache);
Object value = Main.getDataManager().getDataType(type).decode(valueCache);
data.set(name, value, type);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Data data = DataReader.readData(array, true);
setData(data);
if (callback != null)

View File

@ -6,6 +6,7 @@ import fr.themode.minestom.Main;
import fr.themode.minestom.bossbar.BossBar;
import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.collision.BoundingBox;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.property.Attribute;
import fr.themode.minestom.event.*;
import fr.themode.minestom.instance.Chunk;
@ -24,6 +25,7 @@ import fr.themode.minestom.utils.*;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
import java.io.File;
import java.util.Collections;
import java.util.Random;
import java.util.Set;
@ -51,8 +53,8 @@ public class Player extends LivingEntity {
static {
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
//instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data"));
instanceContainer = Main.getInstanceManager().createInstanceContainer();
instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data"));
//instanceContainer = Main.getInstanceManager().createInstanceContainer();
instanceContainer.enableAutoChunkLoad(true);
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
int loopStart = -2;
@ -133,6 +135,20 @@ public class Player extends LivingEntity {
if (player != this)
player.teleport(getPosition());
}
getInstance().saveToFolder(() -> {
sendMessage("SAVED");
});
});
setEventCallback(PlayerStartDiggingEvent.class, event -> {
BlockPosition blockPosition = event.getBlockPosition();
Data data = getInstance().getBlockData(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
if (data == null) {
sendMessage("DATA NULL");
return;
}
sendMessage("BLOCK DATA: " + data.get("x"));
});
setEventCallback(PickupItemEvent.class, event -> {

View File

@ -1,15 +1,22 @@
package fr.themode.minestom.event;
import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.utils.BlockPosition;
public class PlayerStartDiggingEvent extends CancellableEvent {
private BlockPosition blockPosition;
private CustomBlock customBlock;
public PlayerStartDiggingEvent(CustomBlock customBlock) {
public PlayerStartDiggingEvent(BlockPosition blockPosition, CustomBlock customBlock) {
this.blockPosition = blockPosition;
this.customBlock = customBlock;
}
public BlockPosition getBlockPosition() {
return blockPosition;
}
public CustomBlock getBlock() {
return customBlock;
}

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.instance;
import fr.themode.minestom.Main;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.instance.block.BlockManager;
import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.utils.BlockPosition;
@ -10,9 +11,17 @@ public interface BlockModifier {
BlockManager BLOCK_MANAGER = Main.getBlockManager();
void setBlock(int x, int y, int z, short blockId);
void setBlock(int x, int y, int z, short blockId, Data data);
void setCustomBlock(int x, int y, int z, short blockId);
void setCustomBlock(int x, int y, int z, short blockId, Data data);
default void setBlock(int x, int y, int z, short blockId) {
setBlock(x, y, z, blockId, null);
}
default void setCustomBlock(int x, int y, int z, short blockId) {
setCustomBlock(x, y, z, blockId, null);
}
default void setBlock(BlockPosition blockPosition, short blockId) {
setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockId);
@ -22,9 +31,13 @@ public interface BlockModifier {
setBlock(position.toBlockPosition(), blockId);
}
default void setCustomBlock(int x, int y, int z, String blockId) {
default void setCustomBlock(int x, int y, int z, String blockId, Data data) {
CustomBlock customBlock = BLOCK_MANAGER.getBlock(blockId);
setCustomBlock(x, y, z, customBlock.getId());
setCustomBlock(x, y, z, customBlock.getId(), data);
}
default void setCustomBlock(int x, int y, int z, String blockId) {
setCustomBlock(x, y, z, blockId, null);
}
default void setCustomBlock(BlockPosition blockPosition, String blockId) {

View File

@ -12,6 +12,8 @@ import fr.themode.minestom.utils.PacketUtils;
import fr.themode.minestom.utils.SerializerUtils;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@ -31,6 +33,16 @@ public class Chunk implements Viewable {
private Biome biome;
private int chunkX, chunkZ;
// Int represent the chunk coord of the block
// value is: 2 bytes -> blockId | 2 bytes -> customBlockId (filled with 0 if isn't)
private Int2IntMap blocks = new Int2IntOpenHashMap(16 * 16 * 16); // Start with the size of a full chunk section
// Used to get all blocks with data (no null)
// Key is still chunk coord
// TODO shouldn't take Data object (too much memory overhead)
private Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>(16 * 16); // Start with the size of a single row
protected volatile boolean packetUpdated;
// Block entities
@ -41,9 +53,6 @@ public class Chunk implements Viewable {
// Cache
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private Packet fullDataPacket;
// Int represent the chunk coord of the block
// value is: 2 bytes -> blockId | 2 bytes -> customBlockId (filled with 0 if isn't)
private Int2IntMap blocks = new Int2IntOpenHashMap(16 * 16 * 16); // Start with the size of a full chunk section
public Chunk(Biome biome, int chunkX, int chunkZ) {
this.biome = biome;
@ -51,19 +60,35 @@ public class Chunk implements Viewable {
this.chunkZ = chunkZ;
}
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId) {
setBlock(x, y, z, blockId, (short) 0);
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId, Data data) {
setBlock(x, y, z, blockId, (short) 0, data);
}
public void UNSAFE_setCustomBlock(byte x, byte y, byte z, short customBlockId) {
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId) {
UNSAFE_setBlock(x, y, z, blockId, null);
}
public void UNSAFE_setCustomBlock(byte x, byte y, byte z, short customBlockId, Data data) {
CustomBlock customBlock = BLOCK_MANAGER.getBlock(customBlockId);
if (customBlock == null)
throw new IllegalArgumentException("The custom block " + customBlockId + " does not exist or isn't registered");
setCustomBlock(x, y, z, customBlock);
setCustomBlock(x, y, z, customBlock, data);
}
private void setBlock(byte x, byte y, byte z, short blockType, short customId) {
public void UNSAFE_setCustomBlock(byte x, byte y, byte z, short customBlockId) {
UNSAFE_setCustomBlock(x, y, z, customBlockId, null);
}
private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock, Data data) {
if (customBlock.hasUpdate()) {
Consumer<Data> test = customBlock::update;
// TODO add update callback
}
setBlock(x, y, z, customBlock.getType(), customBlock.getId(), data);
}
private void setBlock(byte x, byte y, byte z, short blockType, short customId, Data data) {
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
if (blockType != 0 || customId != 0) {
int value = (blockType << 16 | customId & 0xFFFF);
@ -73,6 +98,13 @@ public class Chunk implements Viewable {
this.blocks.remove(index);
}
// Set the new data (or remove from the map if is null)
if (data != null) {
this.blocksData.put(index, data);
} else {
this.blocksData.remove(index);
}
if (isBlockEntity(blockType)) {
this.blockEntities.add(index);
} else {
@ -82,12 +114,13 @@ public class Chunk implements Viewable {
this.packetUpdated = false;
}
private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock) {
if (customBlock.hasUpdate()) {
Consumer<Data> test = customBlock::update;
// TODO add update callback
public void setBlockData(byte x, byte y, byte z, Data data) {
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
if (data != null) {
this.blocksData.put(index, data);
} else {
this.blocksData.remove(index);
}
setBlock(x, y, z, customBlock.getType(), customBlock.getId());
}
public short getBlockId(byte x, byte y, byte z) {
@ -103,6 +136,11 @@ public class Chunk implements Viewable {
return id != 0 ? BLOCK_MANAGER.getBlock(id) : null;
}
public Data getData(byte x, byte y, byte z) {
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
return blocksData.get(index);
}
public void updateBlocks() {
/**
* TODO blocks' update:
@ -161,9 +199,20 @@ public class Chunk implements Viewable {
boolean isCustomBlock = customBlockId != 0;
short id = isCustomBlock ? customBlockId : blockId;
Data data = blocksData.get(index);
boolean hasData = data != null;
dos.writeInt(index); // Chunk coord
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);
}
}
byte[] result = output.toByteArray();

View File

@ -1,11 +1,13 @@
package fr.themode.minestom.instance;
import fr.themode.minestom.instance.batch.ChunkBatch;
import fr.themode.minestom.io.ChunkReader;
import fr.themode.minestom.io.IOManager;
import fr.themode.minestom.utils.CompressionUtils;
import fr.themode.minestom.utils.SerializerUtils;
import java.io.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Consumer;
@ -53,37 +55,7 @@ public class ChunkLoaderIO {
return;
}
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(CompressionUtils.getDecompressedData(array)));
ChunkBatch chunkBatch = null;
try {
Biome biome = Biome.fromId(stream.readByte());
Chunk chunk = new Chunk(biome, chunkX, chunkZ);
chunkBatch = instance.createChunkBatch(chunk);
while (true) {
// TODO block data
int index = stream.readInt();
boolean isCustomBlock = stream.readBoolean();
short blockId = stream.readShort();
byte[] chunkPos = SerializerUtils.indexToChunkPosition(index);
byte x = chunkPos[0];
byte y = chunkPos[1];
byte z = chunkPos[2];
if (isCustomBlock) {
chunkBatch.setCustomBlock(x, y, z, blockId);
} else {
chunkBatch.setBlock(x, y, z, blockId);
}
}
} catch (EOFException e) {
} catch (IOException e) {
e.printStackTrace();
}
chunkBatch.flush(c -> callback.accept(c)); // Success, null if file isn't properly encoded
ChunkReader.readChunk(array, instance, chunkX, chunkZ, true, callback);
});
}

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.instance;
import com.github.simplenet.packet.Packet;
import fr.themode.minestom.Main;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.*;
import fr.themode.minestom.instance.batch.BlockBatch;
import fr.themode.minestom.instance.batch.ChunkBatch;
@ -147,6 +148,11 @@ public abstract class Instance implements BlockModifier {
return chunk.getCustomBlock((byte) (x % 16), (byte) y, (byte) (z % 16));
}
public Data getBlockData(int x, int y, int z) {
Chunk chunk = getChunkAt(x, z);
return chunk.getData((byte) (x % 16), (byte) y, (byte) (z % 16));
}
public Chunk getChunkAt(double x, double z) {
int chunkX = Math.floorDiv((int) x, 16);
int chunkZ = Math.floorDiv((int) z, 16);

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.instance;
import com.github.simplenet.packet.Packet;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.PlayerBlockBreakEvent;
import fr.themode.minestom.instance.batch.BlockBatch;
@ -37,25 +38,25 @@ public class InstanceContainer extends Instance {
}
@Override
public synchronized void setBlock(int x, int y, int z, short blockId) {
public synchronized void setBlock(int x, int y, int z, short blockId, Data data) {
Chunk chunk = getChunkAt(x, z);
synchronized (chunk) {
byte chunkX = (byte) (x % 16);
byte chunkY = (byte) y;
byte chunkZ = (byte) (z % 16);
chunk.UNSAFE_setBlock(chunkX, chunkY, chunkZ, blockId);
chunk.UNSAFE_setBlock(chunkX, chunkY, chunkZ, blockId, data);
sendBlockChange(chunk, x, y, z, blockId);
}
}
@Override
public synchronized void setCustomBlock(int x, int y, int z, short blockId) {
public synchronized void setCustomBlock(int x, int y, int z, short blockId, Data data) {
Chunk chunk = getChunkAt(x, z);
synchronized (chunk) {
byte chunkX = (byte) (x % 16);
byte chunkY = (byte) y;
byte chunkZ = (byte) (z % 16);
chunk.UNSAFE_setCustomBlock(chunkX, chunkY, chunkZ, blockId);
chunk.UNSAFE_setCustomBlock(chunkX, chunkY, chunkZ, blockId, data);
short id = BLOCK_MANAGER.getBlock(blockId).getType();
sendBlockChange(chunk, x, y, z, id);
}

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.instance;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.instance.batch.BlockBatch;
import fr.themode.minestom.instance.batch.ChunkBatch;
@ -118,13 +119,13 @@ public class SharedInstance extends Instance {
}
@Override
public void setBlock(int x, int y, int z, short blockId) {
instanceContainer.setBlock(x, y, z, blockId);
public void setBlock(int x, int y, int z, short blockId, Data data) {
instanceContainer.setBlock(x, y, z, blockId, data);
}
@Override
public void setCustomBlock(int x, int y, int z, short blockId) {
instanceContainer.setBlock(x, y, z, blockId);
public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
instanceContainer.setBlock(x, y, z, blockId, data);
}
public InstanceContainer getContainer() {

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.instance.batch;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.instance.BlockModifier;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.InstanceContainer;
@ -20,36 +21,38 @@ public class BlockBatch implements IBatch, BlockModifier {
}
@Override
public synchronized void setBlock(int x, int y, int z, short blockId) {
public synchronized void setBlock(int x, int y, int z, short blockId, Data data) {
Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blockData = this.data.getOrDefault(chunk, new ArrayList<>());
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>());
BlockData data = new BlockData();
data.x = x % 16;
data.y = y;
data.z = z % 16;
data.blockId = blockId;
BlockData blockData = new BlockData();
blockData.x = x % 16;
blockData.y = y;
blockData.z = z % 16;
blockData.blockId = blockId;
blockData.data = data;
blockData.add(data);
blocksData.add(blockData);
this.data.put(chunk, blockData);
this.data.put(chunk, blocksData);
}
@Override
public void setCustomBlock(int x, int y, int z, short blockId) {
public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blockData = this.data.getOrDefault(chunk, new ArrayList<>());
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>());
BlockData data = new BlockData();
data.x = x % 16;
data.y = y;
data.z = z % 16;
data.isCustomBlock = true;
data.blockId = blockId;
BlockData blockData = new BlockData();
blockData.x = x % 16;
blockData.y = y;
blockData.z = z % 16;
blockData.isCustomBlock = true;
blockData.blockId = blockId;
blockData.data = data;
blockData.add(data);
blocksData.add(blockData);
this.data.put(chunk, blockData);
this.data.put(chunk, blocksData);
}
public void flush(Runnable callback) {
@ -81,12 +84,13 @@ public class BlockBatch implements IBatch, BlockModifier {
private int x, y, z;
private boolean isCustomBlock;
private short blockId;
private Data data;
public void apply(Chunk chunk) {
if (!isCustomBlock) {
chunk.UNSAFE_setBlock((byte) x, (byte) y, (byte) z, blockId);
chunk.UNSAFE_setBlock((byte) x, (byte) y, (byte) z, blockId, data);
} else {
chunk.UNSAFE_setCustomBlock((byte) x, (byte) y, (byte) z, blockId);
chunk.UNSAFE_setCustomBlock((byte) x, (byte) y, (byte) z, blockId, data);
}
}

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.instance.batch;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.instance.BlockModifier;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.ChunkGenerator;
@ -25,27 +26,29 @@ public class ChunkBatch implements IBatch, BlockModifier {
}
@Override
public void setBlock(int x, int y, int z, short blockId) {
BlockData data = new BlockData();
data.x = (byte) x;
data.y = (byte) y;
data.z = (byte) z;
data.isCustomBlock = false;
data.blockId = blockId;
public void setBlock(int x, int y, int z, short blockId, Data data) {
BlockData blockData = new BlockData();
blockData.x = (byte) x;
blockData.y = (byte) y;
blockData.z = (byte) z;
blockData.isCustomBlock = false;
blockData.blockId = blockId;
blockData.data = data;
this.dataList.add(data);
this.dataList.add(blockData);
}
@Override
public void setCustomBlock(int x, int y, int z, short blockId) {
BlockData data = new BlockData();
data.x = (byte) x;
data.y = (byte) y;
data.z = (byte) z;
data.isCustomBlock = true;
data.blockId = blockId;
public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
BlockData blockData = new BlockData();
blockData.x = (byte) x;
blockData.y = (byte) y;
blockData.z = (byte) z;
blockData.isCustomBlock = true;
blockData.blockId = blockId;
blockData.data = data;
this.dataList.add(data);
this.dataList.add(blockData);
}
public void flushChunkGenerator(ChunkGenerator chunkGenerator, Consumer<Chunk> callback) {
@ -79,12 +82,13 @@ public class ChunkBatch implements IBatch, BlockModifier {
private byte x, y, z;
private boolean isCustomBlock;
private short blockId;
private Data data;
public void apply(Chunk chunk) {
if (!isCustomBlock) {
chunk.UNSAFE_setBlock(x, y, z, blockId);
chunk.UNSAFE_setBlock(x, y, z, blockId, data);
} else {
chunk.UNSAFE_setCustomBlock(x, y, z, blockId);
chunk.UNSAFE_setCustomBlock(x, y, z, blockId, data);
}
}

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.instance.demo;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.instance.Biome;
import fr.themode.minestom.instance.ChunkGenerator;
import fr.themode.minestom.instance.batch.ChunkBatch;
@ -15,7 +16,9 @@ public class ChunkGeneratorDemo extends ChunkGenerator {
for (byte x = 0; x < 16; x++)
for (byte z = 0; z < 16; z++) {
for (byte y = 0; y < 65; y++) {
batch.setCustomBlock(x, y, z, "custom_block");
Data data = new Data();
data.set("x", (int) x, int.class);
batch.setCustomBlock(x, y, z, "custom_block", data);
}
}
}

View File

@ -0,0 +1,65 @@
package fr.themode.minestom.io;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.instance.Biome;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.instance.batch.ChunkBatch;
import fr.themode.minestom.utils.CompressionUtils;
import fr.themode.minestom.utils.SerializerUtils;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.function.Consumer;
public class ChunkReader {
public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, boolean shouldDecompress, Consumer<Chunk> callback) {
b = shouldDecompress ? CompressionUtils.getDecompressedData(b) : b;
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(b));
ChunkBatch chunkBatch = null;
try {
Biome biome = Biome.fromId(stream.readByte());
Chunk chunk = new Chunk(biome, chunkX, chunkZ);
chunkBatch = instance.createChunkBatch(chunk);
while (true) {
// TODO block data
int index = stream.readInt();
boolean isCustomBlock = stream.readBoolean();
short blockId = stream.readShort();
boolean hasData = stream.readBoolean();
Data data = null;
// Data deserializer
if (hasData) {
int dataLength = stream.readInt();
byte[] dataArray = stream.readNBytes(dataLength);
data = DataReader.readData(dataArray, false);
}
byte[] chunkPos = SerializerUtils.indexToChunkPosition(index);
byte x = chunkPos[0];
byte y = chunkPos[1];
byte z = chunkPos[2];
if (isCustomBlock) {
chunkBatch.setCustomBlock(x, y, z, blockId, data);
} else {
chunkBatch.setBlock(x, y, z, blockId, data);
}
}
} catch (EOFException e) {
} catch (IOException e) {
e.printStackTrace();
}
chunkBatch.flush(c -> callback.accept(c)); // Success, null if file isn't properly encoded
}
}

View File

@ -0,0 +1,61 @@
package fr.themode.minestom.io;
import fr.themode.minestom.Main;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.utils.CompressionUtils;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class DataReader {
public static Data readData(byte[] b, boolean shouldDecompress) {
b = shouldDecompress ? CompressionUtils.getDecompressedData(b) : b;
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(b));
Data data = new Data();
try {
while (true) {
short typeLength = stream.readShort();
if (typeLength == 0xff) {
// End of data
break;
}
byte[] typeCache = new byte[typeLength];
for (int i = 0; i < typeLength; i++) {
typeCache[i] = stream.readByte();
}
short nameLength = stream.readShort();
byte[] nameCache = new byte[nameLength];
for (int i = 0; i < nameLength; i++) {
nameCache[i] = stream.readByte();
}
int valueLength = stream.readInt();
byte[] valueCache = new byte[valueLength];
for (int i = 0; i < valueLength; i++) {
valueCache[i] = stream.readByte();
}
Class type = Class.forName(new String(typeCache));
String name = new String(nameCache);
Object value = Main.getDataManager().getDataType(type).decode(valueCache);
data.set(name, value, type);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return data;
}
}

View File

@ -32,7 +32,7 @@ public class PlayerDiggingListener {
if (instance != null) {
CustomBlock customBlock = instance.getCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
if (customBlock != null) {
PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(customBlock);
PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(blockPosition, customBlock);
player.callEvent(PlayerStartDiggingEvent.class, playerStartDiggingEvent);
if (!playerStartDiggingEvent.isCancelled()) {
player.refreshTargetBlock(customBlock, blockPosition);

View File

@ -41,7 +41,11 @@ public class ChunkDataPacket implements ServerPacket {
if (section != null) { // section contains at least one block
mask |= 1 << i;
Utils.writeBlocks(blocks, section, BITS_PER_ENTRY);
} else {
mask |= 0 << i;
}
} else {
mask |= 0 << i;
}
}

View File

@ -140,7 +140,7 @@ public class Position {
}
public BlockPosition toBlockPosition() {
return new BlockPosition((int) Math.ceil(getX()), (int) Math.ceil(getY()), (int) Math.ceil(getZ()));
return new BlockPosition((int) Math.ceil(x), (int) Math.ceil(y), (int) Math.ceil(z));
}
@Override

View File

@ -22,4 +22,24 @@ public class PrimitiveConversion {
return clazz;
}
public static String getObjectClassString(String clazz) {
if (clazz == "boolean")
return "java.lang.Boolean";
if (clazz == "byte")
return "java.lang.Byte";
if (clazz == "char")
return "java.lang.Character";
if (clazz == "short")
return "java.lang.Short";
if (clazz == "int")
return "java.lang.Integer";
if (clazz == "long")
return "java.lang.Long";
if (clazz == "float")
return "java.lang.Float";
if (clazz == "double")
return "java.lang.Double";
return clazz;
}
}