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,51 +2,53 @@ 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) {
this.cipher = cipher;
}
private final Cipher cipher;
private byte[] inTempArray = new byte[0];
private byte[] outTempArray = new byte[0];
private byte[] bufToByte(ByteBuf buffer) {
int remainingBytes = buffer.readableBytes();
protected CipherBase(@NotNull Cipher cipher) {
this.cipher = cipher;
}
// Need to resize temp array
if (inTempArray.length < remainingBytes) {
inTempArray = new byte[remainingBytes];
}
private byte[] bufToByte(ByteBuf buffer) {
int remainingBytes = buffer.readableBytes();
buffer.readBytes(inTempArray, 0, remainingBytes);
return inTempArray;
}
// Need to resize temp array
if (inTempArray.length < remainingBytes) {
inTempArray = new byte[remainingBytes];
}
protected ByteBuf decrypt(ChannelHandlerContext channelHandlerContext, ByteBuf byteBufIn) throws ShortBufferException {
int remainingBytes = byteBufIn.readableBytes();
byte[] bytes = bufToByte(byteBufIn);
buffer.readBytes(inTempArray, 0, remainingBytes);
return inTempArray;
}
ByteBuf outputBuffer = channelHandlerContext.alloc().heapBuffer(cipher.getOutputSize(remainingBytes));
outputBuffer.writerIndex(cipher.update(bytes, 0, remainingBytes, outputBuffer.array(), outputBuffer.arrayOffset()));
protected ByteBuf decrypt(ChannelHandlerContext channelHandlerContext, ByteBuf byteBufIn) throws ShortBufferException {
int remainingBytes = byteBufIn.readableBytes();
byte[] bytes = bufToByte(byteBufIn);
return outputBuffer;
}
ByteBuf outputBuffer = channelHandlerContext.alloc().heapBuffer(cipher.getOutputSize(remainingBytes));
outputBuffer.writerIndex(cipher.update(bytes, 0, remainingBytes, outputBuffer.array(), outputBuffer.arrayOffset()));
protected void encrypt(ByteBuf byteBufIn, ByteBuf byteBufOut) throws ShortBufferException {
int remainingBytes = byteBufIn.readableBytes();
byte[] bytes = bufToByte(byteBufIn);
int newSize = cipher.getOutputSize(remainingBytes);
return outputBuffer;
}
// Need to resize temp array
if (outTempArray.length < newSize) {
outTempArray = new byte[newSize];
}
protected void encrypt(ByteBuf byteBufIn, ByteBuf byteBufOut) throws ShortBufferException {
int remainingBytes = byteBufIn.readableBytes();
byte[] bytes = bufToByte(byteBufIn);
int newSize = cipher.getOutputSize(remainingBytes);
byteBufOut.writeBytes(outTempArray, 0, cipher.update(bytes, 0, remainingBytes, outTempArray));
}
// Need to resize temp array
if (outTempArray.length < newSize) {
outTempArray = new byte[newSize];
}
byteBufOut.writeBytes(outTempArray, 0, cipher.update(bytes, 0, remainingBytes, outTempArray));
}
}

View File

@ -8,13 +8,13 @@ import javax.crypto.Cipher;
import java.util.List;
public class Decrypter extends MessageToMessageDecoder<ByteBuf> {
private final CipherBase cipher;
private final CipherBase cipher;
public Decrypter(Cipher cipher) {
this.cipher = new CipherBase(cipher);
}
public Decrypter(Cipher cipher) {
this.cipher = new CipherBase(cipher);
}
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
list.add(this.cipher.decrypt(channelHandlerContext, byteBuf));
}
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
list.add(this.cipher.decrypt(channelHandlerContext, byteBuf));
}
}

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,21 +66,39 @@ public class ChunkBatch implements InstanceBatch {
}
private void addBlockData(byte x, int y, byte z, short blockStateId, short customBlockId, @Nullable Data data) {
final int index = ChunkUtils.getBlockIndex(x, y, z);
if (data != null) {
synchronized (blockDataMap) {
this.blockDataMap.put(index, 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) {
synchronized (blockDataMap) {
this.blockDataMap.put(index, data);
}
}
long value = index;
value = (value << 16) | blockStateId;
value = (value << 16) | customBlockId;
synchronized (blocks) {
this.blocks.add(value);
}
}
}
long value = index;
value = (value << 16) | blockStateId;
value = (value << 16) | customBlockId;
synchronized (blocks) {
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;
}
/**
@ -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

@ -54,7 +54,7 @@ public class Main {
//VelocityProxy.enable("rBeJJ79W4MVU");
//BungeeCordProxy.enable();
// MojangAuth.init();
//MojangAuth.init();
minecraftServer.start("0.0.0.0", 25565, PlayerInit.getResponseDataConsumer());
}

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)