More more more more more more more more more more more more more work

This commit is contained in:
Nassim Jahnke 2021-11-24 16:07:19 +01:00 committed by MiniDigger | Martin
parent 4e81c1fe78
commit 45c36e5d0c
29 changed files with 247 additions and 269 deletions

View file

@ -0,0 +1,213 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 4 Jun 2020 02:24:49 -0400
Subject: [PATCH] Optimize Bit Operations by inlining
Inline bit operations and reduce instruction count to make these hot
operations faster
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index d38049bed6f3dc3198e687686ef4d8938c7a6b59..0dcf75c5c792650d7a5b9354222df16bcd1cfbd2 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -30,15 +30,16 @@ public class BlockPos extends Vec3i {
}).stable();
private static final Logger LOGGER = LogManager.getLogger();
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
- private static final int PACKED_X_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
- private static final int PACKED_Z_LENGTH = PACKED_X_LENGTH;
- public static final int PACKED_Y_LENGTH = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
- private static final long PACKED_X_MASK = (1L << PACKED_X_LENGTH) - 1L;
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
- private static final long PACKED_Z_MASK = (1L << PACKED_Z_LENGTH) - 1L;
- private static final int Y_OFFSET = 0;
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
+ // Paper start - static constants
+ private static final int PACKED_X_LENGTH = 26;
+ private static final int PACKED_Z_LENGTH = 26;
+ public static final int PACKED_Y_LENGTH = 12;
+ private static final long PACKED_X_MASK = 67108863;
+ private static final long PACKED_Y_MASK = 4095;
+ private static final long PACKED_Z_MASK = 67108863;
+ private static final int Z_OFFSET = 12;
+ private static final int X_OFFSET = 38;
+ // Paper end
public BlockPos(int x, int y, int z) {
super(x, y, z);
@@ -60,28 +61,29 @@ public class BlockPos extends Vec3i {
this(pos.getX(), pos.getY(), pos.getZ());
}
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction enumdirection) { return asLong(baseX + enumdirection.getStepX(), baseY + enumdirection.getStepY(), baseZ + enumdirection.getStepZ()); } // Paper
public static long offset(long value, Direction direction) {
return offset(value, direction.getStepX(), direction.getStepY(), direction.getStepZ());
}
public static long offset(long value, int x, int y, int z) {
- return asLong(getX(value) + x, getY(value) + y, getZ(value) + z);
+ return asLong((int) (value >> 38) + x, (int) ((value << 52) >> 52) + y, (int) ((value << 26) >> 38) + z); // Paper - simplify/inline
}
public static int getX(long packedPos) {
- return (int)(packedPos << 64 - X_OFFSET - PACKED_X_LENGTH >> 64 - PACKED_X_LENGTH);
+ return (int) (packedPos >> 38); // Paper - simplify/inline
}
public static int getY(long packedPos) {
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
}
public static int getZ(long packedPos) {
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_Z_LENGTH >> 64 - PACKED_Z_LENGTH);
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
}
public static BlockPos of(long packedPos) {
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
}
public long asLong() {
@@ -89,10 +91,7 @@ public class BlockPos extends Vec3i {
}
public static long asLong(int x, int y, int z) {
- long l = 0L;
- l |= ((long)x & PACKED_X_MASK) << X_OFFSET;
- l |= ((long)y & PACKED_Y_MASK) << 0;
- return l | ((long)z & PACKED_Z_MASK) << Z_OFFSET;
+ return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12); // Paper - inline constants and simplify
}
public static long getFlatIndex(long y) {
diff --git a/src/main/java/net/minecraft/core/SectionPos.java b/src/main/java/net/minecraft/core/SectionPos.java
index f9a6e9a7403d3fe8726214da981fdc599956f856..51567ca63a0d2748515d002e1f838bbb14afc162 100644
--- a/src/main/java/net/minecraft/core/SectionPos.java
+++ b/src/main/java/net/minecraft/core/SectionPos.java
@@ -38,7 +38,7 @@ public class SectionPos extends Vec3i {
}
public static SectionPos of(BlockPos pos) {
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
}
public static SectionPos of(ChunkPos chunkPos, int y) {
@@ -50,7 +50,7 @@ public class SectionPos extends Vec3i {
}
public static SectionPos of(long packed) {
- return new SectionPos(x(packed), y(packed), z(packed));
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
}
public static SectionPos bottomOf(ChunkAccess chunk) {
@@ -61,8 +61,16 @@ public class SectionPos extends Vec3i {
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
}
+ // Paper start
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction enumdirection) {
+ return (((long) ((x >> 4) + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + enumdirection.getStepY()) & 1048575L)) | (((long) ((z >> 4) + enumdirection.getStepZ()) & 4194303L) << 20);
+ }
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction enumdirection) {
+ return (((long) (x + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y) + enumdirection.getStepY()) & 1048575L)) | (((long) (z + enumdirection.getStepZ()) & 4194303L) << 20);
+ }
+ // Paper end
public static long offset(long packed, int x, int y, int z) {
- return asLong(x(packed) + x, y(packed) + y, z(packed) + z);
+ return (((long) ((int) (packed >> 42) + x) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + y) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + z) & 4194303L) << 20); // Simplify to reduce instruction count
}
public static int posToSectionCoord(double coord) {
@@ -78,10 +86,7 @@ public class SectionPos extends Vec3i {
}
public static short sectionRelativePos(BlockPos pos) {
- int i = sectionRelative(pos.getX());
- int j = sectionRelative(pos.getY());
- int k = sectionRelative(pos.getZ());
- return (short)(i << 8 | k << 4 | j << 0);
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
}
public static int sectionRelativeX(short packedLocalPos) {
@@ -144,16 +149,16 @@ public class SectionPos extends Vec3i {
return this.getZ();
}
- public int minBlockX() {
- return sectionToBlockCoord(this.x());
+ public final int minBlockX() { // Paper - make final
+ return this.getX() << 4; // Paper - inline
}
- public int minBlockY() {
- return sectionToBlockCoord(this.y());
+ public final int minBlockY() { // Paper - make final
+ return this.getY() << 4; // Paper - inline
}
- public int minBlockZ() {
- return sectionToBlockCoord(this.z());
+ public int minBlockZ() { // Paper - make final
+ return this.getZ() << 4; // Paper - inline
}
public int maxBlockX() {
@@ -169,7 +174,8 @@ public class SectionPos extends Vec3i {
}
public static long blockToSection(long blockPos) {
- return asLong(blockToSectionCoord(BlockPos.getX(blockPos)), blockToSectionCoord(BlockPos.getY(blockPos)), blockToSectionCoord(BlockPos.getZ(blockPos)));
+ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i)));
+ return (((long) (int) (blockPos >> 42) & 4194303L) << 42) | (((long) (int) ((blockPos << 52) >> 56) & 1048575L)) | (((long) (int) ((blockPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
}
public static long getZeroNode(long pos) {
@@ -193,15 +199,18 @@ public class SectionPos extends Vec3i {
return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
}
+ // Paper start
+ public static long blockPosAsSectionLong(int i, int j, int k) {
+ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20);
+ }
+ // Paper end
+
public static long asLong(int x, int y, int z) {
- long l = 0L;
- l |= ((long)x & 4194303L) << 42;
- l |= ((long)y & 1048575L) << 0;
- return l | ((long)z & 4194303L) << 20;
+ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
}
public long asLong() {
- return asLong(this.x(), this.y(), this.z());
+ return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
}
@Override
@@ -214,16 +223,11 @@ public class SectionPos extends Vec3i {
}
public static Stream<SectionPos> cube(SectionPos center, int radius) {
- int i = center.x();
- int j = center.y();
- int k = center.z();
- return betweenClosedStream(i - radius, j - radius, k - radius, i + radius, j + radius, k + radius);
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
}
public static Stream<SectionPos> aroundChunk(ChunkPos center, int radius, int minY, int maxY) {
- int i = center.x;
- int j = center.z;
- return betweenClosedStream(i - radius, minY, j - radius, i + radius, maxY - 1, j + radius);
+ return betweenClosedStream(center.x - radius, 0, center.z - radius, center.x + radius, 15, center.z + radius); // Paper - simplify/inline
}
public static Stream<SectionPos> betweenClosedStream(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {

View file

@ -0,0 +1,121 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 9 Jun 2020 03:33:03 -0400
Subject: [PATCH] Add Plugin Tickets to API Chunk Methods
Like previous versions, plugins loading chunks kept them loaded until
they garbage collected to avoid constant spamming of chunk loads
This adds tickets to a few more places so that they can be unloaded.
Additionally, this drops their ticket level to BORDER so they wont be ticking
so they will just sit inactive instead.
Using .loadChunk to keep a chunk ticking was a horrible idea for upstream
when we have TWO methods that are able to do that already in the API.
Also reduce their collection count down to a maximum of 1 second. Barely
anyone knows what chunk-gc is in bukkit.yml as its less relevant now, and
since this wasn't spigot behavior, this is safe to mostly ignore (unless someone
wants it to collect even faster, they can restore that setting back to 1 instead of 20+)
Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 835ff36cfd8c15bf11b3b6a70eb02f6c5b693b8a..b1dfd1b13652807882e057ae4fb55f9a045d1a16 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -373,7 +373,7 @@ public final class CraftServer implements Server {
this.ambientSpawn = this.configuration.getInt("spawn-limits.ambient");
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
+ TicketType.PLUGIN.timeout = Math.min(20, this.configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
this.minimumAPI = this.configuration.getString("settings.minimum-api");
this.loadIcon();
}
@@ -903,7 +903,7 @@ public final class CraftServer implements Server {
this.waterUndergroundCreatureSpawn = this.configuration.getInt("spawn-limits.water-underground-creature");
this.ambientSpawn = this.configuration.getInt("spawn-limits.ambient");
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
+ TicketType.PLUGIN.timeout = Math.min(20, configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
this.minimumAPI = this.configuration.getString("settings.minimum-api");
this.printSaveWarning = false;
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index c4d5d78064cbef9386c00dc962e0a7889ed73d9d..3bc98586792960f50ca25929f1d91fc60a8577ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -264,8 +264,21 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public Chunk getChunkAt(int x, int z) {
- return this.world.getChunkSource().getChunk(x, z, true).bukkitChunk;
+ // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it
+ net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
+ if (chunk == null) {
+ addTicket(x, z);
+ chunk = this.world.getChunkSource().getChunk(x, z, true);
+ }
+ return chunk.bukkitChunk;
+ // Paper end
+ }
+
+ // Paper start
+ private void addTicket(int x, int z) {
+ net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper
}
+ // Paper end
@Override
public Chunk getChunkAt(Block block) {
@@ -332,7 +345,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public boolean unloadChunkRequest(int x, int z) {
org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
if (this.isChunkLoaded(x, z)) {
- this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
+ this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE); // Paper
}
return true;
@@ -409,9 +422,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
// Paper start - Optimize this method
ChunkPos chunkPos = new ChunkPos(x, z);
+ ChunkAccess immediate = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); // Paper
+ if (immediate != null) return true; // Paper
if (!generate) {
- ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z);
+
+ //IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z); // Paper
if (immediate == null) {
immediate = world.getChunkSource().chunkMap.getUnloadingChunk(x, z);
}
@@ -419,7 +435,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
if (!(immediate instanceof ImposterProtoChunk) && !(immediate instanceof net.minecraft.world.level.chunk.LevelChunk)) {
return false; // not full status
}
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
world.getChunk(x, z); // make sure we're at ticket level 32 or lower
return true;
}
@@ -445,7 +461,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
// we do this so we do not re-read the chunk data on disk
}
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true);
return true;
// Paper end
@@ -1914,6 +1930,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> {
net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null);
+ if (chunk != null) addTicket(x, z); // Paper
return java.util.concurrent.CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk());
}, net.minecraft.server.MinecraftServer.getServer());
}

View file

@ -0,0 +1,297 @@
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 573cdb0897978eef8f5fc906ed4928293f4b2ab9..314b46f0becd088d26956b45981217b128d539cb 100644
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
@@ -9,7 +9,7 @@ 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
@@ -20,13 +20,13 @@ public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLigh
}
protected 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 67ff66e232592203cf8dad605ad01eabc4dded89..f357a3473682c2d37a20fb862522c67b9979402a 100644
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
@@ -9,10 +9,23 @@ 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 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
- protected DataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
- this.map = arrays;
+ // 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;
}
@@ -20,16 +33,17 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
public abstract M copy();
public void copyDataLayer(long pos) {
- this.map.put(pos, 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 i = 0; i < 2; ++i) {
if (chunkPos == this.lastSectionKeys[i]) {
@@ -38,7 +52,7 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
}
}
- DataLayer dataLayer = this.map.get(chunkPos);
+ DataLayer dataLayer = lookup.apply(chunkPos); // Paper - avoid copying light data
if (dataLayer == null) {
return null;
} else {
@@ -58,11 +72,13 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
@Nullable
public DataLayer removeLayer(long chunkPos) {
- return 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() {
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 99a758341d4b31cb1703fdce0a257f65ed602ca0..4f7b63f2cc8a69fa8efb3a84f6abc3d3dcf05b49 100644
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
@@ -28,7 +28,7 @@ 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 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;
protected final LongSet changedSections = new LongOpenHashSet();
protected final LongSet sectionsAffectedByLightUpdates = new LongOpenHashSet();
@@ -43,8 +43,8 @@ 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 dat
+ this.e_visible.disableCache(); // Paper - avoid copying light dat
}
protected boolean storingLightForSection(long sectionPos) {
@@ -53,7 +53,15 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
@Nullable
protected DataLayer getDataLayer(long sectionPos, boolean cached) {
- return this.getDataLayer((M)(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
@@ -343,9 +351,11 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
protected void swapSectionMap() {
if (!this.changedSections.isEmpty()) {
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
M dataLayerStorageMap = this.updatingSectionData.copy();
dataLayerStorageMap.disableCache();
- this.visibleSectionData = dataLayerStorageMap;
+ this.e_visible = dataLayerStorageMap; // 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 1f6ed4309f0f5e06cd2981864feaa6ea16df0350..9797254e981d08d3934f7ca8f369dd78a6ef1a48 100644
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
@@ -21,7 +21,7 @@ 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
@@ -32,8 +32,9 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
protected int getLightValue(long blockPos, boolean cached) {
long l = SectionPos.blockToSection(blockPos);
int i = SectionPos.y(l);
- SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = cached ? this.updatingSectionData : this.visibleSectionData;
- int j = skyDataLayerStorageMap.topSections.get(SectionPos.getZeroNode(l));
+ synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
+ SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.e_visible; // Paper - avoid copying light data - must be after lock acquire
+ int j = skyDataLayerStorageMap.otherData.getVisibleAsync(SectionPos.getZeroNode(l)); // Paper - avoid copying light data
if (j != skyDataLayerStorageMap.currentLowestY && i < j) {
DataLayer dataLayer = this.getDataLayer(skyDataLayerStorageMap, l);
if (dataLayer == null) {
@@ -52,6 +53,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
} else {
return cached && !this.lightOnInSection(l) ? 0 : 15;
}
+ } // Paper - avoid copying light data
}
@Override
@@ -59,13 +61,13 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
int i = SectionPos.y(sectionPos);
if ((this.updatingSectionData).currentLowestY > i) {
(this.updatingSectionData).currentLowestY = i;
- (this.updatingSectionData).topSections.defaultReturnValue((this.updatingSectionData).currentLowestY);
+ (this.updatingSectionData).otherData.queueDefaultReturnValue((this.updatingSectionData).currentLowestY); // Paper - avoid copying light data
}
long l = SectionPos.getZeroNode(sectionPos);
- int j = (this.updatingSectionData).topSections.get(l);
+ int j = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
if (j < i + 1) {
- (this.updatingSectionData).topSections.put(l, i + 1);
+ (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
if (this.columnsWithSkySources.contains(l)) {
this.queueAddSource(sectionPos);
if (j > (this.updatingSectionData).currentLowestY) {
@@ -102,19 +104,19 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
}
int i = SectionPos.y(sectionPos);
- if ((this.updatingSectionData).topSections.get(l) == i + 1) {
+ if ((this.updatingSectionData).otherData.getUpdating(l) == i + 1) { // Paper - avoid copying light data
long m;
for(m = sectionPos; !this.storingLightForSection(m) && this.hasSectionsBelow(i); m = SectionPos.offset(m, Direction.DOWN)) {
--i;
}
if (this.storingLightForSection(m)) {
- (this.updatingSectionData).topSections.put(l, i + 1);
+ (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
if (bl) {
this.queueAddSource(m);
}
} else {
- (this.updatingSectionData).topSections.remove(l);
+ (this.updatingSectionData).otherData.queueRemove(l); // Paper - avoid copying light data
}
}
@@ -128,7 +130,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
protected void enableLightSources(long columnPos, boolean enabled) {
this.runAllUpdates();
if (enabled && this.columnsWithSkySources.add(columnPos)) {
- int i = (this.updatingSectionData).topSections.get(columnPos);
+ int i = (this.updatingSectionData).otherData.getUpdating(columnPos); // Paper - avoid copying light data
if (i != (this.updatingSectionData).currentLowestY) {
long l = SectionPos.asLong(SectionPos.x(columnPos), i - 1, SectionPos.z(columnPos));
this.queueAddSource(l);
@@ -152,7 +154,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
return dataLayer;
} else {
long l = SectionPos.offset(sectionPos, Direction.UP);
- int i = (this.updatingSectionData).topSections.get(SectionPos.getZeroNode(sectionPos));
+ int i = (this.updatingSectionData).otherData.getUpdating(SectionPos.getZeroNode(sectionPos)); // Paper - avoid copying light data
if (i != (this.updatingSectionData).currentLowestY && SectionPos.y(l) < i) {
DataLayer dataLayer2;
while((dataLayer2 = this.getDataLayer(l, true)) == null) {
@@ -275,7 +277,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
protected boolean isAboveData(long sectionPos) {
long l = SectionPos.getZeroNode(sectionPos);
- int i = (this.updatingSectionData).topSections.get(l);
+ int i = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
return i == (this.updatingSectionData).currentLowestY || SectionPos.y(sectionPos) >= i;
}
@@ -286,18 +288,21 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
protected static final class SkyDataLayerStorageMap extends DataLayerStorageMap<SkyLightSectionStorage.SkyDataLayerStorageMap> {
int currentLowestY;
- final Long2IntOpenHashMap topSections;
-
- public SkyDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) {
- super(arrays);
- this.topSections = columnToTopSection;
- columnToTopSection.defaultReturnValue(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> arrays, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int columnToTopSection, int minSectionY, boolean isVisible) {
+ super(arrays, isVisible);
+ this.otherData = columnToTopSection;
+ otherData.queueDefaultReturnValue(minSectionY);
+ // Paper end
this.currentLowestY = minSectionY;
}
@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
}
}
}

View file

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 29 Jun 2020 03:26:17 -0400
Subject: [PATCH] Support old UUID format for NBT
We have stored UUID in plenty of places that did not get DFU'd
So just look for old format and load it if it exists.
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
index be2bd47a509a03e78c380cf749cd476f332ab03d..210f81e380cb38c2d5d69849e593d2fdb54e8856 100644
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
@@ -182,6 +182,12 @@ public class CompoundTag implements Tag {
}
public void putUUID(String key, UUID value) {
+ // Paper start - support old format
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ this.tags.remove(key + "Most");
+ this.tags.remove(key + "Least");
+ }
+ // Paper end
this.tags.put(key, NbtUtils.createUUID(value));
}
@@ -190,10 +196,20 @@ public class CompoundTag implements Tag {
* You must use {@link #hasUUID(String)} before or else it <b>will</b> throw an NPE.
*/
public UUID getUUID(String key) {
+ // Paper start - support old format
+ if (!contains(key, 11) && this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least"));
+ }
+ // Paper end
return NbtUtils.loadUUID(this.get(key));
}
public boolean hasUUID(String key) {
+ // Paper start - support old format
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ return true;
+ }
+ // Paper end
Tag tag = this.get(key);
return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4;
}
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
index a61f480bc2e2169969e614bccd3e143f47c1a40e..b77b806b28dfada3e84e25d868aa8a8f8556f5af 100644
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
@@ -40,14 +40,14 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public final class NbtUtils {
- private static final Comparator<ListTag> YXZ_LISTTAG_INT_COMPARATOR = Comparator.comparingInt((nbt) -> {
+ private static final Comparator<ListTag> YXZ_LISTTAG_INT_COMPARATOR = Comparator.<ListTag>comparingInt((nbt) -> { // Paper - decompile fix
return nbt.getInt(1);
}).thenComparingInt((nbt) -> {
return nbt.getInt(0);
}).thenComparingInt((nbt) -> {
return nbt.getInt(2);
});
- private static final Comparator<ListTag> YXZ_LISTTAG_DOUBLE_COMPARATOR = Comparator.comparingDouble((nbt) -> {
+ private static final Comparator<ListTag> YXZ_LISTTAG_DOUBLE_COMPARATOR = Comparator.<ListTag>comparingDouble((nbt) -> { // Paper - decompile fix
return nbt.getDouble(1);
}).thenComparingDouble((nbt) -> {
return nbt.getDouble(0);
@@ -75,6 +75,11 @@ public final class NbtUtils {
if (compound.contains("Name", 8)) {
string = compound.getString("Name");
}
+ // Paper start - support string UUID's
+ if (compound.contains("Id", 8)) {
+ uUID = UUID.fromString(compound.getString("Id"));
+ }
+ // Paper end
if (compound.hasUUID("Id")) {
uUID = compound.getUUID("Id");
@@ -495,7 +500,7 @@ public final class NbtUtils {
}
public static CompoundTag update(DataFixer fixer, DataFixTypes fixTypes, CompoundTag compound, int oldVersion, int targetVersion) {
- return fixer.update(fixTypes.getType(), new Dynamic<>(NbtOps.INSTANCE, compound), oldVersion, targetVersion).getValue();
+ return (CompoundTag) fixer.update(fixTypes.getType(), new Dynamic<>(NbtOps.INSTANCE, compound), oldVersion, targetVersion).getValue(); // Paper - decompile fix
}
public static Component toPrettyComponent(Tag element) {

View file

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 1 Jul 2020 03:12:06 -0400
Subject: [PATCH] Clean up duplicated GameProfile Properties
We had a bug where we accidently cloned properties resulting in skulls
growing to large sizes and preventing login.
This now automatically cleans up the extra properties.
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
index b77b806b28dfada3e84e25d868aa8a8f8556f5af..97c5e6c70cd9f96bc229557a425fbffbf489910e 100644
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
@@ -93,7 +93,8 @@ public final class NbtUtils {
for(String string2 : compoundTag.getAllKeys()) {
ListTag listTag = compoundTag.getList(string2, 10);
- for(int i = 0; i < listTag.size(); ++i) {
+ if (listTag.size() == 0) continue; // Paper - remove duplicate properties
+ for (int i = listTag.size() - 1; i < listTag.size(); ++i) { // Paper - remove duplicate properties
CompoundTag compoundTag2 = listTag.getCompound(i);
String string3 = compoundTag2.getString("Value");
if (compoundTag2.contains("Signature", 8)) {
diff --git a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
index 7fb2cc8d49a2d8f256f625cb99b66ef8efc3fc0e..f9980110a4614bb0206dce3dc796d9459069b750 100644
--- a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
+++ b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
@@ -53,6 +53,18 @@ public class PlayerHeadItem extends StandingAndWallBlockItem {
});
// CraftBukkit start
} else {
+ // Paper start - clean up old duplicated properties
+ CompoundTag properties = nbt.getCompound("SkullOwner").getCompound("Properties");
+ for (String key : properties.getAllKeys()) {
+ net.minecraft.nbt.ListTag values = properties.getList(key, 10);
+ if (values.size() > 1) {
+ net.minecraft.nbt.Tag texture = values.get(values.size() - 1);
+ values = new net.minecraft.nbt.ListTag();
+ values.add(texture);
+ properties.put(key, values);
+ }
+ }
+ // Paper end
net.minecraft.nbt.ListTag textures = nbt.getCompound("SkullOwner").getCompound("Properties").getList("textures", 10); // Safe due to method contracts
for (int i = 0; i < textures.size(); i++) {
if (textures.get(i) instanceof CompoundTag && !((CompoundTag) textures.get(i)).contains("Signature", 8) && ((CompoundTag) textures.get(i)).getString("Value").trim().isEmpty()) {

View file

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 1 Jul 2020 04:50:22 -0400
Subject: [PATCH] Convert legacy attributes in Item Meta
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
index 0520c45197629cbdc2777d9ae11eef572e793160..46c313d581b9af6aa0a48f97ae3cc800a88535f2 100644
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
@@ -11,6 +11,20 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
public class CraftAttributeMap implements Attributable {
private final AttributeMap handle;
+ // Paper start - convert legacy attributes
+ private static final com.google.common.collect.ImmutableMap<String, String> legacyNMS = com.google.common.collect.ImmutableMap.<String, String>builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build();
+
+ public static String convertIfNeeded(String nms) {
+ if (nms == null) {
+ return null;
+ }
+ nms = legacyNMS.getOrDefault(nms, nms);
+ if (!nms.toLowerCase().equals(nms) || nms.indexOf(' ') != -1) {
+ return null;
+ }
+ return nms;
+ }
+ // Paper end
public CraftAttributeMap(AttributeMap handle) {
this.handle = handle;
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 9d4685698ed707239b071a366eebbc4b8450683c..9ef1da08fe1b0ff8146c4931139eee9a2c6d5f12 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -480,7 +480,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier);
- String attributeName = entry.getString(ATTRIBUTES_IDENTIFIER.NBT);
+ String attributeName = CraftAttributeMap.convertIfNeeded(entry.getString(ATTRIBUTES_IDENTIFIER.NBT)); // Paper
if (attributeName == null || attributeName.isEmpty()) {
continue;
}

View file

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Mon, 29 Jun 2020 17:03:06 -0400
Subject: [PATCH] Remove some streams from structures
This showed up a lot in the spark profiler, should have a low-medium performance improvement.
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
index 1de44cc8d3e030421ad50a732bfe569f569655f0..98c4ddb261b6a17f6b8fc269c98add92688cae96 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
@@ -16,6 +16,7 @@ import net.minecraft.world.level.levelgen.feature.structures.StructureTemplatePo
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.PoolElementStructurePiece;
import net.minecraft.world.level.levelgen.structure.StructurePiece;
+import net.minecraft.world.level.levelgen.structure.StructureStart;
public class Beardifier implements NoiseChunk.NoiseFiller {
public static final int BEARD_KERNEL_RADIUS = 12;
@@ -43,7 +44,7 @@ public class Beardifier implements NoiseChunk.NoiseFiller {
this.rigids = new ObjectArrayList<>(10);
for(StructureFeature<?> structureFeature : StructureFeature.NOISE_AFFECTING_FEATURES) {
- structureAccessor.startsForFeature(SectionPos.bottomOf(chunk), structureFeature).forEach((structureStart) -> {
+ for (StructureStart<?> structureStart : structureAccessor.startsForFeature(SectionPos.bottomOf(chunk), structureFeature)) { // Paper - remove streams
for(StructurePiece structurePiece : structureStart.getPieces()) {
if (structurePiece.isCloseToChunk(chunkPos, 12)) {
if (structurePiece instanceof PoolElementStructurePiece) {
@@ -66,7 +67,7 @@ public class Beardifier implements NoiseChunk.NoiseFiller {
}
}
- });
+ } // Paper
}
this.pieceIterator = this.rigids.iterator();

View file

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Wed, 1 Jul 2020 18:01:49 -0400
Subject: [PATCH] Remove streams from classes related villager gossip
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
index 5498ec7049318dc2d10bb2ef7fbfefcf1e6e1e72..d45d14394320e87513f70a9e821fb7d179450cd9 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
@@ -8,6 +8,7 @@ import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList; // Paper
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import java.util.Arrays;
@@ -60,8 +61,21 @@ public class GossipContainer {
});
}
+ // Paper start - Remove streams from reputation
+ private List<GossipContainer.GossipEntry> decompress() {
+ List<GossipContainer.GossipEntry> list = new ObjectArrayList<>();
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : getReputations().entrySet()) {
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
+ if (cur.weightedValue() != 0)
+ list.add(cur);
+ }
+ }
+ return list;
+ }
+ // Paper end
+
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(Random random, int count) {
- List<GossipContainer.GossipEntry> list = this.unpack().collect(Collectors.toList());
+ List<GossipContainer.GossipEntry> list = decompress(); // Paper - Remove streams from reputation
if (list.isEmpty()) {
return Collections.emptyList();
} else {
@@ -154,9 +168,9 @@ public class GossipContainer {
}
- public <T> Dynamic<T> store(DynamicOps<T> dynamicOps) {
- return new Dynamic<>(dynamicOps, dynamicOps.createList(this.unpack().map((gossipEntry) -> {
- return gossipEntry.store(dynamicOps);
+ public <T> Dynamic<T> store(DynamicOps<T> dynamicops) {
+ return new Dynamic(dynamicops, dynamicops.createList(this.decompress().stream().map((reputation_b) -> {
+ return reputation_b.store(dynamicops);
}).map(Dynamic::getValue)));
}
@@ -181,11 +195,23 @@ public class GossipContainer {
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
- return this.entries.object2IntEntrySet().stream().filter((entry) -> {
- return gossipTypeFilter.test(entry.getKey());
- }).mapToInt((entry) -> {
- return entry.getIntValue() * (entry.getKey()).weight;
- }).sum();
+ // Paper start - Remove streams from reputation
+ int weight = 0;
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+ if (gossipTypeFilter.test(entry.getKey())) {
+ weight += entry.getIntValue() * entry.getKey().weight;
+ }
+ }
+ return weight;
+ }
+
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
+ List<GossipContainer.GossipEntry> list = new ObjectArrayList<>();
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
+ }
+ return list;
+ // Paper - end
}
public Stream<GossipContainer.GossipEntry> unpack(UUID target) {

View file

@ -0,0 +1,378 @@
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/ClientboundLevelChunkWithLightPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
index 079734654c0fd421561b5f9003cd318bad5787a9..a15dbd37bf810c89b751710537203d6bf1d085bc 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
@@ -2,8 +2,11 @@ package net.minecraft.network.protocol.game;
import java.util.BitSet;
import javax.annotation.Nullable;
+
+import io.netty.channel.ChannelFuture;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.lighting.LevelLightEngine;
@@ -14,6 +17,23 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
private final ClientboundLevelChunkPacketData chunkData;
private final ClientboundLightUpdatePacketData lightData;
+ // Paper start
+ @Override
+ public void onPacketDispatch(ServerPlayer player) {
+ lightData.onPacketDispatch(player);
+ }
+
+ @Override
+ public void onPacketDispatchFinish(ServerPlayer player, ChannelFuture future) {
+ lightData.onPacketDispatchFinish(player, future);
+ }
+
+ @Override
+ public boolean hasFinishListener() {
+ return true;
+ }
+ // Paper end
+
public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightProvider, @Nullable BitSet bitSet, @Nullable BitSet bitSet2, boolean bl) {
ChunkPos chunkPos = chunk.getPos();
this.x = chunkPos.x;
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 15350c301ba670cd86c83c7051c3571ff2759d8f..da46695e4d45f701a216767a048b21e289f056f6 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacket.java
@@ -2,8 +2,11 @@ package net.minecraft.network.protocol.game;
import java.util.BitSet;
import javax.annotation.Nullable;
+
+import io.netty.channel.ChannelFuture;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.lighting.LevelLightEngine;
@@ -12,6 +15,23 @@ public class ClientboundLightUpdatePacket implements Packet<ClientGamePacketList
private final int z;
private final ClientboundLightUpdatePacketData lightData;
+ // Paper start
+ @Override
+ public void onPacketDispatch(ServerPlayer player) {
+ lightData.onPacketDispatch(player);
+ }
+
+ @Override
+ public void onPacketDispatchFinish(ServerPlayer player, ChannelFuture future) {
+ lightData.onPacketDispatchFinish(player, future);
+ }
+
+ @Override
+ public boolean hasFinishListener() {
+ return true;
+ }
+ // Paper end
+
public ClientboundLightUpdatePacket(ChunkPos chunkPos, LevelLightEngine lightProvider, @Nullable BitSet skyBits, @Nullable BitSet blockBits, boolean nonEdge) {
this.x = chunkPos.x;
this.z = chunkPos.z;
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
index fe9cfb2c6e3ecbe8966bc33a16785f03f870e7cf..e887317e8fcf71740ec96d85b7ea5b819a39d468 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLightUpdatePacketData.java
@@ -19,6 +19,27 @@ public class ClientboundLightUpdatePacketData {
private final List<byte[]> skyUpdates;
private final List<byte[]> blockUpdates;
private final 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);
+
+ public void onPacketDispatch(net.minecraft.server.level.ServerPlayer player) {
+ remainingSends.incrementAndGet();
+ }
+
+ public void onPacketDispatchFinish(net.minecraft.server.level.ServerPlayer player, io.netty.channel.ChannelFuture future) {
+ if (remainingSends.decrementAndGet() <= 0) {
+ // incase of any race conditions, schedule this delayed
+ net.minecraft.server.MCUtil.scheduleTask(5, () -> {
+ if (remainingSends.get() == 0) {
+ cleaner1.run();
+ cleaner2.run();
+ }
+ }, "Light Packet Release");
+ }
+ }
+ // Paper end
public ClientboundLightUpdatePacketData(ChunkPos pos, LevelLightEngine lightProvider, @Nullable BitSet skyBits, @Nullable BitSet blockBits, boolean nonEdge) {
this.trustEdges = nonEdge;
@@ -26,8 +47,8 @@ public class ClientboundLightUpdatePacketData {
this.blockYMask = new BitSet();
this.emptySkyYMask = new BitSet();
this.emptyBlockYMask = new BitSet();
- this.skyUpdates = Lists.newArrayList();
- this.blockUpdates = Lists.newArrayList();
+ this.skyUpdates = Lists.newArrayList();this.cleaner1 = net.minecraft.server.MCUtil.registerListCleaner(this, this.skyUpdates, DataLayer::releaseBytes); // Paper
+ this.blockUpdates = Lists.newArrayList();this.cleaner2 = net.minecraft.server.MCUtil.registerListCleaner(this, this.blockUpdates, DataLayer::releaseBytes); // Paper
for(int i = 0; i < lightProvider.getLightSectionCount(); ++i) {
if (skyBits == null || skyBits.get(i)) {
@@ -72,7 +93,7 @@ public class ClientboundLightUpdatePacketData {
uninitialized.set(y);
} else {
initialized.set(y);
- nibbles.add((byte[])dataLayer.getData().clone());
+ nibbles.add((byte[])dataLayer.getCloneIfSet()); // Paper
}
}
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 81701abd11fbc4671393a76a42973f53835ca234..e8cf0088e94925934acd02ba05b9411bd7cf186e 100644
--- a/src/main/java/net/minecraft/world/level/chunk/DataLayer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/DataLayer.java
@@ -13,11 +13,65 @@ public final class DataLayer {
private static final int NIBBLE_SIZE = 4;
@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 com.destroystokyo.paper.util.pooled.PooledObjects<byte[]> BYTE_2048 = new com.destroystokyo.paper.util.pooled.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 = net.minecraft.server.MCUtil.registerCleaner(this, this.data, DataLayer::releaseBytes);
+ } else {
+ cleaner = net.minecraft.server.MCUtil.once(() -> DataLayer.releaseBytes(this.data));
+ }
+ }
public DataLayer() {}
public DataLayer(byte[] bytes) {
+ // Paper start
+ this(bytes, false);
+ }
+ public DataLayer(byte[] bytes, boolean isSafe) {
this.data = bytes;
+ if (!isSafe) this.data = getCloneIfSet(); // Paper - clone for safety
+ registerCleaner();
+ // Paper end
if (bytes.length != 2048) {
throw (IllegalArgumentException) Util.pauseInIde(new IllegalArgumentException("DataLayer should be 2048 bytes not: " + bytes.length));
}
@@ -52,7 +106,8 @@ public final class DataLayer {
private void set(int index, int value) {
if (this.data == null) {
- this.data = new byte[2048];
+ this.data = BYTE_2048.acquire(); // Paper
+ registerCleaner();// Paper
}
int k = DataLayer.getByteIndex(index);
@@ -74,13 +129,33 @@ public final 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;
}
+ @javax.annotation.Nonnull
+ public byte[] asBytesPoolSafe() {
+ if (this.data == null) {
+ this.data = BYTE_2048.acquire(); // Paper
+ registerCleaner(); // Paper
+ }
+
+ return this.data;
+ }
+ // Paper end
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 fdc80d70cf444e9b6d968764e4232f23f3ae9c37..5c21871c7bdfce191db499860725da769dc9caac 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
@@ -496,11 +496,11 @@ public class ChunkSerializer {
}
if (nibblearray != null && !nibblearray.isEmpty()) {
- nbttagcompound1.putByteArray("BlockLight", nibblearray.getData());
+ nbttagcompound1.putByteArray("BlockLight", nibblearray.asBytesPoolSafe().clone()); // Paper
}
if (nibblearray1 != null && !nibblearray1.isEmpty()) {
- nbttagcompound1.putByteArray("SkyLight", nibblearray1.getData());
+ nbttagcompound1.putByteArray("SkyLight", nibblearray1.asBytesPoolSafe().clone()); // Paper
}
if (!nbttagcompound1.isEmpty()) {
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 f357a3473682c2d37a20fb862522c67b9979402a..52682471adc13dffc0383fc4abacbd3397f3bb10 100644
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
@@ -34,7 +34,9 @@ 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) net.minecraft.server.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/LayerLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
index 4f7b63f2cc8a69fa8efb3a84f6abc3d3dcf05b49..cae559b37b5404851fa99d1d206232b5e7ab770c 100644
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
@@ -157,7 +157,7 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
protected DataLayer createDataLayer(long sectionPos) {
DataLayer dataLayer = this.queuedSections.get(sectionPos);
- return dataLayer != null ? dataLayer : new DataLayer();
+ return dataLayer != null ? dataLayer : new DataLayer().markPoolSafe(); // Paper
}
protected void clearQueuedSectionBlocks(LayerLightEngine<?, ?> storage, long sectionPos) {
@@ -318,12 +318,12 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
protected void queueSectionData(long sectionPos, @Nullable DataLayer array, boolean nonEdge) {
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 (!nonEdge) {
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 9797254e981d08d3934f7ca8f369dd78a6ef1a48..4012d87dc27c3b1096fdaa60bfdfd68f27a22da7 100644
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
@@ -163,14 +163,14 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
return repeatFirstLayer(dataLayer2);
} else {
- return new DataLayer();
+ return new DataLayer().markPoolSafe(); // Paper - mark pool use as safe (no auto cleaner)
}
}
}
private static DataLayer repeatFirstLayer(DataLayer source) {
if (source.isEmpty()) {
- return new DataLayer();
+ return new DataLayer().markPoolSafe(); // Paper - mark pool use as safe (no auto cleaner)
} else {
byte[] bs = source.getData();
byte[] cs = new byte[2048];
@@ -179,7 +179,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
System.arraycopy(bs, 0, cs, i * 128, 128);
}
- return new DataLayer(cs);
+ return new DataLayer(cs).markPoolSafe(cs); // Paper - mark pool use as safe (no auto cleaner)
}
}
@@ -197,7 +197,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
this.updatingSectionData.copyDataLayer(l);
}
- Arrays.fill(this.getDataLayer(l, true).getData(), (byte)-1);
+ Arrays.fill(this.getDataLayer(l, true).asBytesPoolSafe(), (byte)-1); // Paper
int j = SectionPos.sectionToBlockCoord(SectionPos.x(l));
int k = SectionPos.sectionToBlockCoord(SectionPos.y(l));
int m = SectionPos.sectionToBlockCoord(SectionPos.z(l));
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index 7bc1219523eeb0880493e6fb42692f1fdb30c110..187366c33c86b220581c3deac9168d6b6a2c5a3e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -339,14 +339,14 @@ public class CraftChunk implements Chunk {
sectionSkyLights[i] = CraftChunk.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] = CraftChunk.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
}
if (biome != null) {

View file

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@minidigger.me>
Date: Sat, 6 Jun 2020 18:13:42 +0200
Subject: [PATCH] Support components in ItemMeta
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 9ef1da08fe1b0ff8146c4931139eee9a2c6d5f12..bfede0c5dac43e063d465e386a080d2ffb89eb6f 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -874,11 +874,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return CraftChatMessage.fromJSONComponent(displayName);
}
+ // Paper start
+ @Override
+ public net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent() {
+ return displayName == null ? new net.md_5.bungee.api.chat.BaseComponent[0] : net.md_5.bungee.chat.ComponentSerializer.parse(displayName);
+ }
+ // Paper end
@Override
public final void setDisplayName(String name) {
this.displayName = CraftChatMessage.fromStringOrNullToJSON(name);
}
+ // Paper start
+ @Override
+ public void setDisplayNameComponent(net.md_5.bungee.api.chat.BaseComponent[] component) {
+ this.displayName = net.md_5.bungee.chat.ComponentSerializer.toString(component);
+ }
+ // Paper end
@Override
public boolean hasDisplayName() {
return this.displayName != null;
@@ -1021,6 +1033,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return this.lore == null ? null : new ArrayList<String>(Lists.transform(this.lore, CraftChatMessage::fromJSONComponent));
}
+ // Paper start
+ @Override
+ public List<net.md_5.bungee.api.chat.BaseComponent[]> getLoreComponents() {
+ return this.lore == null ? null : new ArrayList<>(this.lore.stream().map(entry ->
+ net.md_5.bungee.chat.ComponentSerializer.parse(entry)
+ ).collect(java.util.stream.Collectors.toList()));
+ }
+ // Paper end
@Override
public void setLore(List<String> lore) {
if (lore == null || lore.isEmpty()) {
@@ -1035,6 +1055,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
+ // Paper start
+ @Override
+ public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
+ if (lore == null) {
+ this.lore = null;
+ } else {
+ if (this.lore == null) {
+ safelyAdd(lore, this.lore = new ArrayList<>(lore.size()), false);
+ } else {
+ this.lore.clear();
+ safelyAdd(lore, this.lore, false);
+ }
+ }
+ }
+ // Paper end
@Override
public boolean hasCustomModelData() {
return this.customModelData != null;
@@ -1495,6 +1530,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
for (Object object : addFrom) {
+ // Paper start - support components
+ if(object instanceof net.md_5.bungee.api.chat.BaseComponent[]) {
+ addTo.add(net.md_5.bungee.chat.ComponentSerializer.toString((net.md_5.bungee.api.chat.BaseComponent[]) object));
+ } else
+ // Paper end
if (!(object instanceof String)) {
if (object != null) {
throw new IllegalArgumentException(addFrom + " cannot contain non-string " + object.getClass().getName());

View file

@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 3 Jul 2020 15:03:33 -0700
Subject: [PATCH] Improve EntityTargetLivingEntityEvent for 1.16 mobs
CraftBukkit has a bug in their implementation and is incorrectly handling forget
Also adds more target reasons for why it forgot target.
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
index 3210f8de59b8760fc48809bd451744b46119c0b0..85f8634edddd3b8a05cb3f89262032fb8c49b560 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
@@ -50,15 +50,15 @@ public class StopAttackingIfTargetInvalid<E extends Mob> extends Behavior<E> {
LivingEntity entityliving = this.getAttackTarget(entity);
if (!entity.canAttack(entityliving)) {
- this.clearAttackTarget(entity);
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID); // Paper
} else if (StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entity)) {
- this.clearAttackTarget(entity);
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET); // Paper
} else if (this.isCurrentTargetDeadOrRemoved(entity)) {
- this.clearAttackTarget(entity);
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_DIED); // Paper
} else if (this.isCurrentTargetInDifferentLevel(entity)) {
- this.clearAttackTarget(entity);
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL); // Paper
} else if (this.stopAttackingWhen.test(this.getAttackTarget(entity))) {
- this.clearAttackTarget(entity);
+ this.clearAttackTarget(entity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID); // Paper
}
}
@@ -82,17 +82,20 @@ public class StopAttackingIfTargetInvalid<E extends Mob> extends Behavior<E> {
return optional.isPresent() && !((LivingEntity) optional.get()).isAlive();
}
- protected void clearAttackTarget(E entity) {
+ protected void clearAttackTarget(E entity, EntityTargetEvent.TargetReason reason) {
// CraftBukkit start
- LivingEntity old = entity.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entity, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET);
+ // Paper start - fix this event
+ //EntityLiving old = e0.getBehaviorController().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entity, null, reason);
if (event.isCancelled()) {
return;
}
- if (event.getTarget() != null) {
- entity.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, ((CraftLivingEntity) event.getTarget()).getHandle());
+ // comment out, bad logic - bad
+ /*if (event.getTarget() != null) {
+ e0.getBehaviorController().setMemory(MemoryModuleType.ATTACK_TARGET, ((CraftLivingEntity) event.getTarget()).getHandle());
return;
- }
+ }*/
+ // Paper end
// CraftBukkit end
this.onTargetErased.accept(entity);
entity.getBrain().eraseMemory(MemoryModuleType.ATTACK_TARGET);

View file

@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Thu, 2 Jul 2020 18:11:43 -0500
Subject: [PATCH] Add entity liquid API
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 4c506e2bf241ba9d6dd53b54def09be09303664b..91e034f54deb2aa084527aaa001e48ddcc2e9cd1 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1359,7 +1359,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
return this.isInWater() || this.isInRain();
}
- @Deprecated public final boolean isInWaterOrRainOrBubble() { return isInWaterRainOrBubble(); } // Paper - OBFHELPER
public boolean isInWaterRainOrBubble() {
return this.isInWater() || this.isInRain() || this.isInBubbleColumn();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index fd811e2ba455d7e4eb618d48ca2c4983797a265c..38e38abd5302a9f8c5eb2d3d81d825cdae99d7c4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1235,5 +1235,29 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
return getHandle().spawnReason;
}
+
+ public boolean isInRain() {
+ return getHandle().isInRain();
+ }
+
+ public boolean isInBubbleColumn() {
+ return getHandle().isInBubbleColumn();
+ }
+
+ public boolean isInWaterOrRain() {
+ return getHandle().isInWaterOrRain();
+ }
+
+ public boolean isInWaterOrBubbleColumn() {
+ return getHandle().isInWaterOrBubble();
+ }
+
+ public boolean isInWaterOrRainOrBubbleColumn() {
+ return getHandle().isInWaterRainOrBubble();
+ }
+
+ public boolean isInLava() {
+ return getHandle().isInLava();
+ }
// Paper end
}

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Wed, 1 Jul 2020 11:57:40 -0500
Subject: [PATCH] Update itemstack legacy name and lore
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 3d6d48ce4b762091aeee3b4fdd28bd121aaf291b..a18cf051b374cbf294e319b619b7e2fba10a6268 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -168,6 +168,44 @@ public final class ItemStack {
list.sort((Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
} catch (Exception ignored) {}
}
+
+ private void processText() {
+ CompoundTag display = getTagElement("display");
+ if (display != null) {
+ if (display.contains("Name", 8)) {
+ String json = display.getString("Name");
+ if (json != null && json.contains("\u00A7")) {
+ try {
+ display.put("Name", convert(json));
+ } catch (JsonParseException jsonparseexception) {
+ display.remove("Name");
+ }
+ }
+ }
+ if (display.contains("Lore", 9)) {
+ ListTag list = display.getList("Lore", 8);
+ for (int index = 0; index < list.size(); index++) {
+ String json = list.getString(index);
+ if (json != null && json.contains("\u00A7")) { // Only try if it has legacy in the unparsed json
+ try {
+ list.set(index, convert(json));
+ } catch (JsonParseException e) {
+ list.set(index, net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(new TextComponent(""))));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private net.minecraft.nbt.StringTag convert(String json) {
+ Component component = Component.Serializer.fromJson(json);
+ if (component instanceof TextComponent && component.getContents().contains("\u00A7") && component.getSiblings().isEmpty()) {
+ // Only convert if the root component is a single comp with legacy in it, don't convert already normal components
+ component = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(component.getContents())[0];
+ }
+ return net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(component));
+ }
// Paper end
public ItemStack(ItemLike item) {
@@ -214,6 +252,7 @@ public final class ItemStack {
this.tag = nbttagcompound.getCompound("tag").copy();
// CraftBukkit end
this.processEnchantOrder(this.tag); // Paper
+ this.processText(); // Paper
this.getItem().verifyTagAfterLoad(this.tag);
}

View file

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wyatt Childers <wchilders@nearce.com>
Date: Fri, 3 Jul 2020 14:57:05 -0400
Subject: [PATCH] Spawn player in correct world on login
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index c2cc59f476a67224774503009439fec2ad1ec62d..0ac5ba6bc7b582d1ab02a90c9418c9b899175d93 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -196,7 +196,18 @@ public abstract class PlayerList {
}String lastKnownName = s; // Paper
// CraftBukkit end
- if (nbttagcompound != null) {
+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
+ if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) {
+ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"));
+ org.bukkit.World bWorld = org.bukkit.Bukkit.getServer().getWorld(uid);
+ if (bWorld != null) {
+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension();
+ } else {
+ resourcekey = Level.OVERWORLD;
+ }
+ } else if (nbttagcompound != null) {
+ // Vanilla migration support
+ // Paper end
DataResult dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension")));
Logger logger = PlayerList.LOGGER;

View file

@ -0,0 +1,152 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 3 Jul 2020 11:58:56 -0500
Subject: [PATCH] Add PrepareResultEvent
Adds a new event for all crafting stations that generate a result slot item
Anvil, Grindstone and Smithing now extend this event
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
index 6b9c39b85e3a21fc0073fc15c8a76c92f75d2487..b40377e882d9cc3571f527e706862e27c59b1fd0 100644
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
@@ -316,6 +316,7 @@ public class AnvilMenu extends ItemCombinerMenu {
}
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 2); // Paper
}
public int getCost() {
diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
index fc2b400c58ddbd7b012707c61d9a37363d351251..35e13a5fc23fc0cc046345059b43b37b348a3803 100644
--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -150,6 +150,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
this.setupResultSlot(itemstack, itemstack1, itemstack2);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 2); // Paper
}
private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) {
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index aa0ba9c7dcb0ee81c9081031c447eeab61d92a10..aa47947ea2f04afd3cca4b359891609025c112d5 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -159,6 +159,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
super.slotsChanged(inventory);
if (inventory == this.repairSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 2); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
index f5e52220abc5c678c090b32d83eb9644fa91ce9d..0a30b051e2fb4f081d0d579b30732aa8289c3389 100644
--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
@@ -78,6 +78,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
super.slotsChanged(inventory);
if (inventory == this.inputSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 2); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
index 5d9e444793bc9995f669596e699ace095ae3cb2b..fba8c59071847d9669943534ff8a0898b5787c28 100644
--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
@@ -198,7 +198,8 @@ public class LoomMenu extends AbstractContainerMenu {
}
this.setupResultSlot();
- this.broadcastChanges();
+ //this.c(); // Paper - done below
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper
}
public void registerUpdateListener(Runnable inventoryChangeListener) {
diff --git a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
index 92dd2ea23185bba311e184b2ac9744a423c102ea..cb3f522a586b841056c35378a49dd50bfa673f61 100644
--- a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
@@ -76,6 +76,7 @@ public class SmithingMenu extends ItemCombinerMenu {
// CraftBukkit end
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 2); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
index cdebd0cdf6eb901464cf4c16089b10ea0147b54d..221b6ffb426edc034183dbaf37de29c694874c62 100644
--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
@@ -176,6 +176,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
this.setupRecipeList(inventory, itemstack);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 1); // Paper
}
private void setupRecipeList(Container input, ItemStack stack) {
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 5fea023590fd1456a4d43c1ebc5b8c243e185631..1c0bf20f19a697e588a1d0210c181d29edbcaba7 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1556,19 +1556,44 @@ public class CraftEventFactory {
return event;
}
- public static PrepareAnvilEvent callPrepareAnvilEvent(InventoryView view, ItemStack item) {
- PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item).clone());
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
+ // Paper start - disable this method, handled below
+ public static void callPrepareAnvilEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
+ PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // disable event
event.getInventory().setItem(2, event.getResult());
- return event;
+ //return event; // Paper
}
+ // Paper end
- public static PrepareSmithingEvent callPrepareSmithingEvent(InventoryView view, ItemStack item) {
- PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item).clone());
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
+ // Paper start - disable this method, handled in callPrepareResultEvent
+ public static void callPrepareSmithingEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
+ PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // Paper - disable event
event.getInventory().setItem(2, event.getResult());
- return event;
+ //return event; // Paper
}
+ // Paper end
+
+ // Paper start - support specific overrides for prepare result
+ public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) {
+ com.destroystokyo.paper.event.inventory.PrepareResultEvent event;
+ InventoryView view = container.getBukkitView();
+ org.bukkit.inventory.ItemStack origItem = view.getTopInventory().getItem(resultSlot);
+ CraftItemStack result = origItem != null ? CraftItemStack.asCraftCopy(origItem) : null;
+ if (view.getTopInventory() instanceof org.bukkit.inventory.AnvilInventory) {
+ event = new PrepareAnvilEvent(view, result);
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.GrindstoneInventory) {
+ event = new com.destroystokyo.paper.event.inventory.PrepareGrindstoneEvent(view, result);
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.SmithingInventory) {
+ event = new PrepareSmithingEvent(view, result);
+ } else {
+ event = new com.destroystokyo.paper.event.inventory.PrepareResultEvent(view, result);
+ }
+ event.callEvent();
+ event.getInventory().setItem(resultSlot, event.getResult());
+ container.broadcastChanges();;
+ }
+ // Paper end
/**
* Mob spawner event.

View file

@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 5 Jul 2020 14:59:31 -0400
Subject: [PATCH] Don't check chunk for portal on world gen entity add
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 6c4fd054a06830947dbb4728e62dc320a51f43f0..2e02fc6d9c54bd246602b8535553dd04c4e26679 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3362,7 +3362,7 @@ public abstract class LivingEntity extends Entity {
Entity entity = this.getVehicle();
super.stopRiding(suppressCancellation); // Paper - suppress
- if (entity != null && entity != this.getVehicle() && !this.level.isClientSide) {
+ if (entity != null && entity != this.getVehicle() && !this.level.isClientSide && entity.valid) { // Paper - don't process on world gen
this.dismountVehicle(entity);
}