diff --git a/patches/unapplied/server/0253-Asynchronous-chunk-IO-and-loading.patch b/patches/server/0253-Asynchronous-chunk-IO-and-loading.patch similarity index 92% rename from patches/unapplied/server/0253-Asynchronous-chunk-IO-and-loading.patch rename to patches/server/0253-Asynchronous-chunk-IO-and-loading.patch index 2950c20b3..59bc36d94 100644 --- a/patches/unapplied/server/0253-Asynchronous-chunk-IO-and-loading.patch +++ b/patches/server/0253-Asynchronous-chunk-IO-and-loading.patch @@ -300,10 +300,10 @@ index 0000000000000000000000000000000000000000..5af0ac3d9e87c06053e65433060f1577 +} diff --git a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..ab583855d46e2adc56e503f191bdb523c2afdd91 +index 0000000000000000000000000000000000000000..7c89a96d54641904e2d4562fe28c59deecfb5444 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java -@@ -0,0 +1,606 @@ +@@ -0,0 +1,596 @@ +package com.destroystokyo.paper.io; + +import com.mojang.logging.LogUtils; @@ -846,16 +846,6 @@ index 0000000000000000000000000000000000000000..ab583855d46e2adc56e503f191bdb523 + write = this.inProgressWrite; + } + -+ // check if another process is writing -+ /*try { TODO: Can we restore this? -+ ((WorldServer)this.world).checkSession(); -+ } catch (final Exception ex) { -+ LOGGER.fatal("Couldn't save chunk; already in use by another instance of Minecraft?", ex); -+ // we don't need to set the write counter to -1 as we know at this stage there's no point in re-scheduling -+ // writes since they'll fail anyways. -+ return; -+ } -+*/ + for (;;) { + final long writeCounter; + final CompoundTag data; @@ -1476,10 +1466,10 @@ index 0000000000000000000000000000000000000000..f1b940704400266e6df186139b57ec72 +} diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c88680954 +index 0000000000000000000000000000000000000000..aaf73da45e6ba6e990a94f63eb3da0e250153053 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java -@@ -0,0 +1,138 @@ +@@ -0,0 +1,148 @@ +package com.destroystokyo.paper.io.chunk; + +import co.aikar.timings.Timing; @@ -1487,13 +1477,17 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c +import com.destroystokyo.paper.io.IOUtil; +import java.util.ArrayDeque; +import java.util.function.Consumer; ++import com.mojang.logging.LogUtils; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.storage.ChunkSerializer; ++import org.slf4j.Logger; + +public final class ChunkLoadTask extends ChunkTask { + ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ + public boolean cancelled; + + Consumer onComplete; @@ -1519,7 +1513,7 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + try { + this.executeTask(); + } catch (final Throwable ex) { -+ PaperFileIOThread.LOGGER.error("Failed to execute chunk load task: " + this.toString(), ex); ++ LOGGER.error("Failed to execute chunk load task: " + this.toString(), ex); + if (!this.hasCompleted) { + this.complete(ChunkLoadTask.createEmptyHolder()); + } @@ -1552,7 +1546,7 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + final PaperFileIOThread.ChunkData chunkData = this.chunkData; + + if (chunkData.poiData == PaperFileIOThread.FAILURE_VALUE || chunkData.chunkData == PaperFileIOThread.FAILURE_VALUE) { -+ PaperFileIOThread.LOGGER.error("Could not load chunk for task: " + this.toString() + ", file IO thread has dumped the relevant exception above"); ++ LOGGER.error("Could not load chunk for task: " + this.toString() + ", file IO thread has dumped the relevant exception above"); + this.complete(ChunkLoadTask.createEmptyHolder()); + return; + } @@ -1563,6 +1557,12 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + return; + } + ++ if (!ChunkMap.isChunkDataValid(chunkData.chunkData)) { ++ LOGGER.error("Chunk file at {} is missing level data, skipping", new ChunkPos(this.chunkX, this.chunkZ)); ++ this.complete(ChunkLoadTask.createEmptyHolder()); ++ return; ++ } ++ + final ChunkPos chunkPos = new ChunkPos(this.chunkX, this.chunkZ); + + final ChunkMap chunkManager = this.world.getChunkSource().chunkMap; @@ -1576,7 +1576,7 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + chunkData.chunkData = chunkManager.upgradeChunkTag(this.world.getTypeKey(), + chunkManager.overworldDataStorage, chunkData.chunkData, chunkManager.generator.getTypeNameForDataFixer(), chunkPos, this.world); // clone data for safety, file IO thread does not clone + } catch (final Throwable ex) { -+ PaperFileIOThread.LOGGER.error("Could not apply datafixers for chunk task: " + this.toString(), ex); ++ LOGGER.error("Could not apply datafixers for chunk task: " + this.toString(), ex); + this.complete(ChunkLoadTask.createEmptyHolder()); + return; + } @@ -1589,7 +1589,7 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + chunkHolder = ChunkSerializer.loadChunk(this.world, chunkManager.getPoiManager(), chunkPos, + chunkData.chunkData, true); + } catch (final Throwable ex) { -+ PaperFileIOThread.LOGGER.error("Could not de-serialize chunk data for task: " + this.toString(), ex); ++ LOGGER.error("Could not de-serialize chunk data for task: " + this.toString(), ex); + this.complete(ChunkLoadTask.createEmptyHolder()); + return; + } @@ -1612,7 +1612,7 @@ index 0000000000000000000000000000000000000000..79082639d9238c62c896dfc025ede92c + try { + ChunkLoadTask.this.onComplete.accept(holder); + } catch (final Throwable thr) { -+ PaperFileIOThread.LOGGER.error("Failed to complete chunk data for task: " + this.toString(), thr); ++ LOGGER.error("Failed to complete chunk data for task: " + this.toString(), thr); + } + return null; + }); @@ -2306,22 +2306,22 @@ index a5e438a834826161c52ca9db57d234d9ff80a591..b8bc1b9b8e8a33df90a963f9f9769292 @Override diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 8f5784ed4df46f3c7d4c6b4ff76ad839d436be1f..6a006f22d33491be4413fb64649ba9f6f51acac8 100644 +index 455a8d824540c66cf50b6440000b807bc1c71025..efa3c79533ac2abff8387f3bbe6e312ffc727e77 100644 --- a/src/main/java/net/minecraft/server/Main.java +++ b/src/main/java/net/minecraft/server/Main.java -@@ -250,6 +250,7 @@ public class Main { +@@ -246,6 +246,7 @@ public class Main { convertable_conversionsession.saveDataTag(iregistrycustom_dimension, savedata); */ + Class.forName(net.minecraft.world.entity.npc.VillagerTrades.class.getName());// Paper - load this sync so it won't fail later async final DedicatedServer dedicatedserver = (DedicatedServer) MinecraftServer.spin((thread) -> { - DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), minecraftsessionservice, gameprofilerepository, usercache, LoggerChunkProgressListener::new); + DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4f070d2a7ff5dfe9890e79c30911a1fe1ec9983b..311a51f91f6f4572d56dcd700c652b2690239f75 100644 +index 87970a1291b6c01bcb94a87fbbb0877a9d6b350f..2ad76722a54d4cc1a4f4799d14d0148c86e93198 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -996,7 +996,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { return true; }); @@ -2365,7 +2352,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb } else { this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); } -@@ -548,11 +550,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -565,11 +567,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider protected void tick(BooleanSupplier shouldKeepTicking) { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); @@ -2381,7 +2368,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb } gameprofilerfiller.pop(); -@@ -615,7 +621,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -632,7 +638,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ((LevelChunk) ichunkaccess).setLoaded(false); } @@ -2399,45 +2386,36 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb if (this.entitiesInLevel.remove(pos) && ichunkaccess instanceof LevelChunk) { LevelChunk chunk = (LevelChunk) ichunkaccess; -@@ -681,20 +696,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -698,32 +713,54 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private CompletableFuture> scheduleChunkLoad(ChunkPos pos) { -- return CompletableFuture.supplyAsync(() -> { +- return this.readChunk(pos).thenApply((optional) -> { +- return optional.filter((nbttagcompound) -> { +- boolean flag = ChunkMap.isChunkDataValid(nbttagcompound); + // Paper start - Async chunk io + final java.util.function.BiFunction> syncLoadComplete = (chunkHolder, ioThrowable) -> { - try (Timing ignored = this.level.timings.chunkLoad.startTimingIfSync()) { // Paper - this.level.getProfiler().incrementCounter("chunkLoad"); -- CompoundTag nbttagcompound; // Paper -- try (Timing ignored2 = this.level.timings.chunkIO.startTimingIfSync()) { // Paper start - timings -- nbttagcompound = this.readChunk(pos); -- } // Paper end -- -- if (nbttagcompound != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings -- boolean flag = nbttagcompound.contains("Status", 8); -- -- if (flag) { -- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, pos, nbttagcompound); -+ // Paper start ++ try (Timing ignored = this.level.timings.chunkLoad.startTimingIfSync()) { // Paper ++ this.level.getProfiler().incrementCounter("chunkLoad"); + if (ioThrowable != null) { -+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioThrowable); ++ return this.handleChunkLoadFailure(ioThrowable, pos); + } + this.poiManager.loadInData(pos, chunkHolder.poiData); + chunkHolder.tasks.forEach(Runnable::run); -+ // Paper end -+ if (chunkHolder.protoChunk != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings // Paper - chunk is created async -+ if (true) { -+ ProtoChunk protochunk = chunkHolder.protoChunk; - this.markPosition(pos, protochunk.getStatus().getChunkType()); - return Either.left(protochunk); - } -@@ -716,7 +732,32 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +- if (!flag) { +- ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", pos); ++ if (chunkHolder.protoChunk != null) { ++ ProtoChunk protochunk = chunkHolder.protoChunk; ++ this.markPosition(pos, protochunk.getStatus().getChunkType()); ++ return Either.left(protochunk); + } ++ } catch (Exception ex) { ++ return this.handleChunkLoadFailure(ex, pos); ++ } - this.markPositionReplaceable(pos); - return Either.left(new ProtoChunk(pos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), (BlendingData) null)); -- }, this.mainThreadExecutor); -+ // Paper start - Async chunk io +- return flag; ++ return Either.left(this.createEmptyChunk(pos)); + }; + CompletableFuture> ret = new CompletableFuture<>(); + @@ -2449,9 +2427,21 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb + } catch (Exception e) { + ret.completeExceptionally(e); + } -+ }); + }); +- }).thenApplyAsync((optional) -> { +- this.level.getProfiler().incrementCounter("chunkLoad"); +- if (optional.isPresent()) { +- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, pos, (CompoundTag) optional.get()); + }; -+ + +- this.markPosition(pos, protochunk.getStatus().getChunkType()); +- return Either.left(protochunk); // CraftBukkit - decompile error +- } else { +- return Either.left(this.createEmptyChunk(pos)); // CraftBukkit - decompile error +- } +- }, this.mainThreadExecutor).exceptionallyAsync((throwable) -> { +- return this.handleChunkLoadFailure(throwable, pos); +- }, this.mainThreadExecutor); + CompletableFuture chunkSaveFuture = this.level.asyncChunkTaskManager.getChunkSaveFuture(pos.x, pos.z); + if (chunkSaveFuture != null) { + this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z, @@ -2462,11 +2452,15 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb + com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY, chunkHolderConsumer, false); + } + return ret; -+ // Paper end ++ // Paper end - Async chunk io } - private void markPositionReplaceable(ChunkPos pos) { -@@ -931,7 +972,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +- private static boolean isChunkDataValid(CompoundTag nbt) { ++ public static boolean isChunkDataValid(CompoundTag nbt) { // Paper - async chunk loading + return nbt.contains("Status", 8); + } + +@@ -962,7 +999,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -2515,7 +2509,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb this.poiManager.flush(chunk.getPos()); if (!chunk.isUnsaved()) { return false; -@@ -943,7 +1025,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -974,7 +1052,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ChunkStatus chunkstatus = chunk.getStatus(); if (chunkstatus.getChunkType() != ChunkStatus.ChunkType.LEVELCHUNK) { @@ -2524,7 +2518,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb return false; } -@@ -953,9 +1035,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -984,9 +1062,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.level.getProfiler().incrementCounter("chunkSave"); @@ -2542,7 +2536,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); return true; } catch (Exception exception) { -@@ -964,6 +1052,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -995,6 +1079,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return false; } } @@ -2550,14 +2544,14 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb } private boolean isExistingChunkFull(ChunkPos pos) { -@@ -1097,6 +1186,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1128,6 +1213,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } + // Paper start - Asynchronous chunk io + @Nullable + @Override -+ public CompoundTag read(ChunkPos chunkcoordintpair) throws IOException { ++ public CompoundTag readSync(ChunkPos chunkcoordintpair) throws IOException { + if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) { + CompoundTag ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE + .loadChunkDataAsyncFuture(this.level, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(), @@ -2568,7 +2562,7 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb + } + return ret; + } -+ return super.read(chunkcoordintpair); ++ return super.readSync(chunkcoordintpair); + } + + @Override @@ -2583,9 +2577,9 @@ index 4206e1c96cdc7b7e324331681215f735688dd558..04b287c91acef5b9f0b73edb71fbefbb + } + // Paper end + - @Nullable - public CompoundTag readChunk(ChunkPos pos) throws IOException { - CompoundTag nbttagcompound = this.read(pos); + private CompletableFuture> readChunk(ChunkPos chunkPos) { + return this.read(chunkPos).thenApplyAsync((optional) -> { + return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java index f08089b8672454acf8c2309e850466b335248692..ab785bfc29c0b120b7c6fed2d15460c86e020291 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -2600,10 +2594,10 @@ index f08089b8672454acf8c2309e850466b335248692..ab785bfc29c0b120b7c6fed2d15460c8 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc..98f3b91605ecf81538659220354f78d4de9d203e 100644 +index f4174e4b7c296407cb1b18af77ae855978ec1b6a..7784dae8016d6ca5fbbf887316100d270710294b 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -490,10 +490,111 @@ public class ServerChunkCache extends ChunkSource { +@@ -491,10 +491,111 @@ public class ServerChunkCache extends ChunkSource { return ret; } // Paper end @@ -2715,7 +2709,7 @@ index f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc..98f3b91605ecf81538659220354f78d4 if (Thread.currentThread() != this.mainThread) { return (ChunkAccess) CompletableFuture.supplyAsync(() -> { return this.getChunk(x, z, leastStatus, create); -@@ -516,13 +617,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -517,13 +618,18 @@ public class ServerChunkCache extends ChunkSource { } gameprofilerfiller.incrementCounter("getChunkCacheMiss"); @@ -2735,7 +2729,7 @@ index f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc..98f3b91605ecf81538659220354f78d4 this.level.timings.syncChunkLoad.stopTiming(); // Paper } // Paper ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { -@@ -609,6 +715,11 @@ public class ServerChunkCache extends ChunkSource { +@@ -610,6 +716,11 @@ public class ServerChunkCache extends ChunkSource { } private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { @@ -2747,7 +2741,7 @@ index f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc..98f3b91605ecf81538659220354f78d4 ChunkPos chunkcoordintpair = new ChunkPos(chunkX, chunkZ); long k = chunkcoordintpair.toLong(); int l = 33 + ChunkStatus.getDistance(leastStatus); -@@ -1028,11 +1139,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -1033,11 +1144,12 @@ public class ServerChunkCache extends ChunkSource { // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { try { @@ -2762,10 +2756,10 @@ index f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc..98f3b91605ecf81538659220354f78d4 } finally { chunkMap.callbackExecutor.run(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index e09638b0ac68a685bf71ae3a84475bde19669b1e..b57b6f411442827ec1222fbf5bf87947e325d470 100644 +index 8c00f5d064106cca5722bdd41287ba4e99afe227..a37991c960df688f4890fd1a9d88b2e637f26101 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -310,6 +310,78 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -315,6 +315,78 @@ public class ServerLevel extends Level implements WorldGenLevel { } } } @@ -2814,7 +2808,7 @@ index e09638b0ac68a685bf71ae3a84475bde19669b1e..b57b6f411442827ec1222fbf5bf87947 + + @Override + public net.minecraft.nbt.CompoundTag readData(int x, int z) throws java.io.IOException { -+ return ServerLevel.this.getChunkSource().chunkMap.read(new ChunkPos(x, z)); ++ return ServerLevel.this.getChunkSource().chunkMap.readSync(new ChunkPos(x, z)); + } + + @Override @@ -2843,8 +2837,8 @@ index e09638b0ac68a685bf71ae3a84475bde19669b1e..b57b6f411442827ec1222fbf5bf87947 + public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager; // Paper end - // Add env and gen to constructor, WorldData -> WorldDataServer -@@ -379,6 +451,8 @@ public class ServerLevel extends Level implements WorldGenLevel { + // Add env and gen to constructor, IWorldDataServer -> WorldDataServer +@@ -395,6 +467,8 @@ public class ServerLevel extends Level implements WorldGenLevel { this.sleepStatus = new SleepStatus(); this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -2866,17 +2860,17 @@ index 0d536d72ac918fbd403397ff369d10143ee9c204..be677d437d17b74c6188ce1bd5fc6fdc private final String name; private final Comparator comparator; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0680946b445b0727ab66f201ee08cf1b5927f550..84403ae9d6900c3dfce4e4e9063a28275277fc2d 100644 +index a6add84c2bae068263b0ae9fe4bd66c569884be5..27725c9c1ad03f8f2263c027ebf6f175efb8b986 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -717,6 +717,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser - server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper +@@ -749,6 +749,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser + server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper return; } + // Paper start + String str = packet.getCommand(); int index = -1; + if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) { -+ server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper ++ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper + return; + } + // Paper end @@ -2884,22 +2878,22 @@ index 0680946b445b0727ab66f201ee08cf1b5927f550..84403ae9d6900c3dfce4e4e9063a2827 StringReader stringreader = new StringReader(packet.getCommand()); diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index 2b60fc107c309958ec3f20539b243d32765f3518..4a972b26242cf4c9d7e8f655cb1264cddad5f143 100644 +index db4fa7355b1f834d0f8a0710c1c583dded184613..ab9bb440c8e91ecb49c1e14a427d35087a87ac80 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -37,9 +37,11 @@ public class PoiManager extends SectionStorage { +@@ -40,9 +40,11 @@ public class PoiManager extends SectionStorage { public static final int VILLAGE_SECTION_SIZE = 1; private final PoiManager.DistanceTracker distanceTracker; private final LongSet loadedChunks = new LongOpenHashSet(); + private final net.minecraft.server.level.ServerLevel world; // Paper - public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) { - super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world); + public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { + super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); + this.world = (net.minecraft.server.level.ServerLevel)world; // Paper this.distanceTracker = new PoiManager.DistanceTracker(); } -@@ -173,7 +175,18 @@ public class PoiManager extends SectionStorage { +@@ -195,7 +197,18 @@ public class PoiManager extends SectionStorage { @Override public void tick(BooleanSupplier shouldKeepTicking) { @@ -2919,7 +2913,7 @@ index 2b60fc107c309958ec3f20539b243d32765f3518..4a972b26242cf4c9d7e8f655cb1264cd this.distanceTracker.runAllUpdates(); } -@@ -266,6 +279,35 @@ public class PoiManager extends SectionStorage { +@@ -288,6 +301,35 @@ public class PoiManager extends SectionStorage { } } @@ -2956,10 +2950,10 @@ index 2b60fc107c309958ec3f20539b243d32765f3518..4a972b26242cf4c9d7e8f655cb1264cd HAS_SPACE(PoiRecord::hasSpace), IS_OCCUPIED(PoiRecord::isOccupied), 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 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75afee9796f 100644 +index 864e2e0355a5fb8c1d4a5b0896ba299faf9ea534..8cc2a2c026eb44461cd94faeb64fb2151d2d3898 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 -@@ -77,7 +77,31 @@ public class ChunkSerializer { +@@ -84,7 +84,31 @@ public class ChunkSerializer { public ChunkSerializer() {} @@ -2991,18 +2985,8 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); if (!Objects.equals(chunkPos, chunkcoordintpair1)) { -@@ -94,7 +118,9 @@ public class ChunkSerializer { - LevelLightEngine lightengine = chunkproviderserver.getLightEngine(); - - if (flag) { -+ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main - lightengine.retainData(chunkPos, true); -+ }); // Paper - delay this task since we're executing off-main - } - - Registry iregistry = world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); -@@ -138,16 +164,28 @@ public class ChunkSerializer { - LevelChunkSection chunksection = new LevelChunkSection(b0, datapaletteblock, datapaletteblock1); +@@ -141,7 +165,9 @@ public class ChunkSerializer { + LevelChunkSection chunksection = new LevelChunkSection(b0, datapaletteblock, (PalettedContainer) object); // CraftBukkit - read/write achunksection[k] = chunksection; + tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main @@ -3010,39 +2994,49 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a + }); // Paper - delay this task since we're executing off-main } - if (flag) { - if (nbttagcompound1.contains("BlockLight", 7)) { + boolean flag3 = nbttagcompound1.contains("BlockLight", 7); +@@ -149,16 +175,28 @@ public class ChunkSerializer { + + if (flag3 || flag4) { + if (!flag2) { ++ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main + lightengine.retainData(chunkPos, true); ++ }); // Paper - delay this task since we're executing off-main + flag2 = true; + } + + if (flag3) { - lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("BlockLight")), true); + // Paper start - delay this task since we're executing off-main -+ DataLayer blockLight = new DataLayer(nbttagcompound1.getByteArray("BlockLight")); ++ DataLayer blockLight = new DataLayer(nbttagcompound1.getByteArray("BlockLight").clone()); + tasksToExecuteOnMain.add(() -> { -+ lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkcoordintpair1, b0), blockLight, true); ++ lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), blockLight, true); + }); + // Paper end - delay this task since we're executing off-main } - if (flag1 && nbttagcompound1.contains("SkyLight", 7)) { + if (flag4) { - lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("SkyLight")), true); + // Paper start - delay this task since we're executing off-main -+ DataLayer skyLight = new DataLayer(nbttagcompound1.getByteArray("SkyLight")); ++ DataLayer skyLight = new DataLayer(nbttagcompound1.getByteArray("SkyLight").clone()); + tasksToExecuteOnMain.add(() -> { -+ lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkcoordintpair1, b0), skyLight, true); ++ lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), skyLight, true); + }); + // Paper end - delay this task since we're executing off-mai } } } -@@ -267,7 +305,7 @@ public class ChunkSerializer { +@@ -278,7 +316,7 @@ public class ChunkSerializer { } if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) { -- return new ImposterProtoChunk((LevelChunk) object, false); -+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object, false), tasksToExecuteOnMain); // Paper - Async chunk loading +- return new ImposterProtoChunk((LevelChunk) object1, false); ++ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false), tasksToExecuteOnMain); // Paper - Async chunk loading } else { - ProtoChunk protochunk1 = (ProtoChunk) object; + ProtoChunk protochunk1 = (ProtoChunk) object1; -@@ -306,9 +344,67 @@ public class ChunkSerializer { - protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object).getMinBuildHeight())); +@@ -317,9 +355,67 @@ public class ChunkSerializer { + protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight())); } - return protochunk1; @@ -3110,8 +3104,8 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a private static void logErrors(ChunkPos chunkPos, int y, String message) { ChunkSerializer.LOGGER.error("Recoverable errors when loading section [" + chunkPos.x + ", " + y + ", " + chunkPos.z + "]: " + message); -@@ -319,6 +415,11 @@ public class ChunkSerializer { - } +@@ -336,6 +432,11 @@ public class ChunkSerializer { + // CraftBukkit end public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { + // Paper start @@ -3122,7 +3116,7 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a ChunkPos chunkcoordintpair = chunk.getPos(); CompoundTag nbttagcompound = new CompoundTag(); -@@ -326,7 +427,7 @@ public class ChunkSerializer { +@@ -343,7 +444,7 @@ public class ChunkSerializer { nbttagcompound.putInt("xPos", chunkcoordintpair.x); nbttagcompound.putInt("yPos", chunk.getMinSection()); nbttagcompound.putInt("zPos", chunkcoordintpair.z); @@ -3131,7 +3125,7 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); nbttagcompound.putString("Status", chunk.getStatus().getName()); BlendingData blendingdata = chunk.getBlendingData(); -@@ -369,8 +470,17 @@ public class ChunkSerializer { +@@ -386,8 +487,17 @@ public class ChunkSerializer { for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { int j = chunk.getSectionIndexFromSectionY(i); boolean flag1 = j >= 0 && j < achunksection.length; @@ -3151,7 +3145,7 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a if (flag1 || nibblearray != null || nibblearray1 != null) { CompoundTag nbttagcompound1 = new CompoundTag(); -@@ -408,8 +518,17 @@ public class ChunkSerializer { +@@ -425,8 +535,17 @@ public class ChunkSerializer { nbttagcompound.putBoolean("isLightOn", true); } @@ -3171,7 +3165,7 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a CompoundTag nbttagcompound2; -@@ -446,7 +565,14 @@ public class ChunkSerializer { +@@ -463,7 +582,14 @@ public class ChunkSerializer { nbttagcompound.put("CarvingMasks", nbttagcompound2); } @@ -3187,10 +3181,10 @@ index 4e5cfc508e356691a9a249013553f97e77c213b0..37a60420b993525852492fd6665fb75a CompoundTag nbttagcompound3 = new CompoundTag(); Iterator iterator1 = chunk.getHeightmaps().iterator(); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index 2d1c8d5cf8ea6739d5e9df91cc16cde72917feff..ba677f282f2c8a05d1bad88226655549a81679bb 100644 +index c56946f86565ad1ac41bb7b655c113f648d2f539..694778b5c23dbe9c8603c3483476b5252aa079bc 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -25,27 +25,38 @@ import net.minecraft.world.level.storage.DimensionDataStorage; +@@ -28,26 +28,33 @@ import net.minecraft.world.level.storage.DimensionDataStorage; public class ChunkStorage implements AutoCloseable { public static final int LAST_MONOLYTH_STRUCTURE_DATA_VERSION = 1493; @@ -3198,9 +3192,8 @@ index 2d1c8d5cf8ea6739d5e9df91cc16cde72917feff..ba677f282f2c8a05d1bad88226655549 + // Paper - nuke IO worker protected final DataFixer fixerUpper; @Nullable -- private LegacyStructureDataHandler legacyStructureHandler; + private volatile LegacyStructureDataHandler legacyStructureHandler; + // Paper start - async chunk loading -+ private volatile LegacyStructureDataHandler legacyStructureHandler; + private final Object persistentDataLock = new Object(); // Paper + public final RegionFileStorage regionFileCache; + // Paper end - async chunk loading @@ -3214,8 +3207,13 @@ index 2d1c8d5cf8ea6739d5e9df91cc16cde72917feff..ba677f282f2c8a05d1bad88226655549 + // Paper end - async chunk io } + public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) { +- return this.worker.isOldChunkAround(chunkPos, checkRadius); ++ return true; // Paper - (for now, old unoptimised behavior) TODO implement later? the chunk status that blender uses SHOULD already have this radius loaded, no need to go back for it... + } + // CraftBukkit start - private boolean check(ServerChunkCache cps, int x, int z) throws IOException { + private boolean check(ServerChunkCache cps, int x, int z) { ChunkPos pos = new ChunkPos(x, z); if (cps != null) { - com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); @@ -3225,46 +3223,53 @@ index 2d1c8d5cf8ea6739d5e9df91cc16cde72917feff..ba677f282f2c8a05d1bad88226655549 return true; } } +@@ -75,6 +82,7 @@ public class ChunkStorage implements AutoCloseable { -- CompoundTag nbt = this.read(pos); -+ // Paper start - prioritize -+ CompoundTag nbt = cps == null ? read(pos) : -+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.loadChunkData((ServerLevel)cps.getLevel(), x, z, -+ com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHER_PRIORITY, false, true).chunkData; -+ // Paper end - if (nbt != null) { - CompoundTag level = nbt.getCompound("Level"); - if (level.getBoolean("TerrainPopulated")) { -@@ -63,6 +74,7 @@ public class ChunkStorage implements AutoCloseable { - - public CompoundTag upgradeChunkTag(ResourceKey resourcekey, Supplier supplier, CompoundTag nbttagcompound, Optional>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) throws IOException { + public CompoundTag upgradeChunkTag(ResourceKey resourcekey, Supplier supplier, CompoundTag nbttagcompound, Optional>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) { // CraftBukkit end + nbttagcompound = nbttagcompound.copy(); // Paper - defensive copy, another thread might modify this int i = ChunkStorage.getVersion(nbttagcompound); // CraftBukkit start -@@ -80,11 +92,13 @@ public class ChunkStorage implements AutoCloseable { +@@ -92,9 +100,11 @@ public class ChunkStorage implements AutoCloseable { if (i < 1493) { nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, i, 1493); if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { + synchronized (this.persistentDataLock) { // Paper - Async chunk loading - if (this.legacyStructureHandler == null) { - this.legacyStructureHandler = LegacyStructureDataHandler.getLegacyStructureHandler(resourcekey, (DimensionDataStorage) supplier.get()); - } + LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier); - nbttagcompound = this.legacyStructureHandler.updateFromLegacy(nbttagcompound); + nbttagcompound = persistentstructurelegacy.updateFromLegacy(nbttagcompound); + } // Paper - Async chunk loading } } -@@ -129,26 +143,39 @@ public class ChunkStorage implements AutoCloseable { +@@ -127,7 +137,7 @@ public class ChunkStorage implements AutoCloseable { + LegacyStructureDataHandler persistentstructurelegacy = this.legacyStructureHandler; - @Nullable - public CompoundTag read(ChunkPos chunkPos) throws IOException { -- return this.worker.load(chunkPos); -+ return this.regionFileCache.read(chunkPos); // Paper - async chunk io + if (persistentstructurelegacy == null) { +- synchronized (this) { ++ synchronized (this.persistentDataLock) { // Paper - async chunk loading + persistentstructurelegacy = this.legacyStructureHandler; + if (persistentstructurelegacy == null) { + this.legacyStructureHandler = persistentstructurelegacy = LegacyStructureDataHandler.getLegacyStructureHandler(resourcekey, (DimensionDataStorage) supplier.get()); +@@ -153,26 +163,49 @@ public class ChunkStorage implements AutoCloseable { } + public CompletableFuture> read(ChunkPos chunkPos) { +- return this.worker.loadAsync(chunkPos); ++ // Paper start - async chunk io ++ try { ++ return CompletableFuture.completedFuture(Optional.ofNullable(this.readSync(chunkPos))); ++ } catch (Throwable thr) { ++ return CompletableFuture.failedFuture(thr); ++ } ++ } ++ @Nullable ++ public CompoundTag readSync(ChunkPos chunkPos) throws IOException { ++ return this.regionFileCache.read(chunkPos); + } ++ // Paper end - async chunk io + - public void write(ChunkPos chunkPos, CompoundTag nbt) { - this.worker.store(chunkPos, nbt); + // Paper start - async chunk io @@ -3456,10 +3461,10 @@ index deb852aa0fb2ad55a94d3c7ee542a0cc8013be42..40830a2b231df9bbf676d8325e76c825 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -index 4160a35ecfa1c28b88d6ebbfd14a0be1933e3b6d..3e08ff74979c78b27537403bbcaf13459e9e06b1 100644 +index 8a4750dd8f604062c4ea452f7b97b05a0c8d583a..80a7a1340908ae783a029912487485f7596bec5b 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -@@ -30,10 +30,10 @@ import net.minecraft.world.level.ChunkPos; +@@ -34,10 +34,10 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import org.slf4j.Logger; @@ -3472,52 +3477,62 @@ index 4160a35ecfa1c28b88d6ebbfd14a0be1933e3b6d..3e08ff74979c78b27537403bbcaf1345 private final Long2ObjectMap> storage = new Long2ObjectOpenHashMap<>(); public final LongLinkedOpenHashSet dirty = new LongLinkedOpenHashSet(); private final Function> codec; -@@ -43,12 +43,13 @@ public class SectionStorage implements AutoCloseable { +@@ -48,13 +48,14 @@ public class SectionStorage implements AutoCloseable { protected final LevelHeightAccessor levelHeightAccessor; - public SectionStorage(Path path, Function> codecFactory, Function factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) { -+ super(path, dsync); + public SectionStorage(Path path, Function> codecFactory, Function factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) { ++ super(path, dsync); // Paper - remove mojang I/O thread this.codec = codecFactory; this.factory = factory; this.fixerUpper = dataFixer; this.type = dataFixTypes; + this.registryAccess = dynamicRegistryManager; this.levelHeightAccessor = world; - this.worker = new IOWorker(path, dsync, path.getFileName().toString()); + // Paper - remove mojang I/O thread } protected void tick(BooleanSupplier shouldKeepTicking) { -@@ -110,13 +111,18 @@ public class SectionStorage implements AutoCloseable { +@@ -122,15 +123,20 @@ public class SectionStorage implements AutoCloseable { } - private void readColumn(ChunkPos chunkPos) { -- this.readColumn(chunkPos, NbtOps.INSTANCE, this.tryRead(chunkPos)); -+ // Paper start - expose function to load in data -+ this.loadInData(chunkPos, this.tryRead(chunkPos)); + private CompletableFuture> tryRead(ChunkPos pos) { +- return this.worker.loadAsync(pos).exceptionally((throwable) -> { +- if (throwable instanceof IOException iOException) { +- LOGGER.error("Error reading chunk {} data from disk", pos, iOException); +- return Optional.empty(); +- } else { +- throw new CompletionException(throwable); +- } +- }); ++ // Paper start - async chunk io ++ try { ++ return CompletableFuture.completedFuture(Optional.ofNullable(this.read(pos))); ++ } catch (Throwable thr) { ++ return CompletableFuture.failedFuture(thr); ++ } ++ // Paper end - async chunk io + } ++ ++ // Paper start - async chunk io + public void loadInData(ChunkPos chunkPos, CompoundTag compound) { + this.readColumn(chunkPos, NbtOps.INSTANCE, compound); -+ // Paper end - expose function to load in data } ++ // Paper end - aync chnnk i - @Nullable - private CompoundTag tryRead(ChunkPos pos) { - try { -- return this.worker.load(pos); -+ return this.read(pos); // Paper - nuke IOWorker - } catch (IOException var3) { - LOGGER.error("Error reading chunk {} data from disk", pos, var3); - return null; -@@ -160,13 +166,26 @@ public class SectionStorage implements AutoCloseable { - Dynamic dynamic = this.writeColumn(chunkPos, NbtOps.INSTANCE); + private void readColumn(ChunkPos pos, DynamicOps ops, @Nullable T data) { + if (data == null) { +@@ -170,7 +176,7 @@ public class SectionStorage implements AutoCloseable { + Dynamic dynamic = this.writeColumn(pos, registryOps); Tag tag = dynamic.getValue(); if (tag instanceof CompoundTag) { -- this.worker.store(chunkPos, (CompoundTag)tag); -+ try { this.write(chunkPos, (CompoundTag)tag); } catch (IOException ioexception) { SectionStorage.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker +- this.worker.store(pos, (CompoundTag)tag); ++ try { this.write(pos, (CompoundTag)tag); } catch (IOException ioexception) { SectionStorage.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker } else { LOGGER.error("Expected compound tag, got {}", (Object)tag); } - +@@ -198,6 +204,20 @@ public class SectionStorage implements AutoCloseable { + return new Dynamic<>(ops, ops.createMap(ImmutableMap.of(ops.createString("Sections"), ops.createMap(map), ops.createString("DataVersion"), ops.createInt(SharedConstants.getCurrentVersion().getWorldVersion())))); } + // Paper start - internal get data function, copied from above @@ -3533,10 +3548,11 @@ index 4160a35ecfa1c28b88d6ebbfd14a0be1933e3b6d..3e08ff74979c78b27537403bbcaf1345 + return null; + } + // Paper end - private Dynamic writeColumn(ChunkPos chunkPos, DynamicOps dynamicOps) { - Map map = Maps.newHashMap(); - -@@ -223,6 +242,23 @@ public class SectionStorage implements AutoCloseable { ++ + private static long getKey(ChunkPos chunkPos, int y) { + return SectionPos.asLong(chunkPos.x, y, chunkPos.z); + } +@@ -233,6 +253,23 @@ public class SectionStorage implements AutoCloseable { @Override public void close() throws IOException { @@ -3562,10 +3578,10 @@ index 4160a35ecfa1c28b88d6ebbfd14a0be1933e3b6d..3e08ff74979c78b27537403bbcaf1345 + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 9ba1b86cb576ae4b1a01c53dac49b836f79c62ea..3c4f06c9446dd769999e8f52bd43709cdd5cf9b0 100644 +index a21b96ceca273543e23cdc62aa3acff314467f85..5eb8aad09826c94defcc8c42bc395e6a617f60e6 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1876,6 +1876,34 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1877,6 +1877,34 @@ public class CraftWorld extends CraftRegionAccessor implements World { public DragonBattle getEnderDragonBattle() { return (this.getHandle().dragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().dragonFight()); } @@ -3601,18 +3617,10 @@ index 9ba1b86cb576ae4b1a01c53dac49b836f79c62ea..3c4f06c9446dd769999e8f52bd43709c @Override public PersistentDataContainer getPersistentDataContainer() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 20c753f5819652430e4fe7b9e3fd4a4b16fc3647..8e6ae581c714c1fec6b1cdc1c26b83772573ab27 100644 +index 1adc2ad30b174465989c628c4306df011356c93c..c752f70b0c05cb7acd8c7cfce92ab05af560671a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -15,6 +15,7 @@ import net.minecraft.network.chat.Component; - import net.minecraft.server.level.ChunkMap; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.TicketType; - import net.minecraft.world.damagesource.DamageSource; - import net.minecraft.world.entity.AreaEffectCloud; - import net.minecraft.world.entity.Entity; -@@ -521,6 +522,37 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -533,6 +533,37 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { this.entity.setYHeadRot(yaw); } diff --git a/patches/unapplied/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch b/patches/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch similarity index 96% rename from patches/unapplied/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch rename to patches/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch index 538ab0ac4..2994f0d95 100644 --- a/patches/unapplied/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch +++ b/patches/server/0254-Add-ray-tracing-methods-to-LivingEntity.patch @@ -28,10 +28,10 @@ index 0cf818fceddd76e7704fdc6625456787856b2815..ccdee183f02ab55723e16f41efce55dc switch (enumDirection) { case DOWN: diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 1cf4c80d03b8843be9abbb72baba8cde0bbd329b..c02bca930f1504ff0f294bd60c488c41b05aecdf 100644 +index eb9d45fd330ad4ed194ed593ca15ed579ddb2c54..62e8d61f70c315f346f1f365c874c27e0bdd529c 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3679,6 +3679,23 @@ public abstract class LivingEntity extends Entity { +@@ -3718,6 +3718,23 @@ public abstract class LivingEntity extends Entity { } // Paper start diff --git a/patches/unapplied/server/0255-Expose-attack-cooldown-methods-for-Player.patch b/patches/server/0255-Expose-attack-cooldown-methods-for-Player.patch similarity index 86% rename from patches/unapplied/server/0255-Expose-attack-cooldown-methods-for-Player.patch rename to patches/server/0255-Expose-attack-cooldown-methods-for-Player.patch index 565f7d82e..3302cbbaf 100644 --- a/patches/unapplied/server/0255-Expose-attack-cooldown-methods-for-Player.patch +++ b/patches/server/0255-Expose-attack-cooldown-methods-for-Player.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Expose attack cooldown methods for Player diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ca1a812ee0ac316299004437e86d696f9bacb350..7601453e17132b29b99eabbb66f600a57bd512a9 100644 +index 331dd7f22d71719e7598b076246b9dcaffa77562..72caa9a230318ce87364446682a4ced67ec2d2c5 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2495,6 +2495,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2493,6 +2493,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this.adventure$pointers; } diff --git a/patches/unapplied/server/0256-Improve-death-events.patch b/patches/server/0256-Improve-death-events.patch similarity index 88% rename from patches/unapplied/server/0256-Improve-death-events.patch rename to patches/server/0256-Improve-death-events.patch index fd2c2c081..a5f394a30 100644 --- a/patches/unapplied/server/0256-Improve-death-events.patch +++ b/patches/server/0256-Improve-death-events.patch @@ -19,10 +19,10 @@ maybe more (please check patch overrides for drops for more): - players, armor stands, foxes, chested donkeys/llamas diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 495acba272889277768a6673d7b2b2b691d93477..919fcca5d23002d1637c1f03f2255c74c6df7f5a 100644 +index 9e010074c289abd939cd9743307579bee7583b5c..db5f63dcb0b44a5ba0a1eae892415af73746d7e1 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -221,6 +221,10 @@ public class ServerPlayer extends Player { +@@ -228,6 +228,10 @@ public class ServerPlayer extends Player { public int latency; public boolean wonGame; private int containerUpdateDelay; // Paper @@ -33,7 +33,7 @@ index 495acba272889277768a6673d7b2b2b691d93477..919fcca5d23002d1637c1f03f2255c74 // CraftBukkit start public String displayName; -@@ -790,6 +794,15 @@ public class ServerPlayer extends Player { +@@ -798,6 +802,15 @@ public class ServerPlayer extends Player { String deathmessage = defaultMessage.getString(); this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, PaperAdventure.asAdventure(defaultMessage), defaultMessage.getString(), keepInventory); // Paper - Adventure @@ -49,7 +49,7 @@ index 495acba272889277768a6673d7b2b2b691d93477..919fcca5d23002d1637c1f03f2255c74 // SPIGOT-943 - only call if they have an inventory open if (this.containerMenu != this.inventoryMenu) { -@@ -937,8 +950,17 @@ public class ServerPlayer extends Player { +@@ -946,8 +959,17 @@ public class ServerPlayer extends Player { } } } @@ -70,10 +70,10 @@ index 495acba272889277768a6673d7b2b2b691d93477..919fcca5d23002d1637c1f03f2255c74 } } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee56257a32a9b2 100644 +index 62e8d61f70c315f346f1f365c874c27e0bdd529c..260f51f6a3d3a6da4ff9a0a3a67193abccb31e56 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -260,6 +260,7 @@ public abstract class LivingEntity extends Entity { +@@ -262,6 +262,7 @@ public abstract class LivingEntity extends Entity { public Set collidableExemptions = new HashSet<>(); public boolean bukkitPickUpLoot; public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper @@ -81,7 +81,7 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 @Override public float getBukkitYaw() { -@@ -1442,13 +1443,12 @@ public abstract class LivingEntity extends Entity { +@@ -1465,13 +1466,12 @@ public abstract class LivingEntity extends Entity { if (knockbackCancelled) this.level.broadcastEntityEvent(this, (byte) 2); // Paper - Disable explosion knockback if (this.isDeadOrDying()) { if (!this.checkTotemDeathProtection(source)) { @@ -99,16 +99,16 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 } } else if (flag1) { this.playHurtSound(source); -@@ -1597,7 +1597,7 @@ public abstract class LivingEntity extends Entity { +@@ -1620,7 +1620,7 @@ public abstract class LivingEntity extends Entity { if (!this.isRemoved() && !this.dead) { - Entity entity = source.getEntity(); + Entity entity = damageSource.getEntity(); LivingEntity entityliving = this.getKillCredit(); - + /* // Paper - move down to make death event cancellable - this is the awardKillScore below if (this.deathScore >= 0 && entityliving != null) { - entityliving.awardKillScore(this, this.deathScore, source); + entityliving.awardKillScore(this, this.deathScore, damageSource); } -@@ -1609,20 +1609,54 @@ public abstract class LivingEntity extends Entity { +@@ -1632,20 +1632,53 @@ public abstract class LivingEntity extends Entity { if (!this.level.isClientSide && this.hasCustomName()) { if (org.spigotmc.SpigotConfig.logNamedDeaths) LivingEntity.LOGGER.info("Named entity {} died: {}", this, this.getCombatTracker().getDeathMessage().getString()); // Spigot } @@ -118,17 +118,14 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 - this.getCombatTracker().recheckStatus(); + // Paper - moved into if below if (this.level instanceof ServerLevel) { - if (entity != null) { -- entity.killed((ServerLevel) this.level, this); -+ // Paper - move below into if for onKill - } - -- this.dropAllDeathLoot(source); +- if (entity == null || entity.wasKilled((ServerLevel) this.level, this)) { ++ // Paper - move below into if for onKill ++ + // Paper start -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(source); ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource); + if (deathEvent == null || !deathEvent.isCancelled()) { + if (this.deathScore >= 0 && entityliving != null) { -+ entityliving.awardKillScore(this, this.deathScore, source); ++ entityliving.awardKillScore(this, this.deathScore, damageSource); + } + // Paper start - clear equipment if event is not cancelled + if (this instanceof Mob) { @@ -149,24 +146,29 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 + + this.getCombatTracker().recheckStatus(); + if (entity != null) { -+ entity.killed((ServerLevel) this.level, this); ++ entity.wasKilled((ServerLevel) this.level, this); + } + this.gameEvent(GameEvent.ENTITY_DIE); +- this.dropAllDeathLoot(damageSource); +- this.createWitherRose(entityliving); + } else { + this.dead = false; + this.setHealth((float) deathEvent.getReviveHealth()); -+ } + } +- +- this.level.broadcastEntityEvent(this, (byte) 3); + // Paper end - this.createWitherRose(entityliving); ++ this.createWitherRose(entityliving); } + if (this.dead) { // Paper - this.level.broadcastEntityEvent(this, (byte) 3); ++ this.level.broadcastEntityEvent(this, (byte) 3); this.setPose(Pose.DYING); + } // Paper } } -@@ -1630,7 +1664,7 @@ public abstract class LivingEntity extends Entity { +@@ -1653,7 +1686,7 @@ public abstract class LivingEntity extends Entity { if (!this.level.isClientSide) { boolean flag = false; @@ -175,7 +177,7 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 if (this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { BlockPos blockposition = this.blockPosition(); BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); -@@ -1659,7 +1693,11 @@ public abstract class LivingEntity extends Entity { +@@ -1682,7 +1715,11 @@ public abstract class LivingEntity extends Entity { } } @@ -188,7 +190,7 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 Entity entity = source.getEntity(); int i; -@@ -1674,18 +1712,27 @@ public abstract class LivingEntity extends Entity { +@@ -1697,18 +1734,27 @@ public abstract class LivingEntity extends Entity { this.dropEquipment(); // CraftBukkit - from below if (this.shouldDropLoot() && this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { this.dropFromLootTable(source, flag); @@ -218,10 +220,10 @@ index c02bca930f1504ff0f294bd60c488c41b05aecdf..681ca7f6049016f7661215e4d5ee5625 // CraftBukkit start public int getExpReward() { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index c9d566750d3dc4660f17d3191637e256720bbe52..affa1d906beb49cf599a467d582144d9407b2e0e 100644 +index 2bec7466fcd61731d4da1cefdea8c375def0be12..dc5cb767c91252b1049c76841cbe14b29287572c 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1001,7 +1001,13 @@ public abstract class Mob extends LivingEntity { +@@ -1012,7 +1012,13 @@ public abstract class Mob extends LivingEntity { } this.spawnAtLocation(itemstack); @@ -236,10 +238,10 @@ index c9d566750d3dc4660f17d3191637e256720bbe52..affa1d906beb49cf599a467d582144d9 } diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 6ffd1aec3563e92f5d5975d3fb4d3d89feec1416..e36c01533dc85541c91f7a55690fae46f770b516 100644 +index fb3b42611d8386b110ea079094d5d50fefceac1a..8f294f10aca2df007830b12da0506f7614206a89 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Fox.java +++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -698,15 +698,25 @@ public class Fox extends Animal { +@@ -700,15 +700,25 @@ public class Fox extends Animal { } @Override @@ -269,10 +271,10 @@ index 6ffd1aec3563e92f5d5975d3fb4d3d89feec1416..e36c01533dc85541c91f7a55690fae46 public static boolean isPathClear(Fox fox, LivingEntity chasedEntity) { diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java -index 224eca7d20cf4b890a6bc1b314d566e02e716762..7281eb294ddd178ba742088d3c61bf3d529ff0c4 100644 +index c47884bab387647d99ed842b46f1c078ef9b6995..a3f3e06679cef10f50346e9cc6672ec91c6f04a6 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java -@@ -68,11 +68,19 @@ public abstract class AbstractChestedHorse extends AbstractHorse { +@@ -69,11 +69,19 @@ public abstract class AbstractChestedHorse extends AbstractHorse { this.spawnAtLocation(Blocks.CHEST); } @@ -294,10 +296,10 @@ index 224eca7d20cf4b890a6bc1b314d566e02e716762..7281eb294ddd178ba742088d3c61bf3d public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index 91cf7728aee475cb36f2c02bbfb7e3d2e0d00576..a3a900d10440ed5ebe24370a77ccb6cad911cfc9 100644 +index b2a64c75a9ef3ad2f1129cd7dc59d713c4768539..a885e4a63f9ffb70b305b6d8c0f0dedf5b3cbeef 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -754,7 +754,8 @@ public class ArmorStand extends LivingEntity { +@@ -752,7 +752,8 @@ public class ArmorStand extends LivingEntity { @Override public void kill() { @@ -305,13 +307,13 @@ index 91cf7728aee475cb36f2c02bbfb7e3d2e0d00576..a3a900d10440ed5ebe24370a77ccb6ca + org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event // Paper - make cancellable + if (event.isCancelled()) return; // Paper - make cancellable this.remove(Entity.RemovalReason.KILLED); + this.gameEvent(GameEvent.ENTITY_DIE); } - diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 7601453e17132b29b99eabbb66f600a57bd512a9..2922c1b4d2e5a18c7c54be4a3a81782241f67367 100644 +index 72caa9a230318ce87364446682a4ced67ec2d2c5..12d15eacf915a38ce9af8382d22f25a3b4fef751 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2058,7 +2058,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2056,7 +2056,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } public void sendHealthUpdate() { diff --git a/patches/unapplied/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch b/patches/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch similarity index 83% rename from patches/unapplied/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch rename to patches/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch index d8349a70c..9e9c58de9 100644 --- a/patches/unapplied/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch +++ b/patches/server/0257-Allow-chests-to-be-placed-with-NBT-data.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Allow chests to be placed with NBT data diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 65189af7acc3e60fc7f2bfe82128ada981bf1271..f1289d7251783c5203828c2b76785dd22c7e2992 100644 +index a2426b71830d5c39fff04cedaa7569abe332f92a..59723d34be0517d3d747598f275f4f2829c258a3 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java +++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -348,6 +348,7 @@ public final class ItemStack { +@@ -362,6 +362,7 @@ public final class ItemStack { enuminteractionresult = InteractionResult.FAIL; // cancel placement // PAIL: Remove this when MC-99075 fixed placeEvent.getPlayer().updateInventory(); @@ -17,10 +17,10 @@ index 65189af7acc3e60fc7f2bfe82128ada981bf1271..f1289d7251783c5203828c2b76785dd2 world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 for (BlockState blockstate : blocks) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index ff8e05038c1c2fa630f2d4efe460a313d209da8d..e56f7d76b501dab7d549efd2fafd514a9625c24e 100644 +index d4f5af759bbb6208432ad7b5002af5455dc7958c..a71414397bd45ee7bcacfeef0041d80dfa25f114 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -238,7 +238,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement +@@ -237,7 +237,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement // CraftBukkit start @Override public boolean onlyOpCanSetNbt() { diff --git a/patches/unapplied/server/0258-Mob-Pathfinding-API.patch b/patches/server/0258-Mob-Pathfinding-API.patch similarity index 100% rename from patches/unapplied/server/0258-Mob-Pathfinding-API.patch rename to patches/server/0258-Mob-Pathfinding-API.patch diff --git a/patches/unapplied/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch b/patches/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch similarity index 99% rename from patches/unapplied/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch rename to patches/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch index 111c74cac..3f7c07092 100644 --- a/patches/unapplied/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch +++ b/patches/server/0259-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Implement an API for CanPlaceOn and CanDestroy NBT values diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index d5df6fc244ab82b94196be9c436ba77020716df2..ac779f3cedb7ddd74f39a18f08afbcdad8cd13b1 100644 +index 01ceb8de8411193fa407bf19bbd25a4bf44765d3..c4a87a98af866b9831ff5da2c574b0370d639d52 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -83,6 +83,12 @@ import org.bukkit.persistence.PersistentDataContainer; diff --git a/patches/unapplied/server/0260-Prevent-chunk-loading-from-Fluid-Flowing.patch b/patches/server/0260-Prevent-chunk-loading-from-Fluid-Flowing.patch similarity index 100% rename from patches/unapplied/server/0260-Prevent-chunk-loading-from-Fluid-Flowing.patch rename to patches/server/0260-Prevent-chunk-loading-from-Fluid-Flowing.patch diff --git a/patches/unapplied/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch b/patches/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch similarity index 96% rename from patches/unapplied/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch rename to patches/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch index ded712fe9..12a3938c2 100644 --- a/patches/unapplied/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch +++ b/patches/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Prevent Mob AI Rules from Loading Chunks diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 4a67daa7ee7f8c0fcb37c2a0fdba158485343a1f..027ef44d46cb1dda19c5c239f6970c90285fb961 100644 +index 238c4225bbd4b12bd866603c6eb33182bc9dc89f..bd0cbf4390fc7d00b4bd5008cdf8f6f49df4f69b 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java @@ -133,7 +133,9 @@ public class RemoveBlockGoal extends MoveToBlockGoal { diff --git a/patches/unapplied/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch b/patches/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch similarity index 87% rename from patches/unapplied/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch rename to patches/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch index 150427b2a..7c943a734 100644 --- a/patches/unapplied/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch +++ b/patches/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch @@ -6,11 +6,11 @@ Subject: [PATCH] Prevent mob spawning from loading/generating chunks also prevents if out of world border bounds diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index a62c5f48e54d10eb416111448cd250704ef594a0..1603657d75334c0425e737cd661a4ed724333206 100644 +index ec6fcfc94b34d2b523c011b197e6484d13517c36..31b330e140d71d9b017e68eab531a59d4f2ed9a2 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -168,9 +168,9 @@ public final class NaturalSpawner { - StructureFeatureManager structuremanager = world.structureFeatureManager(); +@@ -169,9 +169,9 @@ public final class NaturalSpawner { + StructureManager structuremanager = world.structureManager(); ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator(); int i = pos.getY(); - BlockState iblockdata = chunk.getBlockState(pos); @@ -21,7 +21,7 @@ index a62c5f48e54d10eb416111448cd250704ef594a0..1603657d75334c0425e737cd661a4ed7 BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); int j = 0; int k = 0; -@@ -199,7 +199,7 @@ public final class NaturalSpawner { +@@ -200,7 +200,7 @@ public final class NaturalSpawner { if (entityhuman != null) { double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); diff --git a/patches/unapplied/server/0263-Implement-furnace-cook-speed-multiplier-API.patch b/patches/server/0263-Implement-furnace-cook-speed-multiplier-API.patch similarity index 69% rename from patches/unapplied/server/0263-Implement-furnace-cook-speed-multiplier-API.patch rename to patches/server/0263-Implement-furnace-cook-speed-multiplier-API.patch index d75b53a87..4fa61122b 100644 --- a/patches/unapplied/server/0263-Implement-furnace-cook-speed-multiplier-API.patch +++ b/patches/server/0263-Implement-furnace-cook-speed-multiplier-API.patch @@ -11,10 +11,10 @@ to the nearest Integer when updating its current cook time. Modified by: Eric Su diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index c3c53a34f645a834256c31951e465ae33aa1a9ff..635d47d4bea679e96736ef891c40f57488cbc6a1 100644 +index bbccb2f97ee88fe43af4eec30fbb2ecea1ebb1b4..a46b2ab813d17b56761e562a49c3cd4112b9def7 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -75,6 +75,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -76,11 +76,13 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit protected NonNullList items; public int litTime; int litDuration; @@ -22,7 +22,21 @@ index c3c53a34f645a834256c31951e465ae33aa1a9ff..635d47d4bea679e96736ef891c40f574 public int cookingProgress; public int cookingTotalTime; protected final ContainerData dataAccess; -@@ -281,6 +282,11 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + public final Object2IntOpenHashMap recipesUsed; + private final RecipeManager.CachedCheck quickCheck; ++ public final RecipeType recipeType; // Paper + + protected AbstractFurnaceBlockEntity(BlockEntityType blockEntityType, BlockPos pos, BlockState state, RecipeType recipeType) { + super(blockEntityType, pos, state); +@@ -127,6 +129,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + }; + this.recipesUsed = new Object2IntOpenHashMap(); + this.quickCheck = RecipeManager.createCheck((RecipeType) recipeType); // CraftBukkit - decompile error // Eclipse fail ++ this.recipeType = recipeType; // Paper + } + + public static Map getFuel() { +@@ -285,6 +288,11 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit this.recipesUsed.put(new ResourceLocation(s), nbttagcompound1.getInt(s)); } @@ -34,7 +48,7 @@ index c3c53a34f645a834256c31951e465ae33aa1a9ff..635d47d4bea679e96736ef891c40f574 } @Override -@@ -289,6 +295,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -293,6 +301,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit nbt.putShort("BurnTime", (short) this.litTime); nbt.putShort("CookTime", (short) this.cookingProgress); nbt.putShort("CookTimeTotal", (short) this.cookingTotalTime); @@ -42,7 +56,7 @@ index c3c53a34f645a834256c31951e465ae33aa1a9ff..635d47d4bea679e96736ef891c40f574 ContainerHelper.saveAllItems(nbt, this.items); CompoundTag nbttagcompound1 = new CompoundTag(); -@@ -351,7 +358,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -364,7 +373,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit CraftItemStack source = CraftItemStack.asCraftMirror(blockEntity.items.get(0)); CookingRecipe recipe = (CookingRecipe) irecipe.toBukkitRecipe(); @@ -51,40 +65,40 @@ index c3c53a34f645a834256c31951e465ae33aa1a9ff..635d47d4bea679e96736ef891c40f574 world.getCraftServer().getPluginManager().callEvent(event); blockEntity.cookingTotalTime = event.getTotalCookTime(); -@@ -359,9 +366,9 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -372,9 +381,9 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit // CraftBukkit end ++blockEntity.cookingProgress; - if (blockEntity.cookingProgress == blockEntity.cookingTotalTime) { + if (blockEntity.cookingProgress >= blockEntity.cookingTotalTime) { // Paper - cook speed multiplier API blockEntity.cookingProgress = 0; -- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity); -+ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier); +- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity); ++ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier); // Paper if (AbstractFurnaceBlockEntity.burn(blockEntity.level, blockEntity.worldPosition, irecipe, blockEntity.items, i)) { // CraftBukkit blockEntity.setRecipeUsed(irecipe); } -@@ -461,9 +468,13 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -474,9 +483,13 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit } } -- private static int getTotalCookTime(Level world, RecipeType recipeType, Container inventory) { -- return (world != null) ? (Integer) world.getRecipeManager().getRecipeFor((RecipeType) recipeType, inventory, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : 200; // CraftBukkit - SPIGOT-4302 // Eclipse fail -+ // Paper begin - Expose this function so CraftFurnace can correctly scale the total cooking time to a new multiplier -+ public static int getTotalCookTime(@Nullable Level world, RecipeType recipeType, Container inventory, final double cookSpeedMultiplier) { +- private static int getTotalCookTime(Level world, AbstractFurnaceBlockEntity furnace) { +- return (world != null) ? (Integer) furnace.quickCheck.getRecipeFor(furnace, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : 200; // CraftBukkit - SPIGOT-4302 ++ // Paper start ++ public static int getTotalCookTime(Level world, RecipeType recipeType, AbstractFurnaceBlockEntity furnace, double cookSpeedMultiplier) { + /* Scale the recipe's cooking time to the current cookSpeedMultiplier */ -+ int cookTime = (world != null ? world.getRecipeManager() : net.minecraft.server.MinecraftServer.getServer().getRecipeManager()).getRecipeFor(recipeType, inventory, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(AbstractCookingRecipe::getCookingTime).orElse(200); // CraftBukkit - SPIGOT-4302 // Eclipse fail ++ int cookTime = world == null ? furnace.quickCheck.getRecipeFor(furnace, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, furnace, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(AbstractCookingRecipe::getCookingTime).orElse(200)); + return (int) Math.ceil (cookTime / cookSpeedMultiplier); } + // Paper end public static boolean isFuel(ItemStack stack) { return AbstractFurnaceBlockEntity.getFuel().containsKey(stack.getItem()); -@@ -532,7 +543,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -545,7 +558,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit } if (slot == 0 && !flag) { -- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this); -+ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this, this.cookSpeedMultiplier); +- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this); ++ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this, this.cookSpeedMultiplier); // Paper this.cookingProgress = 0; this.setChanged(); } diff --git a/patches/unapplied/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch b/patches/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch similarity index 88% rename from patches/unapplied/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch rename to patches/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch index 740e52781..becfaf70e 100644 --- a/patches/unapplied/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch +++ b/patches/server/0264-Catch-JsonParseException-in-Entity-and-TE-names.patch @@ -48,10 +48,10 @@ index ccdee183f02ab55723e16f41efce55dc51e96297..162aa7718488a74980843944e0d026cc return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); } diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -index 04a3627667498b841fbff547d1874d99cc708af4..5b125aa77e769983a0aee7c5f6eb6a8a146fead0 100644 +index a0728e95251e8110bcecd00512c7a266fe120794..da504702bc9423774b35dff792d2dbe7fc270fe3 100644 --- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -@@ -73,7 +73,7 @@ public abstract class BaseCommandBlock implements CommandSource { +@@ -72,7 +72,7 @@ public abstract class BaseCommandBlock implements CommandSource { this.command = nbt.getString("Command"); this.successCount = nbt.getInt("SuccessCount"); if (nbt.contains("CustomName", 8)) { @@ -61,10 +61,10 @@ index 04a3627667498b841fbff547d1874d99cc708af4..5b125aa77e769983a0aee7c5f6eb6a8a if (nbt.contains("TrackOutput", 1)) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -index 0de9d86d5e2f0a9043640e3154c11612408e24d8..d58f3beabbdb48cbb36bd4802d12cda41628731f 100644 +index 601cf7b9aa4b3483a2134a2db0d617ed8938ea48..c6ce5dc5dafc15f1f12b0ea4c9d55325f6a76529 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -@@ -97,7 +97,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable { +@@ -98,7 +98,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable { public void load(CompoundTag nbt) { super.load(nbt); if (nbt.contains("CustomName", 8)) { @@ -74,10 +74,10 @@ index 0de9d86d5e2f0a9043640e3154c11612408e24d8..d58f3beabbdb48cbb36bd4802d12cda4 this.itemPatterns = nbt.getList("Patterns", 10); diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -index cfd1e2fbc029d928daa2d9f12df393c8cf30e850..72c4c367b3531b21f1f28601735a5250069b8713 100644 +index a34ae15cd4048bda965fd1449c75f3bd8f0e530b..adf67868eef7d578b7858a5afd54e37ea0d5102f 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -@@ -31,7 +31,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co +@@ -30,7 +30,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co super.load(nbt); this.lockKey = LockCode.fromTag(nbt); if (nbt.contains("CustomName", 8)) { @@ -87,10 +87,10 @@ index cfd1e2fbc029d928daa2d9f12df393c8cf30e850..72c4c367b3531b21f1f28601735a5250 } diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index dca94c75f4531eab3ab788e722363d2065bf4170..4b7da0df927f669845c7d4c9b4a0acfab8efe657 100644 +index 0c699c08ef85ca3339ada5c869b571581092a11d..349b89dd4d34b92d1077ddadb30c36642fd85622 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -359,7 +359,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider { +@@ -365,7 +365,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider { this.levels = nbt.getInt("Levels"); // SPIGOT-5053, use where available // CraftBukkit end if (nbt.contains("CustomName", 8)) { @@ -100,10 +100,10 @@ index dca94c75f4531eab3ab788e722363d2065bf4170..4b7da0df927f669845c7d4c9b4a0acfa this.lockKey = LockCode.fromTag(nbt); diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -index d399d9ea7656d1c96f3b7547049d2e133ef5e847..1eccf9424bd8a4bcbeed4ebb1795fd113fe5af18 100644 +index 3a8bdb788b07b0a8cda3d4b872ede52ca9a005c4..2341a5a249d455628165fc6ba508fc6d70c3dbfb 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -@@ -43,7 +43,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable +@@ -42,7 +42,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable public void load(CompoundTag nbt) { super.load(nbt); if (nbt.contains("CustomName", 8)) { diff --git a/patches/unapplied/server/0265-Honor-EntityAgeable.ageLock.patch b/patches/server/0265-Honor-EntityAgeable.ageLock.patch similarity index 81% rename from patches/unapplied/server/0265-Honor-EntityAgeable.ageLock.patch rename to patches/server/0265-Honor-EntityAgeable.ageLock.patch index 8a44dcb05..3c2db9937 100644 --- a/patches/unapplied/server/0265-Honor-EntityAgeable.ageLock.patch +++ b/patches/server/0265-Honor-EntityAgeable.ageLock.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Honor EntityAgeable.ageLock diff --git a/src/main/java/net/minecraft/world/entity/AgeableMob.java b/src/main/java/net/minecraft/world/entity/AgeableMob.java -index 123b125a3576903767983c93135086ca7a8ea813..d165117d62fe8a55d624966e8c4b626c0f52db39 100644 +index 6113e05a0636cc4895bccfbf87eef306138bcd33..22ba53d9f8866327752b0c33b517adb02c50b684 100644 --- a/src/main/java/net/minecraft/world/entity/AgeableMob.java +++ b/src/main/java/net/minecraft/world/entity/AgeableMob.java @@ -84,6 +84,7 @@ public abstract class AgeableMob extends PathfinderMob { @@ -17,10 +17,10 @@ index 123b125a3576903767983c93135086ca7a8ea813..d165117d62fe8a55d624966e8c4b626c int k = j; diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index afe4991fb69fa303279a4e46d730f482e8a58f01..e4e879cdfe7d257161bf8e98305c0f2e9b9539f9 100644 +index bd70aa9448a429f813f494c02d09432532985152..ea63802f2644bc2b5b3b0c72d7d09813cb68139d 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -296,6 +296,7 @@ public class BeehiveBlockEntity extends BlockEntity { +@@ -299,6 +299,7 @@ public class BeehiveBlockEntity extends BlockEntity { } private static void setBeeReleaseData(int ticks, Bee bee) { @@ -28,7 +28,7 @@ index afe4991fb69fa303279a4e46d730f482e8a58f01..e4e879cdfe7d257161bf8e98305c0f2e int j = bee.getAge(); if (j < 0) { -@@ -303,6 +304,7 @@ public class BeehiveBlockEntity extends BlockEntity { +@@ -306,6 +307,7 @@ public class BeehiveBlockEntity extends BlockEntity { } else if (j > 0) { bee.setAge(Math.max(0, j - ticks)); }