mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-29 19:41:47 +01:00
Improving chunk generation performance
This commit is contained in:
parent
d4637f328b
commit
392e702108
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user