Improving chunk generation performance

This commit is contained in:
themode 2020-11-16 17:02:40 +01:00
parent d4637f328b
commit 392e702108
6 changed files with 85 additions and 71 deletions

View File

@ -2,16 +2,18 @@ package net.minestom.server.extras.mojangAuth;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.jetbrains.annotations.NotNull;
import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;
public class CipherBase {
private final Cipher cipher;
private byte[] inTempArray = new byte[0];
private byte[] outTempArray = new byte[0];
protected CipherBase(Cipher cipher) {
protected CipherBase(@NotNull Cipher cipher) {
this.cipher = cipher;
}

View File

@ -503,7 +503,7 @@ public class InstanceContainer extends Instance {
@Override
public ChunkBatch createChunkBatch(@NotNull Chunk chunk) {
Check.notNull(chunk, "The chunk of a ChunkBatch cannot be null");
return new ChunkBatch(this, chunk);
return new ChunkBatch(this, chunk, false);
}
@Override
@ -540,7 +540,7 @@ public class InstanceContainer extends Instance {
if (chunkGenerator != null && chunk.shouldGenerate()) {
// Execute the chunk generator to populate the chunk
final ChunkBatch chunkBatch = createChunkBatch(chunk);
final ChunkBatch chunkBatch = new ChunkBatch(this, chunk, true);
chunkBatch.flushChunkGenerator(chunkGenerator, callback);
} else {

View File

@ -31,6 +31,8 @@ public class ChunkBatch implements InstanceBatch {
private final InstanceContainer instance;
private final Chunk chunk;
private final boolean generationBatch;
// Need to be synchronized manually
// Format: blockIndex/blockStateId/customBlockId (32/16/16 bits)
private final LongList blocks = new LongArrayList();
@ -39,9 +41,11 @@ public class ChunkBatch implements InstanceBatch {
// block index - data
private final Int2ObjectMap<Data> blockDataMap = new Int2ObjectOpenHashMap<>();
public ChunkBatch(@NotNull InstanceContainer instance, @NotNull Chunk chunk) {
public ChunkBatch(@NotNull InstanceContainer instance, @NotNull Chunk chunk,
boolean generationBatch) {
this.instance = instance;
this.chunk = chunk;
this.generationBatch = generationBatch;
}
@Override
@ -62,6 +66,10 @@ public class ChunkBatch implements InstanceBatch {
}
private void addBlockData(byte x, int y, byte z, short blockStateId, short customBlockId, @Nullable Data data) {
if (isGenerationBatch()) {
chunk.UNSAFE_setBlock(x, y, z, blockStateId, customBlockId, data, CustomBlockUtils.hasUpdate(customBlockId));
} else {
final int index = ChunkUtils.getBlockIndex(x, y, z);
if (data != null) {
@ -78,6 +86,20 @@ public class ChunkBatch implements InstanceBatch {
this.blocks.add(value);
}
}
}
/**
* Gets if this chunk batch is part of a chunk generation.
* <p>
* Being a generation batch mean that blocks set are not being stored
* but are immediately placed on the chunks. Using less memory
* and CPU cycles.
*
* @return true if this batch is part of a chunk generation
*/
public boolean isGenerationBatch() {
return generationBatch;
}
/**
* Called to fill the chunk batch.
@ -92,24 +114,15 @@ public class ChunkBatch implements InstanceBatch {
chunkGenerator.generateChunkData(this, chunk.getChunkX(), chunk.getChunkZ());
// Check if there is anything to process
if (blocks.isEmpty() && !hasPopulator) {
OptionalCallback.execute(callback, chunk);
return;
}
singleThreadFlush(hasPopulator ? null : callback, true);
clearData(); // So the populators won't place those blocks again
if (hasPopulator) {
for (ChunkPopulator chunkPopulator : populators) {
chunkPopulator.populateChunk(this, chunk);
}
singleThreadFlush(callback, true);
clearData(); // Clear populators blocks
}
instance.scheduleNextTick(inst -> {
OptionalCallback.execute(callback, chunk);
});
});
}

View File

@ -30,7 +30,6 @@ import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.world.DimensionType;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public class PlayerInit {
@ -44,7 +43,7 @@ public class PlayerInit {
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD);
instanceContainer.enableAutoChunkLoad(true);
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
instanceContainer.setChunkGenerator(noiseTestGenerator);
// Load some chunks beforehand
final int loopStart = -3;
@ -163,8 +162,8 @@ public class PlayerInit {
player.addEventCallback(PlayerLoginEvent.class, event -> {
event.setSpawningInstance(instanceContainer);
int x = ThreadLocalRandom.current().nextInt()%10000;
player.setRespawnPoint(new Position(x, 64f, 0));
//int x = ThreadLocalRandom.current().nextInt()%10000;
player.setRespawnPoint(new Position(0, 64f, 0));
/*player.getInventory().addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> {
if (slot == -999)