mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-28 12:07:42 +01:00
WIP blocks update
This commit is contained in:
parent
972ed294d3
commit
d833963414
@ -13,7 +13,7 @@ public class Data {
|
|||||||
|
|
||||||
private static final DataManager DATA_MANAGER = Main.getDataManager();
|
private static final DataManager DATA_MANAGER = Main.getDataManager();
|
||||||
|
|
||||||
// TODO replace maps for something more memory-friendly
|
// TODO replace maps to something more memory-friendly
|
||||||
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
|
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
|
||||||
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
|
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ import fr.themode.minestom.utils.*;
|
|||||||
import fr.themode.minestom.world.Dimension;
|
import fr.themode.minestom.world.Dimension;
|
||||||
import fr.themode.minestom.world.LevelType;
|
import fr.themode.minestom.world.LevelType;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -53,8 +52,8 @@ public class Player extends LivingEntity {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||||
instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data"));
|
//instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data"));
|
||||||
//instanceContainer = Main.getInstanceManager().createInstanceContainer();
|
instanceContainer = Main.getInstanceManager().createInstanceContainer();
|
||||||
instanceContainer.enableAutoChunkLoad(true);
|
instanceContainer.enableAutoChunkLoad(true);
|
||||||
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
|
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
|
||||||
int loopStart = -2;
|
int loopStart = -2;
|
||||||
@ -135,20 +134,16 @@ public class Player extends LivingEntity {
|
|||||||
if (player != this)
|
if (player != this)
|
||||||
player.teleport(getPosition());
|
player.teleport(getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstance().saveToFolder(() -> {
|
|
||||||
sendMessage("SAVED");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setEventCallback(PlayerStartDiggingEvent.class, event -> {
|
setEventCallback(PlayerStartDiggingEvent.class, event -> {
|
||||||
BlockPosition blockPosition = event.getBlockPosition();
|
BlockPosition blockPosition = event.getBlockPosition();
|
||||||
Data data = getInstance().getBlockData(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
|
Data data = getInstance().getBlockData(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
sendMessage("DATA NULL");
|
sendMessage("DATA IS NULL");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendMessage("BLOCK DATA: " + data.get("x"));
|
sendMessage("BLOCK DATA: " + data.get("value"));
|
||||||
});
|
});
|
||||||
|
|
||||||
setEventCallback(PickupItemEvent.class, event -> {
|
setEventCallback(PickupItemEvent.class, event -> {
|
||||||
|
@ -7,13 +7,12 @@ import fr.themode.minestom.data.Data;
|
|||||||
import fr.themode.minestom.entity.Player;
|
import fr.themode.minestom.entity.Player;
|
||||||
import fr.themode.minestom.instance.block.BlockManager;
|
import fr.themode.minestom.instance.block.BlockManager;
|
||||||
import fr.themode.minestom.instance.block.CustomBlock;
|
import fr.themode.minestom.instance.block.CustomBlock;
|
||||||
|
import fr.themode.minestom.instance.block.UpdateConsumer;
|
||||||
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
|
||||||
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
import fr.themode.minestom.utils.PacketUtils;
|
import fr.themode.minestom.utils.PacketUtils;
|
||||||
import fr.themode.minestom.utils.SerializerUtils;
|
import fr.themode.minestom.utils.SerializerUtils;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
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.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@ -21,7 +20,6 @@ import java.io.IOException;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class Chunk implements Viewable {
|
public class Chunk implements Viewable {
|
||||||
|
|
||||||
@ -43,6 +41,9 @@ public class Chunk implements Viewable {
|
|||||||
// TODO shouldn't take Data object (too much memory overhead)
|
// 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
|
private Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>(16 * 16); // Start with the size of a single row
|
||||||
|
|
||||||
|
// Contains CustomBlocks' index which are updatable
|
||||||
|
private IntSet updatableBlocks = new IntOpenHashSet();
|
||||||
|
|
||||||
protected volatile boolean packetUpdated;
|
protected volatile boolean packetUpdated;
|
||||||
|
|
||||||
// Block entities
|
// Block entities
|
||||||
@ -61,7 +62,7 @@ public class Chunk implements Viewable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId, Data data) {
|
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId, Data data) {
|
||||||
setBlock(x, y, z, blockId, (short) 0, data);
|
setBlock(x, y, z, blockId, (short) 0, data, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId) {
|
public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId) {
|
||||||
@ -81,14 +82,11 @@ public class Chunk implements Viewable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock, Data data) {
|
private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock, Data data) {
|
||||||
if (customBlock.hasUpdate()) {
|
UpdateConsumer updateConsumer = customBlock.hasUpdate() ? customBlock::update : null;
|
||||||
Consumer<Data> test = customBlock::update;
|
setBlock(x, y, z, customBlock.getType(), customBlock.getId(), data, updateConsumer);
|
||||||
// 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) {
|
private void setBlock(byte x, byte y, byte z, short blockType, short customId, Data data, UpdateConsumer updateConsumer) {
|
||||||
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
||||||
if (blockType != 0 || customId != 0) {
|
if (blockType != 0 || customId != 0) {
|
||||||
int value = (blockType << 16 | customId & 0xFFFF);
|
int value = (blockType << 16 | customId & 0xFFFF);
|
||||||
@ -105,6 +103,13 @@ public class Chunk implements Viewable {
|
|||||||
this.blocksData.remove(index);
|
this.blocksData.remove(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set update consumer
|
||||||
|
if (updateConsumer != null) {
|
||||||
|
this.updatableBlocks.add(index);
|
||||||
|
} else {
|
||||||
|
this.updatableBlocks.rem(index);
|
||||||
|
}
|
||||||
|
|
||||||
if (isBlockEntity(blockType)) {
|
if (isBlockEntity(blockType)) {
|
||||||
this.blockEntities.add(index);
|
this.blockEntities.add(index);
|
||||||
} else {
|
} else {
|
||||||
@ -125,31 +130,50 @@ public class Chunk implements Viewable {
|
|||||||
|
|
||||||
public short getBlockId(byte x, byte y, byte z) {
|
public short getBlockId(byte x, byte y, byte z) {
|
||||||
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
||||||
int value = this.blocks.get(index);
|
int value = getBlockValue(index);
|
||||||
return (short) (value >>> 16);
|
return (short) (value >>> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomBlock getCustomBlock(byte x, byte y, byte z) {
|
public CustomBlock getCustomBlock(byte x, byte y, byte z) {
|
||||||
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
||||||
int value = this.blocks.get(index);
|
return getCustomBlock(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomBlock getCustomBlock(int index) {
|
||||||
|
int value = getBlockValue(index);
|
||||||
short id = (short) (value & 0xffff);
|
short id = (short) (value & 0xffff);
|
||||||
return id != 0 ? BLOCK_MANAGER.getBlock(id) : null;
|
return id != 0 ? BLOCK_MANAGER.getBlock(id) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getBlockValue(int index) {
|
||||||
|
return blocks.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
public Data getData(byte x, byte y, byte z) {
|
public Data getData(byte x, byte y, byte z) {
|
||||||
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
int index = SerializerUtils.chunkCoordToIndex(x, y, z);
|
||||||
|
return getData(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Data getData(int index) {
|
||||||
return blocksData.get(index);
|
return blocksData.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBlocks() {
|
public void updateBlocks(long time, Instance instance) {
|
||||||
/**
|
synchronized (this) {
|
||||||
* TODO blocks' update:
|
IntIterator iterator = updatableBlocks.iterator();
|
||||||
* - get all custom blocks
|
while (iterator.hasNext()) {
|
||||||
* - check if they have an update method
|
int index = iterator.nextInt();
|
||||||
* - check if they should be updated
|
byte[] blockPos = SerializerUtils.indexToChunkPosition(index);
|
||||||
* - get custom block's data
|
byte x = blockPos[0];
|
||||||
* - call update method
|
byte y = blockPos[1];
|
||||||
*/
|
byte z = blockPos[2];
|
||||||
|
CustomBlock customBlock = getCustomBlock(x, y, z);
|
||||||
|
BlockPosition blockPosition = new BlockPosition(x * chunkX, y, z * chunkZ);
|
||||||
|
Data data = getData(index);
|
||||||
|
// TODO should customBlock be updated?
|
||||||
|
customBlock.update(instance, blockPosition, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Biome getBiome() {
|
public Biome getBiome() {
|
||||||
|
@ -27,10 +27,12 @@ public class BlockManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
// TODO another thread pool
|
||||||
for (Instance instance : instanceManager.getInstances()) {
|
for (Instance instance : instanceManager.getInstances()) {
|
||||||
// TODO only InstanceContainer?
|
// FIXME: only InstanceContainer?
|
||||||
for (Chunk chunk : instance.getChunks()) {
|
for (Chunk chunk : instance.getChunks()) {
|
||||||
chunk.updateBlocks();
|
chunk.updateBlocks(time, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,14 @@ package fr.themode.minestom.instance.block;
|
|||||||
|
|
||||||
import fr.themode.minestom.data.Data;
|
import fr.themode.minestom.data.Data;
|
||||||
import fr.themode.minestom.entity.Player;
|
import fr.themode.minestom.entity.Player;
|
||||||
|
import fr.themode.minestom.instance.Instance;
|
||||||
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
* - option to set the global as "global breaking" meaning that multiple players mining the same block will break it faster (cumulation)
|
* - option to set the global as "global breaking" meaning that multiple players mining the same block will break it faster (cumulation)
|
||||||
*/
|
*/
|
||||||
public abstract class CustomBlock {
|
public abstract class CustomBlock {
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ public abstract class CustomBlock {
|
|||||||
this.id = (short) idCounter.incrementAndGet();
|
this.id = (short) idCounter.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Data data) {
|
public void update(Instance instance, BlockPosition blockPosition, Data data) {
|
||||||
throw new UnsupportedOperationException("Update method not overriden");
|
throw new UnsupportedOperationException("Update method not overriden");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package fr.themode.minestom.instance.block;
|
||||||
|
|
||||||
|
import fr.themode.minestom.data.Data;
|
||||||
|
import fr.themode.minestom.instance.Instance;
|
||||||
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface UpdateConsumer {
|
||||||
|
|
||||||
|
void update(Instance instance, BlockPosition blockPosition, Data data);
|
||||||
|
|
||||||
|
}
|
@ -16,9 +16,11 @@ public class ChunkGeneratorDemo extends ChunkGenerator {
|
|||||||
for (byte x = 0; x < 16; x++)
|
for (byte x = 0; x < 16; x++)
|
||||||
for (byte z = 0; z < 16; z++) {
|
for (byte z = 0; z < 16; z++) {
|
||||||
for (byte y = 0; y < 65; y++) {
|
for (byte y = 0; y < 65; y++) {
|
||||||
Data data = new Data();
|
if (random.nextInt(100) > 90) {
|
||||||
data.set("x", (int) x, int.class);
|
batch.setCustomBlock(x, y, z, "custom_block", new Data());
|
||||||
batch.setCustomBlock(x, y, z, "custom_block", data);
|
} else {
|
||||||
|
batch.setBlock(x, y, z, (short) 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,31 @@ package fr.themode.minestom.instance.demo;
|
|||||||
|
|
||||||
import fr.themode.minestom.data.Data;
|
import fr.themode.minestom.data.Data;
|
||||||
import fr.themode.minestom.entity.Player;
|
import fr.themode.minestom.entity.Player;
|
||||||
|
import fr.themode.minestom.instance.Instance;
|
||||||
import fr.themode.minestom.instance.block.CustomBlock;
|
import fr.themode.minestom.instance.block.CustomBlock;
|
||||||
import fr.themode.minestom.instance.block.UpdateOption;
|
import fr.themode.minestom.instance.block.UpdateOption;
|
||||||
import fr.themode.minestom.timer.TimeUnit;
|
import fr.themode.minestom.timer.TimeUnit;
|
||||||
|
import fr.themode.minestom.utils.BlockPosition;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class StoneBlock extends CustomBlock {
|
public class StoneBlock extends CustomBlock {
|
||||||
|
|
||||||
private static final UpdateOption UPDATE_OPTION = new UpdateOption(1, TimeUnit.TICK);
|
private static final UpdateOption UPDATE_OPTION = new UpdateOption(1, TimeUnit.TICK);
|
||||||
|
|
||||||
|
private final AtomicInteger counter = new AtomicInteger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateOption getUpdateOption() {
|
public UpdateOption getUpdateOption() {
|
||||||
return UPDATE_OPTION;
|
return UPDATE_OPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Data data) {
|
public void update(Instance instance, BlockPosition blockPosition, Data data) {
|
||||||
System.out.println("BLOCK HAS BEEN UPDATED");
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data.set("value", counter.incrementAndGet(), int.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,7 +17,6 @@ import java.util.function.Consumer;
|
|||||||
public class ChunkReader {
|
public class ChunkReader {
|
||||||
|
|
||||||
public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, boolean shouldDecompress, Consumer<Chunk> callback) {
|
public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, boolean shouldDecompress, Consumer<Chunk> callback) {
|
||||||
|
|
||||||
b = shouldDecompress ? CompressionUtils.getDecompressedData(b) : b;
|
b = shouldDecompress ? CompressionUtils.getDecompressedData(b) : b;
|
||||||
|
|
||||||
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(b));
|
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(b));
|
||||||
@ -30,7 +29,6 @@ public class ChunkReader {
|
|||||||
chunkBatch = instance.createChunkBatch(chunk);
|
chunkBatch = instance.createChunkBatch(chunk);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// TODO block data
|
|
||||||
int index = stream.readInt();
|
int index = stream.readInt();
|
||||||
boolean isCustomBlock = stream.readBoolean();
|
boolean isCustomBlock = stream.readBoolean();
|
||||||
short blockId = stream.readShort();
|
short blockId = stream.readShort();
|
||||||
@ -55,6 +53,7 @@ public class ChunkReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (EOFException e) {
|
} catch (EOFException e) {
|
||||||
|
// Finished reading
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user