9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00
Files
Leaf/leaf-server/minecraft-patches/features/0216-Async-chunk-sending.patch
2025-05-03 07:55:50 -04:00

109 lines
6.1 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 32608df3da169159c070f37cb55407f4f6187744..67275e803e0287306b163f4eec17388b9c701a8c 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -409,19 +409,91 @@ public final class RegionizedPlayerChunkLoader {
this.delayedTicketOps.addLast(op);
}
+ // Leaf start - Async chunk sending
+ /**
+ * Sends a chunk to the player.
+ * If async chunk sending is enabled, this will prepare and send the chunk packet asynchronously.
+ * Otherwise, it will use the synchronous chunk sending implementation.
+ */
private void sendChunk(final int chunkX, final int chunkZ) {
- if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
- ((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
- .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player);
+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
- final LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
+ if (!this.sentChunks.add(chunkKey)) {
+ // Already in our sent list - silently return instead of throwing an exception
+ return;
+ }
+
+ // Get the chunk now, as we need it for both sync and async paths
+ final LevelChunk chunk = ((ChunkSystemLevel) this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
+ if (chunk == null) {
+ // Handle case where chunk is no longer loaded
+ this.sentChunks.remove(chunkKey);
+ return;
+ }
+
+ // Try to mark the chunk as received by this player
+ try {
+ // This part needs to remain on the main thread as it affects shared state
+ ((ChunkSystemServerLevel) this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
+ .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder.moonrise$addReceivedChunk(this.player);
+ // Call onChunkWatch on the main thread as it might affect server state
PlatformHooks.get().onChunkWatch(this.world, chunk, this.player);
- PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
+ } catch (IllegalStateException e) {
+ // This happens if the chunk was already marked as received by this player
+ // Just remove it from our sent list and return
+ this.sentChunks.remove(chunkKey);
return;
}
- throw new IllegalStateException();
+
+ // Check if async chunk sending is enabled
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
+ // Async implementation
+ net.minecraft.Util.backgroundExecutor().execute(() -> {
+ try {
+ final net.minecraft.server.network.ServerGamePacketListenerImpl connection = this.player.connection;
+ final ServerLevel serverLevel = this.world;
+
+ // Create the packet with anti-xray control flag
+ final net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket packet = new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
+ chunk, serverLevel.getLightEngine(), null, null,
+ serverLevel.chunkPacketBlockController.shouldModify(this.player, chunk)
+ );
+
+ // Let the main thread handle the anti-xray processing
+ serverLevel.getServer().execute(() -> {
+ if (this.removed || !this.sentChunks.contains(chunkKey)) {
+ return;
+ }
+
+ // This will trigger anti-xray processing and mark the packet as ready when done
+ // The packet automatically handles readiness
+ // Send the packet (which will be held until ready by the network layer)
+ connection.send(packet);
+
+ // Fire events and send POI packets
+ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(
+ new org.bukkit.craftbukkit.CraftChunk(chunk),
+ this.player.getBukkitEntity()
+ ).callEvent();
+ }
+
+ net.minecraft.network.protocol.game.DebugPackets.sendPoiPacketsForChunk(serverLevel, chunk.getPos());
+ });
+ } catch (Exception e) {
+ org.dreeam.leaf.async.AsyncChunkSending.LOGGER.error("Failed to send chunk asynchronously!", e);
+
+ if (!this.removed) {
+ this.sentChunks.remove(chunkKey);
+ }
+ }
+ });
+ } else {
+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
+ }
}
+ // Leaf end - Async chunk sending
private void sendUnloadChunk(final int chunkX, final int chunkZ) {
if (!this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {