mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-26 18:39:23 +00:00
ClassInstanceMultiMap belongs to Minecraft vanilla entity storage. And is unused, since replaced by spottedleaf's entity storage (rewrite chunk system). However these patches might be useful for vanilla entity storage if is used.
189 lines
12 KiB
Diff
189 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Taiyou06 <kaandindar21@gmail.com>
|
|
Date: Sun, 2 Mar 2025 21:23:20 +0100
|
|
Subject: [PATCH] Async chunk sending
|
|
|
|
|
|
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
|
index 0bca3843e8568b37cda6ae312bdf4f423a0891a9..98054ab2be3fecc5f6a111a11cfe94f1a10419c1 100644
|
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
|
@@ -440,7 +440,15 @@ public final class RegionizedPlayerChunkLoader {
|
|
// Note: drop isAlive() check so that chunks properly unload client-side when the player dies
|
|
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
|
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$removeReceivedChunk(this.player);
|
|
- this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
|
+ // Leaf start - Async chunk sending
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
|
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
|
+ () -> this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)))
|
|
+ );
|
|
+ } else {
|
|
+ this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
// Paper start - PlayerChunkUnloadEvent
|
|
if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(new ChunkPos(chunkX, chunkZ).longKey), player.getBukkitEntity()).callEvent();
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
index 9f6d7c5dc0e591488a8a3763d8a1f1b3671d5299..8af4c964ce67373f9b911ce13164f48c29a07d85 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
@@ -75,6 +75,52 @@ public class ClientboundLevelChunkPacketData {
|
|
}
|
|
}
|
|
|
|
+ // Leaf start - Async chunk sending
|
|
+ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo, BlockEntity[] blockEntities, Map<Heightmap.Types, long[]> heightmaps) {
|
|
+ this.heightmaps = heightmaps;
|
|
+
|
|
+ if (Thread.currentThread() instanceof org.dreeam.leaf.async.chunk.AsyncChunkSendThread) {
|
|
+ int size = calculateChunkSize(levelChunk);
|
|
+ ByteBuf buffer = Unpooled.buffer(size);
|
|
+ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo);
|
|
+ // make sure all sections is latest
|
|
+ while (size != buffer.writerIndex()) {
|
|
+ buffer.writerIndex(0);
|
|
+ size = calculateChunkSize(levelChunk);
|
|
+ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo);
|
|
+ }
|
|
+ byte[] array = it.unimi.dsi.fastutil.bytes.ByteArrays.setLength(buffer.array(), buffer.writerIndex());
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setBuffer(array);
|
|
+ }
|
|
+ this.buffer = array;
|
|
+ } else {
|
|
+ this.buffer = new byte[calculateChunkSize(levelChunk)];
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setBuffer(this.buffer);
|
|
+ }
|
|
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
|
+ }
|
|
+
|
|
+ this.blockEntitiesData = Lists.newArrayList();
|
|
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
|
|
+
|
|
+ for (BlockEntity blockEntity : blockEntities) {
|
|
+ // Paper start - Handle oversized block entities in chunks
|
|
+ if (++totalTileEntities > BLOCK_ENTITY_LIMIT) {
|
|
+ net.minecraft.network.protocol.Packet<ClientGamePacketListener> packet = blockEntity.getUpdatePacket();
|
|
+ if (packet != null) {
|
|
+ this.extraPackets.add(packet);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ // Paper end - Handle oversized block entities in chunks
|
|
+ this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(blockEntity));
|
|
+ }
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
+
|
|
public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf buffer, int x, int z) {
|
|
this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(buffer);
|
|
int varInt = buffer.readVarInt();
|
|
@@ -123,6 +169,7 @@ public class ClientboundLevelChunkPacketData {
|
|
// Paper end - Anti-Xray - Add chunk packet info
|
|
}
|
|
|
|
+ if (Thread.currentThread() instanceof org.dreeam.leaf.async.chunk.AsyncChunkSendThread) return; // Leaf - Async chunk sending
|
|
if (buffer.writerIndex() != buffer.capacity()) {
|
|
throw new IllegalStateException("Didn't fill chunk buffer: expected " + buffer.capacity() + " bytes, got " + buffer.writerIndex());
|
|
}
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
index 8578d1f78ddd1bb75f3230f04bfaa35af9f5f822..d8e938abf5123b092cec80feb6468e3d91ae823e 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
@@ -44,6 +44,17 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
|
this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
|
chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
|
}
|
|
+ // Leaf start - Async chunk sending
|
|
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks, net.minecraft.world.level.block.entity.BlockEntity[] blockEntities, java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps) {
|
|
+ ChunkPos pos = chunk.getPos();
|
|
+ this.x = pos.x;
|
|
+ this.z = pos.z;
|
|
+ io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
|
|
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo, blockEntities, heightmaps); // Paper - Anti-Xray
|
|
+ this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
|
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
|
|
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
|
this.x = buffer.readInt();
|
|
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
|
|
index 0376a10ee0544b13e8fd629a7b13f78811e57a30..aa6b900347635857b84460fa8435b81f794f0747 100644
|
|
--- a/net/minecraft/server/network/PlayerChunkSender.java
|
|
+++ b/net/minecraft/server/network/PlayerChunkSender.java
|
|
@@ -64,13 +64,29 @@ public class PlayerChunkSender {
|
|
if (!list.isEmpty()) {
|
|
ServerGamePacketListenerImpl serverGamePacketListenerImpl = player.connection;
|
|
this.unacknowledgedBatches++;
|
|
- serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
|
+ // Leaf start - Async chunk sending
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
|
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
|
+ () -> serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE)
|
|
+ );
|
|
+ } else {
|
|
+ serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
|
|
for (LevelChunk levelChunk : list) {
|
|
sendChunk(serverGamePacketListenerImpl, serverLevel, levelChunk);
|
|
}
|
|
|
|
- serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
|
+ // Leaf start - Async chunk sending
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
|
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
|
+ () -> serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()))
|
|
+ );
|
|
+ } else {
|
|
+ serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
this.batchQuota = this.batchQuota - list.size();
|
|
}
|
|
}
|
|
@@ -81,7 +97,23 @@ public class PlayerChunkSender {
|
|
// Paper start - Anti-Xray
|
|
public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
|
final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
|
|
- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
|
+ // Leaf start - Async chunk sending
|
|
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
|
+ var blockEntities = chunk.blockEntities.values().toArray(new net.minecraft.world.level.block.entity.BlockEntity[0]);
|
|
+ java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps = new java.util.concurrent.ConcurrentHashMap<>();
|
|
+
|
|
+ for (var entry : chunk.getHeightmaps()) {
|
|
+ if (entry.getKey().sendToClient()) {
|
|
+ heightmaps.put(entry.getKey(), entry.getValue().getRawData());
|
|
+ }
|
|
+ }
|
|
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
|
+ () -> packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify, blockEntities, heightmaps))
|
|
+ );
|
|
+ } else {
|
|
+ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
|
+ }
|
|
+ // Leaf end - Async chunk sending
|
|
// Paper end - Anti-Xray
|
|
// Paper start - PlayerChunkLoadEvent
|
|
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
index 36c033b0ee63dfc273d721fb4b614733e8fdef19..4d06df242ab73411bdefc4770e131b27a6ea668a 100644
|
|
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
@@ -18,7 +18,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
|
public static final int SECTION_HEIGHT = 16;
|
|
public static final int SECTION_SIZE = 4096;
|
|
public static final int BIOME_CONTAINER_BITS = 2;
|
|
- short nonEmptyBlockCount; // Paper - package private
|
|
+ volatile short nonEmptyBlockCount; // Paper - package private // Leaf - Async chunk sending - volatile
|
|
private short tickingBlockCount;
|
|
private short tickingFluidCount;
|
|
private boolean isRandomlyTickingBlocksStatus; // Leaf - Cache random tick block status
|