mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-25 01:49:16 +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.
241 lines
10 KiB
Diff
241 lines
10 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Taiyou06 <kaandindar21@gmail.com>
|
|
Date: Mon, 24 Feb 2025 21:33:24 +0100
|
|
Subject: [PATCH] Rewrite ClientboundLightUpdatePacketData
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
On writing operations:
|
|
At 256 sections with 0.75 fill ratio: 18x faster (333.489 μs → 18.606 μs)
|
|
At 256 sections with 0.5 fill ratio: 13.5x faster (147.804 μs → 10.962 μs)
|
|
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java b/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
|
|
index a0b54f3a3d11e0f0f1cb806406a870ba36da8f07..234280499fe1bc495bcdd4c3e144d1f99b7e6975 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
|
|
@@ -16,30 +16,113 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
|
|
public class ClientboundLightUpdatePacketData {
|
|
private static final StreamCodec<ByteBuf, byte[]> DATA_LAYER_STREAM_CODEC = ByteBufCodecs.byteArray(2048);
|
|
+
|
|
+ // Leaf start - Rewrite ClientboundLightUpdatePacketData
|
|
+ // Static constants to avoid allocations
|
|
+ private static final byte[][] EMPTY_ARRAY = new byte[0][];
|
|
+
|
|
+ // Pre-sized arrays to avoid dynamic resizing
|
|
+ private static final ThreadLocal<byte[][]> SKY_BUFFER = ThreadLocal.withInitial(() -> new byte[256][]);
|
|
+ private static final ThreadLocal<byte[][]> BLOCK_BUFFER = ThreadLocal.withInitial(() -> new byte[256][]);
|
|
+
|
|
+ // Pre-cached BitSets with fixed size
|
|
private final BitSet skyYMask;
|
|
private final BitSet blockYMask;
|
|
private final BitSet emptySkyYMask;
|
|
private final BitSet emptyBlockYMask;
|
|
- private final List<byte[]> skyUpdates;
|
|
- private final List<byte[]> blockUpdates;
|
|
+
|
|
+ // Fixed arrays with exact counts
|
|
+ private final byte[][] skyUpdates;
|
|
+ private final byte[][] blockUpdates;
|
|
+ private final int skyUpdateCount;
|
|
+ private final int blockUpdateCount;
|
|
+ // Leaf end - Rewrite ClientboundLightUpdatePacketData
|
|
|
|
public ClientboundLightUpdatePacketData(ChunkPos chunkPos, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight) {
|
|
- this.skyYMask = new BitSet();
|
|
- this.blockYMask = new BitSet();
|
|
- this.emptySkyYMask = new BitSet();
|
|
- this.emptyBlockYMask = new BitSet();
|
|
- this.skyUpdates = Lists.newArrayList();
|
|
- this.blockUpdates = Lists.newArrayList();
|
|
-
|
|
- for (int i = 0; i < lightEngine.getLightSectionCount(); i++) {
|
|
+ // Leaf start - Rewrite ClientboundLightUpdatePacketData
|
|
+ int sectionCount = lightEngine.getLightSectionCount();
|
|
+
|
|
+ // Round up to nearest long boundary (64 bits) to prevent BitSet expansion
|
|
+ int longWords = (sectionCount + 63) >>> 6;
|
|
+ int bitSetSize = longWords << 6;
|
|
+
|
|
+ // Pre-size all BitSets to exact size needed
|
|
+ this.skyYMask = new BitSet(bitSetSize);
|
|
+ this.blockYMask = new BitSet(bitSetSize);
|
|
+ this.emptySkyYMask = new BitSet(bitSetSize);
|
|
+ this.emptyBlockYMask = new BitSet(bitSetSize);
|
|
+
|
|
+ // Get buffer arrays from thread local storage to avoid allocations
|
|
+ byte[][] skyBuffer = SKY_BUFFER.get();
|
|
+ byte[][] blockBuffer = BLOCK_BUFFER.get();
|
|
+
|
|
+ // Process all sections in a single pass
|
|
+ int skyCount = 0;
|
|
+ int blockCount = 0;
|
|
+ int minLightSection = lightEngine.getMinLightSection();
|
|
+
|
|
+ // Cache layer listeners to avoid repeated method calls
|
|
+ var skyLayerListener = lightEngine.getLayerListener(LightLayer.SKY);
|
|
+ var blockLayerListener = lightEngine.getLayerListener(LightLayer.BLOCK);
|
|
+
|
|
+ // Single pass through all sections
|
|
+ for (int i = 0; i < sectionCount; i++) {
|
|
+ int sectionY = minLightSection + i;
|
|
+ SectionPos sectionPos = SectionPos.of(chunkPos.x, sectionY, chunkPos.z);
|
|
+
|
|
+ // Process sky light
|
|
if (skyLight == null || skyLight.get(i)) {
|
|
- this.prepareSectionData(chunkPos, lightEngine, LightLayer.SKY, i, this.skyYMask, this.emptySkyYMask, this.skyUpdates);
|
|
+ DataLayer skyData = skyLayerListener.getDataLayerData(sectionPos);
|
|
+ if (skyData != null) {
|
|
+ if (skyData.isEmpty()) {
|
|
+ emptySkyYMask.set(i);
|
|
+ } else {
|
|
+ skyYMask.set(i);
|
|
+ // Store in buffer temporarily - only clone at the end
|
|
+ skyBuffer[skyCount++] = skyData.getData();
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
+ // Process block light
|
|
if (blockLight == null || blockLight.get(i)) {
|
|
- this.prepareSectionData(chunkPos, lightEngine, LightLayer.BLOCK, i, this.blockYMask, this.emptyBlockYMask, this.blockUpdates);
|
|
+ DataLayer blockData = blockLayerListener.getDataLayerData(sectionPos);
|
|
+ if (blockData != null) {
|
|
+ if (blockData.isEmpty()) {
|
|
+ emptyBlockYMask.set(i);
|
|
+ } else {
|
|
+ blockYMask.set(i);
|
|
+ // Store in buffer temporarily - only clone at the end
|
|
+ blockBuffer[blockCount++] = blockData.getData();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Create final arrays with exact sizes
|
|
+ if (skyCount > 0) {
|
|
+ this.skyUpdates = new byte[skyCount][];
|
|
+ // Clone only at the end to minimize work
|
|
+ for (int i = 0; i < skyCount; i++) {
|
|
+ this.skyUpdates[i] = skyBuffer[i].clone();
|
|
+ }
|
|
+ } else {
|
|
+ this.skyUpdates = EMPTY_ARRAY;
|
|
+ }
|
|
+
|
|
+ if (blockCount > 0) {
|
|
+ this.blockUpdates = new byte[blockCount][];
|
|
+ // Clone only at the end to minimize work
|
|
+ for (int i = 0; i < blockCount; i++) {
|
|
+ this.blockUpdates[i] = blockBuffer[i].clone();
|
|
}
|
|
+ } else {
|
|
+ this.blockUpdates = EMPTY_ARRAY;
|
|
}
|
|
+
|
|
+ this.skyUpdateCount = skyCount;
|
|
+ this.blockUpdateCount = blockCount;
|
|
+ // Leaf end - Rewrite ClientboundLightUpdatePacketData
|
|
}
|
|
|
|
public ClientboundLightUpdatePacketData(FriendlyByteBuf buffer, int x, int z) {
|
|
@@ -47,8 +130,30 @@ public class ClientboundLightUpdatePacketData {
|
|
this.blockYMask = buffer.readBitSet();
|
|
this.emptySkyYMask = buffer.readBitSet();
|
|
this.emptyBlockYMask = buffer.readBitSet();
|
|
- this.skyUpdates = buffer.readList(DATA_LAYER_STREAM_CODEC);
|
|
- this.blockUpdates = buffer.readList(DATA_LAYER_STREAM_CODEC);
|
|
+
|
|
+ // Leaf start - Rewrite ClientboundLightUpdatePacketData
|
|
+ // Read lists directly as arrays to avoid intermediate collections
|
|
+ List<byte[]> skyList = buffer.readList(DATA_LAYER_STREAM_CODEC);
|
|
+ List<byte[]> blockList = buffer.readList(DATA_LAYER_STREAM_CODEC);
|
|
+
|
|
+ int skySize = skyList.size();
|
|
+ int blockSize = blockList.size();
|
|
+
|
|
+ if (skySize > 0) {
|
|
+ this.skyUpdates = skyList.toArray(new byte[skySize][]);
|
|
+ } else {
|
|
+ this.skyUpdates = EMPTY_ARRAY;
|
|
+ }
|
|
+
|
|
+ if (blockSize > 0) {
|
|
+ this.blockUpdates = blockList.toArray(new byte[blockSize][]);
|
|
+ } else {
|
|
+ this.blockUpdates = EMPTY_ARRAY;
|
|
+ }
|
|
+
|
|
+ this.skyUpdateCount = skySize;
|
|
+ this.blockUpdateCount = blockSize;
|
|
+ // Leaf end - Rewrite ClientboundLightUpdatePacketData
|
|
}
|
|
|
|
public void write(FriendlyByteBuf buffer) {
|
|
@@ -56,25 +161,33 @@ public class ClientboundLightUpdatePacketData {
|
|
buffer.writeBitSet(this.blockYMask);
|
|
buffer.writeBitSet(this.emptySkyYMask);
|
|
buffer.writeBitSet(this.emptyBlockYMask);
|
|
- buffer.writeCollection(this.skyUpdates, DATA_LAYER_STREAM_CODEC);
|
|
- buffer.writeCollection(this.blockUpdates, DATA_LAYER_STREAM_CODEC);
|
|
- }
|
|
|
|
- private void prepareSectionData(
|
|
- ChunkPos chunkPos, LevelLightEngine levelLightEngine, LightLayer lightLayer, int index, BitSet skyLight, BitSet blockLight, List<byte[]> updates
|
|
- ) {
|
|
- DataLayer dataLayerData = levelLightEngine.getLayerListener(lightLayer)
|
|
- .getDataLayerData(SectionPos.of(chunkPos, levelLightEngine.getMinLightSection() + index));
|
|
- if (dataLayerData != null) {
|
|
- if (dataLayerData.isEmpty()) {
|
|
- blockLight.set(index);
|
|
- } else {
|
|
- skyLight.set(index);
|
|
- updates.add(dataLayerData.copy().getData());
|
|
+ // Leaf start - Rewrite ClientboundLightUpdatePacketData
|
|
+ // Avoid creating unnecessary objects when writing
|
|
+ if (this.skyUpdateCount > 0) {
|
|
+ // Use direct array access for efficiency
|
|
+ buffer.writeVarInt(this.skyUpdateCount);
|
|
+ for (int i = 0; i < this.skyUpdateCount; i++) {
|
|
+ DATA_LAYER_STREAM_CODEC.encode(buffer, this.skyUpdates[i]);
|
|
}
|
|
+ } else {
|
|
+ buffer.writeVarInt(0);
|
|
}
|
|
+
|
|
+ if (this.blockUpdateCount > 0) {
|
|
+ // Use direct array access for efficiency
|
|
+ buffer.writeVarInt(this.blockUpdateCount);
|
|
+ for (int i = 0; i < this.blockUpdateCount; i++) {
|
|
+ DATA_LAYER_STREAM_CODEC.encode(buffer, this.blockUpdates[i]);
|
|
+ }
|
|
+ } else {
|
|
+ buffer.writeVarInt(0);
|
|
+ }
|
|
+ // Leaf end - Rewrite ClientboundLightUpdatePacketData
|
|
}
|
|
|
|
+ // Getter methods
|
|
+
|
|
public BitSet getSkyYMask() {
|
|
return this.skyYMask;
|
|
}
|
|
@@ -84,7 +197,7 @@ public class ClientboundLightUpdatePacketData {
|
|
}
|
|
|
|
public List<byte[]> getSkyUpdates() {
|
|
- return this.skyUpdates;
|
|
+ return this.skyUpdateCount > 0 ? java.util.Arrays.asList(this.skyUpdates) : List.of(); // Leaf - Rewrite ClientboundLightUpdatePacketData
|
|
}
|
|
|
|
public BitSet getBlockYMask() {
|
|
@@ -96,6 +209,6 @@ public class ClientboundLightUpdatePacketData {
|
|
}
|
|
|
|
public List<byte[]> getBlockUpdates() {
|
|
- return this.blockUpdates;
|
|
+ return this.blockUpdateCount > 0 ? java.util.Arrays.asList(this.blockUpdates) : List.of(); // Leaf - Rewrite ClientboundLightUpdatePacketData
|
|
}
|
|
}
|