Improve ChunkBatch

This commit is contained in:
TheMode 2021-05-28 14:29:26 +02:00
parent ab0f400ea8
commit 4739dbd0b8
2 changed files with 17 additions and 59 deletions

View File

@ -4,9 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import net.minestom.server.data.Data;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
@ -39,14 +36,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
private static final Logger LOGGER = LoggerFactory.getLogger(ChunkBatch.class);
// Need to be synchronized manually
// Format: blockIndex/blockStateId/customBlockId (32/16/16 bits)
private final LongList blocks;
// Need to be synchronized manually
// block index - data
private final Int2ObjectMap<Data> blockDataMap;
private final Int2ObjectMap<Block> blocks = new Int2ObjectOpenHashMap<>();
// Available for other implementations to handle.
protected final CountDownLatch readyLatch;
private final BatchOption options;
@ -56,41 +46,20 @@ public class ChunkBatch implements Batch<ChunkCallback> {
}
public ChunkBatch(BatchOption options) {
this(new LongArrayList(), new Int2ObjectOpenHashMap<>(), options);
this(options, true);
}
protected ChunkBatch(LongList blocks, Int2ObjectMap<Data> blockDataMap, BatchOption options) {
this(blocks, blockDataMap, options, true);
}
private ChunkBatch(LongList blocks, Int2ObjectMap<Data> blockDataMap, BatchOption options, boolean ready) {
this.blocks = blocks;
this.blockDataMap = blockDataMap;
private ChunkBatch(BatchOption options, boolean ready) {
this.readyLatch = new CountDownLatch(ready ? 0 : 1);
this.options = options;
}
@Override
public void setBlock(int x, int y, int z, @NotNull Block block) {
final short blockStateId = block.getStateId();
// TODO other ids
// Cache the entry to be placed later during flush
final int index = ChunkUtils.getBlockIndex(x, y, z);
long value = index;
value = (value << 16) | blockStateId;
//value = (value << 16) | customBlockId;
synchronized (blocks) {
this.blocks.add(value);
this.blocks.put(index, block);
}
/*if (data != null) {
synchronized (blockDataMap) {
this.blockDataMap.put(index, data);
}
}*/
}
@Override
@ -185,7 +154,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
boolean safeCallback) {
if (!this.options.isUnsafeApply()) this.awaitReady();
final ChunkBatch inverse = this.options.shouldCalculateInverse() ? new ChunkBatch(new LongArrayList(), new Int2ObjectOpenHashMap<>(), options, false) : null;
final ChunkBatch inverse = this.options.shouldCalculateInverse() ? new ChunkBatch(options, false) : null;
BLOCK_BATCH_POOL.execute(() -> singleThreadFlush(instance, chunk, inverse, callback, safeCallback));
return inverse;
}
@ -202,18 +171,23 @@ public class ChunkBatch implements Batch<ChunkCallback> {
return;
}
if (this.options.isFullChunk())
if (this.options.isFullChunk()) {
// Clear the chunk
chunk.reset();
}
if (blocks.isEmpty()) {
// Nothing to flush
OptionalCallback.execute(callback, chunk);
return;
}
final IntSet sections = new IntArraySet();
synchronized (blocks) {
for (long block : blocks) {
final int section = apply(chunk, block, inverse);
for (var entry : blocks.int2ObjectEntrySet()) {
final int position = entry.getIntKey();
final Block block = entry.getValue();
final int section = apply(chunk, position, block, inverse);
sections.add(section);
}
}
@ -229,33 +203,18 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* Applies a single block change given a chunk and a value in the described format.
*
* @param chunk The chunk to apply the change
* @param value block index|state id|custom block id (32|16|16 bits)
* @param index the block position computed using {@link ChunkUtils#getBlockIndex(int, int, int)}
* @param block the block to place
* @return The chunk section which the block was placed
*/
private int apply(@NotNull Chunk chunk, long value, @Nullable ChunkBatch inverse) {
final short customBlockId = (short) (value & 0xFFFF);
final short blockId = (short) ((value >> 16) & 0xFFFF);
final int index = (int) ((value >> 32) & 0xFFFFFFFFL);
Data data = null;
if (!blockDataMap.isEmpty()) {
synchronized (blockDataMap) {
data = blockDataMap.get(index);
}
}
private int apply(@NotNull Chunk chunk, int index, Block block, @Nullable ChunkBatch inverse) {
final int x = ChunkUtils.blockIndexToChunkPositionX(index);
final int y = ChunkUtils.blockIndexToChunkPositionY(index);
final int z = ChunkUtils.blockIndexToChunkPositionZ(index);
if (inverse != null) {
Block prevBlock = chunk.getBlock(x, y, z);
inverse.setBlock(x, y, z, prevBlock);
}
Block block = Block.fromStateId(blockId);
// TODO other data
chunk.UNSAFE_setBlock(x, y, z, block);
return ChunkUtils.getSectionAt(y);
}

View File

@ -13,8 +13,7 @@ public class ChunkGenerationBatch extends ChunkBatch {
private final Chunk chunk;
public ChunkGenerationBatch(InstanceContainer instance, Chunk chunk) {
super(null, null, new BatchOption());
super(new BatchOption());
this.instance = instance;
this.chunk = chunk;
}