WIP blocks update

This commit is contained in:
TheMode 2019-09-15 16:30:38 +02:00
parent 972ed294d3
commit d833963414
9 changed files with 89 additions and 44 deletions

View File

@ -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<>();

View File

@ -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 -> {

View File

@ -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() {

View File

@ -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);
} }
} }
} }

View File

@ -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");
} }

View File

@ -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);
}

View File

@ -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);
}
} }
} }
} }

View File

@ -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

View File

@ -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();
} }