mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 23:38:25 +01:00
progress
This commit is contained in:
parent
4fb248cd77
commit
3390082ea7
20 changed files with 58 additions and 939 deletions
|
@ -82,5 +82,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
- Class<?> result = loader.getClassByName(name, resolve, description);
|
||||
+ Class<?> result = loader.getClassByName(name, resolve, description, this); // Paper - prioritize self
|
||||
|
||||
// If the class was loaded from a library instead of a PluginClassLoader, we can assume that its associated plugin is a transitive dependency and can therefore skip this check.
|
||||
if (result != null && result.getClassLoader() instanceof PluginClassLoader) {
|
||||
if (result != null) {
|
||||
// If the class was loaded from a library instead of a PluginClassLoader, we can assume that its associated plugin is a transitive dependency and can therefore skip this check.
|
|
@ -1,394 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 6 May 2020 23:30:30 -0400
|
||||
Subject: [PATCH] Optimize NibbleArray to use pooled buffers
|
||||
|
||||
Massively reduces memory allocation of 2048 byte buffers by using
|
||||
an object pool for these.
|
||||
|
||||
Uses lots of advanced new capabilities of the Paper codebase :)
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package net.minecraft.network.protocol.game;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
+import io.netty.channel.ChannelFuture; // Paper
|
||||
+
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
+import net.minecraft.server.MCUtil;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
private List<byte[]> blockUpdates;
|
||||
private boolean trustEdges;
|
||||
|
||||
+ // Paper start
|
||||
+ java.lang.Runnable cleaner1;
|
||||
+ java.lang.Runnable cleaner2;
|
||||
+ java.util.concurrent.atomic.AtomicInteger remainingSends = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
+
|
||||
+ @Override
|
||||
+ public void onPacketDispatch(ServerPlayer player) {
|
||||
+ remainingSends.incrementAndGet();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onPacketDispatchFinish(ServerPlayer player, ChannelFuture future) {
|
||||
+ if (remainingSends.decrementAndGet() <= 0) {
|
||||
+ // incase of any race conditions, schedule this delayed
|
||||
+ MCUtil.scheduleTask(5, () -> {
|
||||
+ if (remainingSends.get() == 0) {
|
||||
+ cleaner1.run();
|
||||
+ cleaner2.run();
|
||||
+ }
|
||||
+ }, "Light Packet Release");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasFinishListener() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ // Paper end
|
||||
public ClientboundLightUpdatePacket() {}
|
||||
|
||||
public ClientboundLightUpdatePacket(ChunkPos chunkcoordintpair, LevelLightEngine lightengine, boolean flag) {
|
||||
this.x = chunkcoordintpair.x;
|
||||
this.z = chunkcoordintpair.z;
|
||||
this.trustEdges = flag;
|
||||
- this.skyUpdates = Lists.newArrayList();
|
||||
- this.blockUpdates = Lists.newArrayList();
|
||||
+ this.skyUpdates = Lists.newArrayList();cleaner1 = MCUtil.registerListCleaner(this, this.skyUpdates, DataLayer::releaseBytes); // Paper
|
||||
+ this.blockUpdates = Lists.newArrayList();cleaner2 = MCUtil.registerListCleaner(this, this.blockUpdates, DataLayer::releaseBytes); // Paper
|
||||
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
DataLayer nibblearray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkcoordintpair, -1 + i));
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
this.emptySkyYMask |= 1 << i;
|
||||
} else {
|
||||
this.skyYMask |= 1 << i;
|
||||
- this.skyUpdates.add(nibblearray.getData().clone());
|
||||
+ this.skyUpdates.add(nibblearray.getCloneIfSet()); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
this.emptyBlockYMask |= 1 << i;
|
||||
} else {
|
||||
this.blockYMask |= 1 << i;
|
||||
- this.blockUpdates.add(nibblearray1.getData().clone());
|
||||
+ this.blockUpdates.add(nibblearray1.getCloneIfSet()); // Paper
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
this.trustEdges = flag;
|
||||
this.skyYMask = skyLightMask;
|
||||
this.blockYMask = blockLightMask;
|
||||
- this.skyUpdates = Lists.newArrayList();
|
||||
- this.blockUpdates = Lists.newArrayList();
|
||||
+ this.skyUpdates = Lists.newArrayList();cleaner1 = MCUtil.registerListCleaner(this, this.skyUpdates, DataLayer::releaseBytes); // Paper
|
||||
+ this.blockUpdates = Lists.newArrayList();cleaner2 = MCUtil.registerListCleaner(this, this.blockUpdates, DataLayer::releaseBytes); // Paper
|
||||
|
||||
for (int k = 0; k < 18; ++k) {
|
||||
DataLayer nibblearray;
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
if ((this.skyYMask & 1 << k) != 0) {
|
||||
nibblearray = lightProvider.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(pos, -1 + k));
|
||||
if (nibblearray != null && !nibblearray.isEmpty()) {
|
||||
- this.skyUpdates.add(nibblearray.getData().clone());
|
||||
+ this.skyUpdates.add(nibblearray.getCloneIfSet()); // Paper
|
||||
} else {
|
||||
this.skyYMask &= ~(1 << k);
|
||||
if (nibblearray != null) {
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
|
||||
if ((this.blockYMask & 1 << k) != 0) {
|
||||
nibblearray = lightProvider.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(pos, -1 + k));
|
||||
if (nibblearray != null && !nibblearray.isEmpty()) {
|
||||
- this.blockUpdates.add(nibblearray.getData().clone());
|
||||
+ this.blockUpdates.add(nibblearray.getCloneIfSet()); // Paper
|
||||
} else {
|
||||
this.blockYMask &= ~(1 << k);
|
||||
if (nibblearray != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/DataLayer.java b/src/main/java/net/minecraft/world/level/chunk/DataLayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/DataLayer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/DataLayer.java
|
||||
@@ -0,0 +0,0 @@
|
||||
// mc-dev import
|
||||
package net.minecraft.world.level.chunk;
|
||||
|
||||
+import com.destroystokyo.paper.util.pooled.PooledObjects; // Paper
|
||||
+
|
||||
+import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.Util;
|
||||
+import net.minecraft.server.MCUtil;
|
||||
|
||||
public class DataLayer {
|
||||
|
||||
- @Nullable
|
||||
- protected byte[] data;
|
||||
+ // Paper start
|
||||
+ public static byte[] EMPTY_NIBBLE = new byte[2048];
|
||||
+ private static final int nibbleBucketSizeMultiplier = Integer.getInteger("Paper.nibbleBucketSize", 3072);
|
||||
+ private static final int maxPoolSize = Integer.getInteger("Paper.maxNibblePoolSize", (int) Math.min(6, Math.max(1, Runtime.getRuntime().maxMemory() / 1024 / 1024 / 1024)) * (nibbleBucketSizeMultiplier * 8));
|
||||
+ public static final PooledObjects<byte[]> BYTE_2048 = new PooledObjects<>(() -> new byte[2048], maxPoolSize);
|
||||
+ public static void releaseBytes(byte[] bytes) {
|
||||
+ if (bytes != null && bytes != EMPTY_NIBBLE && bytes.length == 2048) {
|
||||
+ System.arraycopy(EMPTY_NIBBLE, 0, bytes, 0, 2048);
|
||||
+ BYTE_2048.release(bytes);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public DataLayer markPoolSafe(byte[] bytes) {
|
||||
+ if (bytes != EMPTY_NIBBLE) this.data = bytes;
|
||||
+ return markPoolSafe();
|
||||
+ }
|
||||
+ public DataLayer markPoolSafe() {
|
||||
+ poolSafe = true;
|
||||
+ return this;
|
||||
+ }
|
||||
+ public byte[] getIfSet() {
|
||||
+ return this.data != null ? this.data : EMPTY_NIBBLE;
|
||||
+ }
|
||||
+ public byte[] getCloneIfSet() {
|
||||
+ if (data == null) {
|
||||
+ return EMPTY_NIBBLE;
|
||||
+ }
|
||||
+ byte[] ret = BYTE_2048.acquire();
|
||||
+ System.arraycopy(getIfSet(), 0, ret, 0, 2048);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public DataLayer cloneAndSet(byte[] bytes) {
|
||||
+ if (bytes != null && bytes != EMPTY_NIBBLE) {
|
||||
+ this.data = BYTE_2048.acquire();
|
||||
+ System.arraycopy(bytes, 0, this.data, 0, 2048);
|
||||
+ }
|
||||
+ return this;
|
||||
+ }
|
||||
+ boolean poolSafe = false;
|
||||
+ public java.lang.Runnable cleaner;
|
||||
+ private void registerCleaner() {
|
||||
+ if (!poolSafe) {
|
||||
+ cleaner = MCUtil.registerCleaner(this, this.data, DataLayer::releaseBytes);
|
||||
+ } else {
|
||||
+ cleaner = MCUtil.once(() -> DataLayer.releaseBytes(this.data));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+ @Nullable protected byte[] data;
|
||||
+
|
||||
|
||||
public DataLayer() {}
|
||||
|
||||
public DataLayer(byte[] abyte) {
|
||||
+ // Paper start
|
||||
+ this(abyte, false);
|
||||
+ }
|
||||
+ public DataLayer(byte[] abyte, boolean isSafe) {
|
||||
this.data = abyte;
|
||||
+ if (!isSafe) this.data = getCloneIfSet(); // Paper - clone for safety
|
||||
+ registerCleaner();
|
||||
+ // Paper end
|
||||
if (abyte.length != 2048) {
|
||||
throw (IllegalArgumentException) Util.pauseInIde((Throwable) (new IllegalArgumentException("ChunkNibbleArrays should be 2048 bytes not: " + abyte.length)));
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class DataLayer {
|
||||
|
||||
public void set(int index, int value) { // PAIL: private -> public
|
||||
if (this.data == null) {
|
||||
- this.data = new byte[2048];
|
||||
+ this.data = BYTE_2048.acquire(); // Paper
|
||||
+ registerCleaner();// Paper
|
||||
}
|
||||
|
||||
int k = this.getPosition(index);
|
||||
@@ -0,0 +0,0 @@ public class DataLayer {
|
||||
public byte[] getData() {
|
||||
if (this.data == null) {
|
||||
this.data = new byte[2048];
|
||||
+ } else { // Paper start
|
||||
+ // Accessor may need this object past garbage collection so need to clone it and return pooled value
|
||||
+ // If we know its safe for pre GC access, use asBytesPoolSafe(). If you just need read, use getIfSet()
|
||||
+ Runnable cleaner = this.cleaner;
|
||||
+ if (cleaner != null) {
|
||||
+ this.data = this.data.clone();
|
||||
+ cleaner.run(); // release the previously pooled value
|
||||
+ this.cleaner = null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ return this.data;
|
||||
+ }
|
||||
+
|
||||
+ @Nonnull
|
||||
+ public byte[] asBytesPoolSafe() {
|
||||
+ if (this.data == null) {
|
||||
+ this.data = BYTE_2048.acquire(); // Paper
|
||||
+ registerCleaner(); // Paper
|
||||
}
|
||||
|
||||
+ //noinspection ConstantConditions
|
||||
return this.data;
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
public DataLayer copy() { return this.copy(); } // Paper - OBFHELPER
|
||||
public DataLayer copy() {
|
||||
- return this.data == null ? new DataLayer() : new DataLayer((byte[]) this.data.clone());
|
||||
+ return this.data == null ? new DataLayer() : new DataLayer(this.data); // Paper - clone in ctor
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
}
|
||||
|
||||
if (nibblearray != null && !nibblearray.isEmpty()) {
|
||||
- nbttagcompound2.putByteArray("BlockLight", nibblearray.getData());
|
||||
+ nbttagcompound2.putByteArray("BlockLight", nibblearray.asBytesPoolSafe().clone()); // Paper
|
||||
}
|
||||
|
||||
if (nibblearray1 != null && !nibblearray1.isEmpty()) {
|
||||
- nbttagcompound2.putByteArray("SkyLight", nibblearray1.getData());
|
||||
+ nbttagcompound2.putByteArray("SkyLight", nibblearray1.asBytesPoolSafe().clone()); // Paper
|
||||
}
|
||||
|
||||
nbttaglist.add(nbttagcompound2);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
@@ -0,0 +0,0 @@ package net.minecraft.world.level.lighting;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import javax.annotation.Nullable;
|
||||
+import net.minecraft.server.MCUtil;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
|
||||
public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
|
||||
public void copyDataLayer(long pos) {
|
||||
if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
- this.data.queueUpdate(pos, ((DataLayer) this.data.getUpdating(pos)).copy()); // Paper - avoid copying light data
|
||||
+ DataLayer updating = this.data.getUpdating(pos); // Paper - pool nibbles
|
||||
+ this.data.queueUpdate(pos, new DataLayer().markPoolSafe(updating.getCloneIfSet())); // Paper - avoid copying light data - pool safe clone
|
||||
+ if (updating.cleaner != null) MCUtil.scheduleTask(2, updating.cleaner, "Light Engine Release"); // Paper - delay clean incase anything holding ref was still using it
|
||||
this.clearCache();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/FlatDataLayer.java b/src/main/java/net/minecraft/world/level/lighting/FlatDataLayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/FlatDataLayer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/FlatDataLayer.java
|
||||
@@ -0,0 +0,0 @@ public class FlatDataLayer extends DataLayer {
|
||||
|
||||
public FlatDataLayer(DataLayer nibblearray, int i) {
|
||||
super(128);
|
||||
- System.arraycopy(nibblearray.getData(), i * 128, this.data, 0, 128);
|
||||
+ System.arraycopy(nibblearray.getIfSet(), i * 128, this.data, 0, 128); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class FlatDataLayer extends DataLayer {
|
||||
|
||||
@Override
|
||||
public byte[] getData() {
|
||||
- byte[] abyte = new byte[2048];
|
||||
+ byte[] abyte = BYTE_2048.acquire(); // Paper
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
System.arraycopy(this.data, 0, abyte, i * 128, 128);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
protected DataLayer createDataLayer(long sectionPos) {
|
||||
DataLayer nibblearray = (DataLayer) this.queuedSections.get(sectionPos);
|
||||
|
||||
- return nibblearray != null ? nibblearray : new DataLayer();
|
||||
+ return nibblearray != null ? nibblearray : new DataLayer().markPoolSafe(); // Paper
|
||||
}
|
||||
|
||||
protected void clearQueuedSectionBlocks(LayerLightEngine<?, ?> storage, long sectionPos) {
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
|
||||
protected void queueSectionData(long sectionPos, @Nullable DataLayer array, boolean flag) {
|
||||
if (array != null) {
|
||||
- this.queuedSections.put(sectionPos, array);
|
||||
+ DataLayer remove = this.queuedSections.put(sectionPos, array); if (remove != null && remove.cleaner != null) remove.cleaner.run(); // Paper - clean up when removed
|
||||
if (!flag) {
|
||||
this.untrustedSections.add(sectionPos);
|
||||
}
|
||||
} else {
|
||||
- this.queuedSections.remove(sectionPos);
|
||||
+ DataLayer remove = this.queuedSections.remove(sectionPos); if (remove != null && remove.cleaner != null) remove.cleaner.run(); // Paper - clean up when removed
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
j = SectionPos.offset(j, Direction.UP);
|
||||
}
|
||||
|
||||
- return new DataLayer((new FlatDataLayer(nibblearray1, 0)).getData());
|
||||
+ return new DataLayer().markPoolSafe(new FlatDataLayer(nibblearray1, 0).getData()); // Paper - mark pool use as safe (no auto cleaner)
|
||||
} else {
|
||||
- return new DataLayer();
|
||||
+ return new DataLayer().markPoolSafe(); // Paper - mark pool use as safe (no auto cleaner)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).copyDataLayer(i);
|
||||
}
|
||||
|
||||
- Arrays.fill(this.getDataLayer(i, true).getData(), (byte) -1);
|
||||
+ Arrays.fill(this.getDataLayer(i, true).asBytesPoolSafe(), (byte) -1); // Paper
|
||||
k = SectionPos.sectionToBlockCoord(SectionPos.x(i));
|
||||
l = SectionPos.sectionToBlockCoord(SectionPos.y(i));
|
||||
int i1 = SectionPos.sectionToBlockCoord(SectionPos.z(i));
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -0,0 +0,0 @@ public class CraftChunk implements Chunk {
|
||||
sectionSkyLights[i] = emptyLight;
|
||||
} else {
|
||||
sectionSkyLights[i] = new byte[2048];
|
||||
- System.arraycopy(skyLightArray.getData(), 0, sectionSkyLights[i], 0, 2048);
|
||||
+ System.arraycopy(skyLightArray.getIfSet(), 0, sectionSkyLights[i], 0, 2048); // Paper
|
||||
}
|
||||
DataLayer emitLightArray = lightengine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(x, i, z));
|
||||
if (emitLightArray == null) {
|
||||
sectionEmitLights[i] = emptyLight;
|
||||
} else {
|
||||
sectionEmitLights[i] = new byte[2048];
|
||||
- System.arraycopy(emitLightArray.getData(), 0, sectionEmitLights[i], 0, 2048);
|
||||
+ System.arraycopy(emitLightArray.getIfSet(), 0, sectionEmitLights[i], 0, 2048); // Paper
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,320 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Mon, 27 Apr 2020 04:05:38 -0700
|
||||
Subject: [PATCH] Stop copy-on-write operations for updating light data
|
||||
|
||||
Causes huge memory allocations + gc issues
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLightSectionStorage.BlockDataLayerStorageMap> {
|
||||
|
||||
protected BlockLightSectionStorage(LightChunkGetter chunkProvider) {
|
||||
- super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new Long2ObjectOpenHashMap()));
|
||||
+ super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), false)); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLigh
|
||||
|
||||
public static final class BlockDataLayerStorageMap extends DataLayerStorageMap<BlockLightSectionStorage.BlockDataLayerStorageMap> {
|
||||
|
||||
- public BlockDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
|
||||
- super(arrays);
|
||||
+ public BlockDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> long2objectopenhashmap, boolean isVisible) { // Paper - avoid copying light data
|
||||
+ super(long2objectopenhashmap, isVisible); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockLightSectionStorage.BlockDataLayerStorageMap copy() {
|
||||
- return new BlockLightSectionStorage.BlockDataLayerStorageMap(this.map.clone());
|
||||
+ return new BlockDataLayerStorageMap(this.data, true); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
private final long[] lastSectionKeys = new long[2];
|
||||
private final DataLayer[] lastSections = new DataLayer[2];
|
||||
private boolean cacheEnabled;
|
||||
- protected final Long2ObjectOpenHashMap<DataLayer> map;
|
||||
-
|
||||
- protected DataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
|
||||
- this.map = arrays;
|
||||
+ protected final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data; // Paper - avoid copying light data
|
||||
+ protected final boolean isVisible; // Paper - avoid copying light data
|
||||
+ java.util.function.Function<Long, DataLayer> lookup; // Paper - faster branchless lookup
|
||||
+
|
||||
+ // Paper start - avoid copying light data
|
||||
+ protected DataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data, boolean isVisible) {
|
||||
+ if (isVisible) {
|
||||
+ data.performUpdatesLockMap();
|
||||
+ }
|
||||
+ this.data = data;
|
||||
+ this.isVisible = isVisible;
|
||||
+ if (isVisible) {
|
||||
+ lookup = data::getVisibleAsync;
|
||||
+ } else {
|
||||
+ lookup = data::getUpdating;
|
||||
+ }
|
||||
+ // Paper end - avoid copying light data
|
||||
this.clearCache();
|
||||
this.cacheEnabled = true;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
public abstract M copy();
|
||||
|
||||
public void copyDataLayer(long pos) {
|
||||
- this.map.put(pos, ((DataLayer) this.map.get(pos)).copy());
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ this.data.queueUpdate(pos, ((DataLayer) this.data.getUpdating(pos)).copy()); // Paper - avoid copying light data
|
||||
this.clearCache();
|
||||
}
|
||||
|
||||
public boolean hasLayer(long chunkPos) {
|
||||
- return this.map.containsKey(chunkPos);
|
||||
+ return lookup.apply(chunkPos) != null; // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- public DataLayer getLayer(long chunkPos) {
|
||||
+ public final DataLayer getLayer(long chunkPos) { // Paper - final
|
||||
if (this.cacheEnabled) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
if (chunkPos == this.lastSectionKeys[j]) {
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
}
|
||||
}
|
||||
|
||||
- DataLayer nibblearray = (DataLayer) this.map.get(chunkPos);
|
||||
+ DataLayer nibblearray = lookup.apply(chunkPos); // Paper - avoid copying light data
|
||||
|
||||
if (nibblearray == null) {
|
||||
return null;
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
|
||||
@Nullable
|
||||
public DataLayer removeLayer(long chunkPos) {
|
||||
- return (DataLayer) this.map.remove(chunkPos);
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ return (DataLayer) this.data.queueRemove(chunkPos); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
public void setLayer(long pos, DataLayer data) {
|
||||
- this.map.put(pos, data);
|
||||
+ if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
|
||||
+ this.data.queueUpdate(pos, data); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
@@ -0,0 +0,0 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
|
||||
this.lastSectionKeys[i] = Long.MAX_VALUE;
|
||||
this.lastSections[i] = null;
|
||||
}
|
||||
-
|
||||
}
|
||||
|
||||
public void disableCache() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
protected final LongSet dataSectionSet = new LongOpenHashSet();
|
||||
protected final LongSet toMarkNoData = new LongOpenHashSet();
|
||||
protected final LongSet toMarkData = new LongOpenHashSet();
|
||||
- protected volatile M visibleSectionData;
|
||||
- protected final M updatingSectionData;
|
||||
+ protected volatile M e_visible; protected final Object visibleUpdateLock = new Object(); // Paper - diff on change, should be "visible" - force compile fail on usage change
|
||||
+ protected final M updatingSectionData; // Paper - diff on change, should be "updating"
|
||||
protected final LongSet changedSections = new LongOpenHashSet();
|
||||
protected final LongSet sectionsAffectedByLightUpdates = new LongOpenHashSet();
|
||||
protected final Long2ObjectMap<DataLayer> queuedSections = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap());
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
this.layer = lightType;
|
||||
this.chunkSource = chunkProvider;
|
||||
this.updatingSectionData = lightData;
|
||||
- this.visibleSectionData = lightData.copy();
|
||||
- this.visibleSectionData.disableCache();
|
||||
+ this.e_visible = lightData.copy(); // Paper - avoid copying light data
|
||||
+ this.e_visible.disableCache(); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
protected boolean storingLightForSection(long sectionPos) {
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
|
||||
@Nullable
|
||||
protected DataLayer getDataLayer(long sectionPos, boolean cached) {
|
||||
- return this.getDataLayer(cached ? this.updatingSectionData : this.visibleSectionData, sectionPos);
|
||||
+ // Paper start - avoid copying light data
|
||||
+ if (cached) {
|
||||
+ return this.getDataLayer(this.updatingSectionData, sectionPos);
|
||||
+ } else {
|
||||
+ synchronized (this.visibleUpdateLock) {
|
||||
+ return this.getDataLayer(this.e_visible, sectionPos);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - avoid copying light data
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -0,0 +0,0 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
|
||||
|
||||
protected void swapSectionMap() {
|
||||
if (!this.changedSections.isEmpty()) {
|
||||
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
|
||||
M m0 = this.updatingSectionData.copy();
|
||||
|
||||
m0.disableCache();
|
||||
- this.visibleSectionData = m0;
|
||||
+ this.e_visible = m0; // Paper - avoid copying light data
|
||||
+ } // Paper - avoid copying light data
|
||||
this.changedSections.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
private volatile boolean hasSourceInconsistencies;
|
||||
|
||||
protected SkyLightSectionStorage(LightChunkGetter chunkProvider) {
|
||||
- super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new Long2ObjectOpenHashMap(), new Long2IntOpenHashMap(), Integer.MAX_VALUE));
|
||||
+ super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int(), Integer.MAX_VALUE, false)); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLightValue(long blockPos) {
|
||||
long j = SectionPos.blockToSection(blockPos);
|
||||
int k = SectionPos.y(j);
|
||||
- SkyLightSectionStorage.SkyDataLayerStorageMap lightenginestoragesky_a = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.visibleSectionData;
|
||||
- int l = lightenginestoragesky_a.topSections.get(SectionPos.getZeroNode(j));
|
||||
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
|
||||
+ SkyLightSectionStorage.SkyDataLayerStorageMap lightenginestoragesky_a = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.e_visible; // Paper - avoid copying light data - must be after lock acquire
|
||||
+ int l = lightenginestoragesky_a.otherData.getVisibleAsync(SectionPos.getZeroNode(j)); // Paper - avoid copying light data
|
||||
|
||||
if (l != lightenginestoragesky_a.currentLowestY && k < l) {
|
||||
DataLayer nibblearray = this.getDataLayer(lightenginestoragesky_a, j); // Paper - decompile fix
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
} else {
|
||||
return 15;
|
||||
}
|
||||
+ } // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
|
||||
if (((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY > j) {
|
||||
((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY = j;
|
||||
- ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.defaultReturnValue(((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY);
|
||||
+ ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.queueDefaultReturnValue(((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY); // Paper - avoid copying light data
|
||||
}
|
||||
|
||||
long k = SectionPos.getZeroNode(sectionPos);
|
||||
- int l = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(k);
|
||||
+ int l = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(k); // Paper - avoid copying light data
|
||||
|
||||
if (l < j + 1) {
|
||||
- ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.put(k, j + 1);
|
||||
+ ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.queueUpdate(k, j + 1); // Paper - avoid copying light data
|
||||
if (this.columnsWithSkySources.contains(k)) {
|
||||
this.queueAddSource(sectionPos);
|
||||
if (l > ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY) {
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
|
||||
int k = SectionPos.y(sectionPos);
|
||||
|
||||
- if (((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(j) == k + 1) {
|
||||
+ if (((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(j) == k + 1) { // Paper - avoid copying light data
|
||||
long l;
|
||||
|
||||
for (l = sectionPos; !this.storingLightForSection(l) && this.hasSectionsBelow(k); l = SectionPos.offset(l, Direction.DOWN)) {
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
}
|
||||
|
||||
if (this.storingLightForSection(l)) {
|
||||
- ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.put(j, k + 1);
|
||||
+ ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.queueUpdate(j, k + 1); // Paper - avoid copying light data
|
||||
if (flag) {
|
||||
this.queueAddSource(l);
|
||||
}
|
||||
} else {
|
||||
- ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.remove(j);
|
||||
+ ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.queueRemove(j); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
protected void enableLightSources(long columnPos, boolean enabled) {
|
||||
this.runAllUpdates();
|
||||
if (enabled && this.columnsWithSkySources.add(columnPos)) {
|
||||
- int j = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(columnPos);
|
||||
+ int j = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(columnPos); // Paper - avoid copying light data
|
||||
|
||||
if (j != ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY) {
|
||||
long k = SectionPos.asLong(SectionPos.x(columnPos), j - 1, SectionPos.z(columnPos));
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
return nibblearray;
|
||||
} else {
|
||||
long j = SectionPos.offset(sectionPos, Direction.UP);
|
||||
- int k = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(SectionPos.getZeroNode(sectionPos));
|
||||
+ int k = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(SectionPos.getZeroNode(sectionPos)); // Paper - avoid copying light data
|
||||
|
||||
if (k != ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY && SectionPos.y(j) < k) {
|
||||
DataLayer nibblearray1;
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
if (!this.columnsWithSkySources.contains(l)) {
|
||||
return false;
|
||||
} else {
|
||||
- int i1 = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(l);
|
||||
+ int i1 = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
|
||||
|
||||
return SectionPos.sectionToBlockCoord(i1) == j + 16;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
|
||||
protected boolean isAboveData(long sectionPos) {
|
||||
long j = SectionPos.getZeroNode(sectionPos);
|
||||
- int k = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).topSections.get(j);
|
||||
+ int k = ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).otherData.getUpdating(j); // Paper - avoid copying light data
|
||||
|
||||
return k == ((SkyLightSectionStorage.SkyDataLayerStorageMap) this.updatingSectionData).currentLowestY || SectionPos.y(sectionPos) >= k;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
|
||||
public static final class SkyDataLayerStorageMap extends DataLayerStorageMap<SkyLightSectionStorage.SkyDataLayerStorageMap> {
|
||||
|
||||
private int currentLowestY;
|
||||
- private final Long2IntOpenHashMap topSections;
|
||||
-
|
||||
- public SkyDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) {
|
||||
- super(arrays);
|
||||
- this.topSections = columnToTopSection;
|
||||
- columnToTopSection.defaultReturnValue(minSectionY);
|
||||
- this.currentLowestY = minSectionY;
|
||||
+ private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data
|
||||
+
|
||||
+ // Paper start - avoid copying light data
|
||||
+ public SkyDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData, int i, boolean isVisible) {
|
||||
+ super(data, isVisible);
|
||||
+ this.otherData = otherData;
|
||||
+ otherData.queueDefaultReturnValue(i);
|
||||
+ // Paper end - avoid copying light data
|
||||
+ this.currentLowestY = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkyLightSectionStorage.SkyDataLayerStorageMap copy() {
|
||||
- return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.map.clone(), this.topSections.clone(), this.currentLowestY);
|
||||
+ this.otherData.performUpdatesLockMap(); // Paper - avoid copying light data
|
||||
+ return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.data, this.otherData, this.currentLowestY, true); // Paper - avoid copying light data
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MeFisto94 <MeFisto94@users.noreply.github.com>
|
||||
Date: Tue, 12 May 2020 23:02:43 +0200
|
||||
Subject: [PATCH] Workaround for Client Lag Spikes (MC-162253)
|
||||
|
||||
When crossing certain chunk boundaries, the client needlessly
|
||||
calculates light maps for chunk neighbours. In some specific map
|
||||
configurations, these calculations cause a 500ms+ freeze on the Client.
|
||||
|
||||
This patch basically serves as a workaround by sending light maps
|
||||
to the client, so that it doesn't attempt to calculate them.
|
||||
This mitigates the frametime impact to a minimum (but it's still there).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
+import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
// Paper start
|
||||
private static int getLightMask(final LevelChunk chunk) {
|
||||
- final ChunkSection[] chunkSections = chunk.getSections();
|
||||
+ final LevelChunkSection[] chunkSections = chunk.getSections();
|
||||
int mask = 0;
|
||||
|
||||
for (int i = 0; i < chunkSections.length; ++i) {
|
||||
@@ -0,0 +0,0 @@ Lightmasks have 18 bits, from the -1 (void) section until the 17th (air) section
|
||||
Sections go from 0..16. Now whenever a section is not empty, it can potentially change lighting for the section itself, the section below and the section above, hence the bitmask 111b, which is 7d.
|
||||
|
||||
*/
|
||||
- mask |= (ChunkSection.isEmpty(chunkSections[i]) ? 0 : 7) << i;
|
||||
+ mask |= (LevelChunkSection.isEmpty(chunkSections[i]) ? 0 : 7) << i;
|
||||
}
|
||||
|
||||
return mask;
|
||||
@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
||||
public final void sendChunk(ServerPlayer entityplayer, Packet<?>[] apacket, LevelChunk chunk) { this.playerLoadedChunk(entityplayer, apacket, chunk); } // Paper - OBFHELPER
|
||||
private void playerLoadedChunk(ServerPlayer player, Packet<?>[] packets, LevelChunk chunk) {
|
||||
if (packets[0] == null) {
|
||||
+ // Paper start - add 8 for light fix workaround
|
||||
+ if (packets.length != 10) { // in case Plugins call sendChunk, resize
|
||||
+ packets = new Packet[10];
|
||||
+ }
|
||||
+ // Paper end
|
||||
packets[0] = new ClientboundLevelChunkPacket(chunk, 65535, chunk.world.chunkPacketBlockController.shouldModify(player, chunk, 65535)); // Paper - Anti-Xray - Bypass
|
||||
packets[1] = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, true);
|
||||
+
|
||||
+ // Paper start - Fix MC-162253
|
||||
+ final int lightMask = getLightMask(chunk);
|
||||
+ int i = 1;
|
||||
+ for (int x = -1; x <= 1; x++) {
|
||||
+ for (int z = -1; z <= 1; z++) {
|
||||
+ if (x == 0 && z == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ++i;
|
||||
+
|
||||
+ if (!chunk.isNeighbourLoaded(x, z)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final LevelChunk neighbor = chunk.getRelativeNeighbourIfLoaded(x, z);
|
||||
+ final int updateLightMask = lightMask & ~getCeilingLightMask(neighbor);
|
||||
+
|
||||
+ if (updateLightMask == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ packets[i] = new ClientboundLightUpdatePacket(new ChunkPos(chunk.getPos().x + x, chunk.getPos().z + z), lightEngine, updateLightMask, 0, true);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final int viewDistance = playerViewDistanceBroadcastMap.getLastViewDistance(player);
|
||||
+ final long lastPosition = playerViewDistanceBroadcastMap.getLastCoordinate(player);
|
||||
+
|
||||
+ int j = 1;
|
||||
+ for (int x = -1; x <= 1; x++) {
|
||||
+ for (int z = -1; z <= 1; z++) {
|
||||
+ if (x == 0 && z == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ++j;
|
||||
+
|
||||
+ Packet<?> packet = packets[j];
|
||||
+ if (packet == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final int distX = Math.abs(MCUtil.getCoordinateX(lastPosition) - (chunk.getPos().x + x));
|
||||
+ final int distZ = Math.abs(MCUtil.getCoordinateZ(lastPosition) - (chunk.getPos().z + z));
|
||||
+
|
||||
+ if (Math.max(distX, distZ) > viewDistance) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ player.connection.send(packet);
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - Fix MC-162253
|
||||
|
||||
player.trackChunk(chunk.getPos(), packets[0], packets[1]);
|
||||
DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos());
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
|
||||
|
||||
// broadcast
|
||||
Object[] backingSet = inRange.getBackingSet();
|
||||
- Packet[] chunkPackets = new Packet[2];
|
||||
+ Packet[] chunkPackets = new Packet[10];
|
||||
for (int index = 0, len = backingSet.length; index < len; ++index) {
|
||||
Object temp = backingSet[index];
|
||||
if (!(temp instanceof ServerPlayer)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -0,0 +0,0 @@ public class LevelChunkSection {
|
||||
return this.nonEmptyBlockCount == 0;
|
||||
}
|
||||
|
||||
+ public static boolean isEmpty(@Nullable LevelChunkSection chunksection) { return isEmpty(chunksection) ; } // Paper - OBFHELPER
|
||||
public static boolean isEmpty(@Nullable LevelChunkSection section) {
|
||||
return section == LevelChunk.EMPTY_SECTION || section.isEmpty();
|
||||
}
|
|
@ -18,19 +18,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- protected void removeEntitiesOnShoulder() {
|
||||
+ public void removeEntitiesOnShoulder() { // Paper - protected -> public
|
||||
if (this.timeEntitySatOnShoulder + 20L < this.level.getGameTime()) {
|
||||
// CraftBukkit start
|
||||
if (this.spawnEntityFromShoulder(this.getShoulderEntityLeft())) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
|
@ -13,8 +13,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+package com.destroystokyo.paper.entity.villager;
|
||||
+// Must have own package due to package-level constructor.
|
||||
+
|
||||
+import Reputation;
|
||||
+
|
||||
+public final class ReputationConstructor {
|
||||
+ // Abuse the package-level constructor.
|
||||
+ public static Reputation construct(int[] values) {
|
||||
|
@ -25,29 +23,24 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.
|
|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.core.SerializableUUID;
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.util.VisibleForDebug;
|
||||
|
||||
public class GossipContainer {
|
||||
|
||||
public static final int DISCARD_THRESHOLD = 2;
|
||||
- private final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newHashMap();
|
||||
+ private final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newHashMap(); public Map<UUID, GossipContainer.EntityGossips> getReputations() { return this.gossips; } // Paper - add getter for reputations
|
||||
|
||||
public GossipContainer() {}
|
||||
|
||||
@VisibleForDebug
|
||||
public Map<UUID, Object2IntMap<GossipType>> getGossipEntries() {
|
||||
@@ -0,0 +0,0 @@ public class GossipContainer {
|
||||
return k > type.max ? Math.max(type.max, left) : k;
|
||||
return i > type.max ? Math.max(type.max, left) : i;
|
||||
}
|
||||
|
||||
- static class EntityGossips {
|
||||
+ public static class EntityGossips { // Paper - make public
|
||||
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
private final Object2IntMap<GossipType> entries;
|
||||
|
||||
- private EntityGossips() {
|
||||
+ public EntityGossips() { // Paper - make public - update CraftVillager setReputation on change
|
||||
this.entries = new Object2IntOpenHashMap();
|
||||
}
|
||||
|
||||
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
|
||||
@@ -0,0 +0,0 @@ public class GossipContainer {
|
||||
public void remove(GossipType gossipType) {
|
||||
this.entries.removeInt(gossipType);
|
|
@ -8,20 +8,19 @@ diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayB
|
|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity implements
|
||||
} else if (!this.level.isClientSide) {
|
||||
List<Entity> list = this.level.getEntitiesOfClass(Entity.class, new AABB(this.getBlockPos()), TheEndGatewayBlockEntity::canEntityTeleport);
|
||||
@@ -0,0 +0,0 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
|
||||
List<Entity> list = world.getEntitiesOfClass(Entity.class, new AABB(pos), TheEndGatewayBlockEntity::canEntityTeleport);
|
||||
|
||||
- if (!list.isEmpty()) {
|
||||
- this.teleportEntity((Entity) list.get(this.level.random.nextInt(list.size())));
|
||||
+ // Paper start
|
||||
+ for (Entity entity : list) {
|
||||
+ if (entity.canChangeDimensions()) {
|
||||
+ this.teleportEntity(entity);
|
||||
+ break;
|
||||
if (!list.isEmpty()) {
|
||||
- TheEndGatewayBlockEntity.teleportEntity(world, pos, state, (Entity) list.get(world.random.nextInt(list.size())), blockEntity);
|
||||
+ // Paper start
|
||||
+ for (Entity entity : list) {
|
||||
+ if (entity.canChangeDimensions()) {
|
||||
+ TheEndGatewayBlockEntity.teleportEntity(world, pos, state, entity, blockEntity);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
if (this.age % 2400L == 0L) {
|
||||
this.triggerCooldown();
|
||||
if (blockEntity.age % 2400L == 0L) {
|
|
@ -26,13 +26,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
object2 = protochunkticklist1;
|
||||
}
|
||||
|
||||
- object = new LevelChunk(worldserver.getLevel(), chunkcoordintpair, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, j, achunksection, (chunk) -> {
|
||||
- postLoadChunk(nbttagcompound1, chunk);
|
||||
- object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, (chunk) -> {
|
||||
- ChunkSerializer.postLoadChunk(world, nbttagcompound1, chunk);
|
||||
- // CraftBukkit start - load chunk persistent data from nbt
|
||||
- net.minecraft.nbt.Tag persistentBase = nbttagcompound1.get("ChunkBukkitValues");
|
||||
- if (persistentBase instanceof CompoundTag) {
|
||||
|
@ -40,11 +40,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
- }
|
||||
- // CraftBukkit end
|
||||
- });
|
||||
+ object = new LevelChunk(worldserver.getLevel(), chunkcoordintpair, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, j, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys.
|
||||
+ object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys.
|
||||
+ createLoadEntitiesConsumer(new SafeNBTCopy(nbttagcompound1, "TileEntities", "Entities", "ChunkBukkitValues")) // Paper - move CB Chunk PDC into here
|
||||
+ );// Paper end
|
||||
} else {
|
||||
ProtoChunk protochunk = new ProtoChunk(chunkcoordintpair, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, worldserver); // Paper - Anti-Xray - Add parameter
|
||||
ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world, world); // Paper - add level
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading
|
||||
|
@ -84,7 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ private static java.util.function.Consumer<LevelChunk> createLoadEntitiesConsumer(CompoundTag nbt) {
|
||||
+ return (chunk) -> {
|
||||
+ postLoadChunk(nbt, chunk);
|
||||
+ postLoadChunk(chunk.level, nbt, chunk);
|
||||
+ // CraftBukkit start - load chunk persistent data from nbt
|
||||
+ Tag persistentBase = nbt.get("ChunkBukkitValues");
|
||||
+ if (persistentBase instanceof CompoundTag) {
|
|
@ -12,8 +12,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
@Override
|
||||
public boolean addPotionEffect(PotionEffect effect, boolean force) {
|
||||
- getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon
|
||||
- this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon
|
||||
return true;
|
||||
}
|
||||
|
|
@ -18,12 +18,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
private Map<String, ArgumentCommandNode<S, ?>> arguments = Maps.newLinkedHashMap();
|
||||
private final Predicate<S> requirement;
|
||||
@@ -0,0 +0,0 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node);
|
||||
}
|
||||
}
|
||||
-
|
||||
- children = children.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
+ //Paper - Remove manual sorting, it is no longer needed
|
||||
|
||||
- this.children = this.children.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
+ // Paper - Remove manual sorting, it is no longer needed
|
||||
}
|
||||
|
||||
public void findAmbiguities(final AmbiguityConsumer<S> consumer) {
|
|
@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -0,0 +0,0 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
return getHandle().sleepCounter;
|
||||
return this.getHandle().sleepCounter;
|
||||
}
|
||||
|
||||
+ // Paper start - Potential bed api
|
|
@ -44,8 +44,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
+ if (!iblockdata.isDestroyable()) continue; // Paper
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper
|
||||
Optional<Float> optional = this.damageCalculator.a(this, this.level, blockposition, iblockdata, fluid);
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
@@ -0,0 +0,0 @@ public class Explosion {
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ BlockState type = getBlockState(pos);
|
||||
+ if (!type.isDestroyable()) return false;
|
||||
+ // Paper end
|
||||
CraftBlockState blockstate = capturedBlockStates.get(pos);
|
||||
CraftBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
if (blockstate == null) {
|
||||
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
|
@ -115,8 +115,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
BlockState iblockdata1 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
|
||||
|
||||
world.setBlock(pos, iblockdata1, 20);
|
||||
- world.setBlockEntity(pos, MovingPistonBlock.newMovingBlockEntity((BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
|
||||
+ world.setBlockEntity(pos, MovingPistonBlock.newMovingBlockEntity((BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change, j is facing direction - copy this above
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
|
||||
world.blockUpdated(pos, iblockdata1.getBlock());
|
||||
iblockdata1.updateNeighbourShapes(world, pos, 2);
|
||||
if (this.isSticky) {
|
||||
|
@ -144,8 +144,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
@Deprecated
|
||||
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
- return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || context.getItemInHand().getItem() != this.asItem());
|
||||
+ return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || context.getItemInHand().getItem() != this.asItem()) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().abilities.instabuild)); // Paper
|
||||
- return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
|
||||
+ return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper
|
||||
}
|
||||
|
||||
@Deprecated
|
|
@ -10,32 +10,32 @@ diff --git a/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.j
|
|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightEngine.java
|
||||
@@ -0,0 +0,0 @@ public final class BlockLightEngine extends LayerLightEngine<BlockLightSectionSt
|
||||
|
||||
@@ -0,0 +0,0 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
||||
public final class BlockLightEngine extends LayerLightEngine<BlockLightSectionStorage.BlockDataLayerStorageMap, BlockLightSectionStorage> {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+ private final MutableInt mutableint = new MutableInt(); // Paper
|
||||
+ private final MutableInt mutableInt = new MutableInt(); // Paper
|
||||
|
||||
public BlockLightEngine(LightChunkGetter chunkProvider) {
|
||||
super(chunkProvider, LightLayer.BLOCK, new BlockLightSectionStorage(chunkProvider));
|
||||
@@ -0,0 +0,0 @@ public final class BlockLightEngine extends LayerLightEngine<BlockLightSectionSt
|
||||
if (enumdirection == null) {
|
||||
if (direction == null) {
|
||||
return 15;
|
||||
} else {
|
||||
- MutableInt mutableint = new MutableInt();
|
||||
- MutableInt mutableInt = new MutableInt();
|
||||
+ //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded
|
||||
BlockState iblockdata = this.getStateAndOpacity(targetId, mutableint);
|
||||
|
||||
if (mutableint.getValue() >= 15) {
|
||||
BlockState blockState = this.getStateAndOpacity(targetId, mutableInt);
|
||||
if (mutableInt.getValue() >= 15) {
|
||||
return 15;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightEngine.java
|
||||
@@ -0,0 +0,0 @@ public final class SkyLightEngine extends LayerLightEngine<SkyLightSectionStorag
|
||||
|
||||
@@ -0,0 +0,0 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
||||
public final class SkyLightEngine extends LayerLightEngine<SkyLightSectionStorage.SkyDataLayerStorageMap, SkyLightSectionStorage> {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
private static final Direction[] HORIZONTALS = new Direction[]{Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST};
|
||||
+ private final MutableInt mutableint = new MutableInt(); // Paper
|
||||
+ private final MutableInt mutableInt = new MutableInt(); // Paper
|
||||
|
||||
public SkyLightEngine(LightChunkGetter chunkProvider) {
|
||||
super(chunkProvider, LightLayer.SKY, new SkyLightSectionStorage(chunkProvider));
|
||||
|
@ -43,8 +43,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
if (level >= 15) {
|
||||
return level;
|
||||
} else {
|
||||
- MutableInt mutableint = new MutableInt();
|
||||
- MutableInt mutableInt = new MutableInt();
|
||||
+ //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded
|
||||
BlockState iblockdata = this.getStateAndOpacity(targetId, mutableint);
|
||||
|
||||
if (mutableint.getValue() >= 15) {
|
||||
BlockState blockState = this.getStateAndOpacity(targetId, mutableInt);
|
||||
if (mutableInt.getValue() >= 15) {
|
||||
return 15;
|
|
@ -8,14 +8,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
|
|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
-import net.minecraft.world.phys.Vec3;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; // Paper
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
||||
public void updatePlayer(ServerPlayer player) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
||||
|
@ -31,16 +23,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
- boolean flag = vec3d.x >= (double) (-i) && vec3d.x <= (double) i && vec3d.z >= (double) (-i) && vec3d.z <= (double) i && this.entity.broadcastToPlayer(player);
|
||||
+ boolean flag = vec3d_dx >= (double) (-i) && vec3d_dx <= (double) i && vec3d_dz >= (double) (-i) && vec3d_dz <= (double) i && this.entity.broadcastToPlayer(player); // Paper - remove allocation of Vec3D here
|
||||
|
||||
if (flag) {
|
||||
boolean flag1 = this.entity.forcedLoading;
|
||||
// CraftBukkit start - respect vanish API
|
||||
if (this.entity instanceof ServerPlayer) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
++this.teleportDelay;
|
||||
i = Mth.floor(this.entity.yRot * 256.0F / 360.0F);
|
||||
j = Mth.floor(this.entity.xRot * 256.0F / 360.0F);
|
||||
i = Mth.floor(this.entity.getYRot() * 256.0F / 360.0F);
|
||||
j = Mth.floor(this.entity.getXRot() * 256.0F / 360.0F);
|
||||
- Vec3 vec3d = this.entity.position().subtract(ClientboundMoveEntityPacket.packetToEntity(this.xp, this.yp, this.zp));
|
||||
- boolean flag1 = vec3d.lengthSqr() >= 7.62939453125E-6D;
|
||||
+ // Paper start - reduce allocation of Vec3D here
|
Loading…
Reference in a new issue