From dee90322ebdda7c9a8ab1c1b7e686e2030448959 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sat, 20 Jan 2024 23:13:41 +0100 Subject: [PATCH] [ci skip] Add more identifying patch comments --- .../server/Actually-optimise-explosions.patch | 2 +- patches/server/Add-API-for-quit-reason.patch | 2 +- .../server/Add-BlockPreDispenseEvent.patch | 2 +- .../server/Add-PlayerKickEvent-causes.patch | 2 +- ...h => Add-PlayerRecipeBookClickEvent.patch} | 14 +++---- patches/server/Add-PrepareResultEvent.patch | 38 +++++++++---------- .../server/Add-fire-tick-delay-option.patch | 2 +- patches/server/Add-more-Evoker-API.patch | 4 +- ...Add-zombie-targets-turtle-egg-config.patch | 2 +- .../Beacon-API-custom-effect-ranges.patch | 2 +- patches/server/Brand-support.patch | 10 ++--- patches/server/Buffer-joins-to-world.patch | 14 +++---- ...le-Keep-Spawn-Loaded-range-per-world.patch | 2 +- .../Deep-clone-unhandled-nbt-tags.patch | 2 +- ...l-more-information-in-watchdog-dumps.patch | 2 +- ...erver-load-chunks-from-newer-version.patch | 6 +-- .../server/Don-t-require-FACING-data.patch | 2 +- .../Expand-PlayerGameModeChangeEvent.patch | 2 +- ...ataPlayer-leak-due-from-quitting-ear.patch | 2 +- ...ortation-and-cancel-velocity-if-tele.patch | 2 +- ...ld-Difficulty-Remembering-Difficulty.patch | 14 +++---- patches/server/Fix-SPIGOT-5989.patch | 4 +- ...geEvent-not-firing-for-all-use-cases.patch | 10 ++--- ...rs-not-working-in-some-kick-messages.patch | 2 +- ...Fix-some-rails-connecting-improperly.patch | 20 +++++----- .../Hide-sync-chunk-writes-behind-flag.patch | 2 +- ...-Legacy-Component-serialization-size.patch | 8 ++-- patches/server/Improve-ServerGUI.patch | 2 +- .../Improve-boat-collision-performance.patch | 4 +- patches/server/Limit-recipe-packets.patch | 2 +- .../Optimize-Bit-Operations-by-inlining.patch | 4 +- ...ze-NetworkManager-Exception-Handling.patch | 6 +-- ...der-Remove-Streams-Optimized-collect.patch | 2 +- .../Optimize-player-lookups-for-beacons.patch | 2 +- ...CreateEvent-needs-to-know-its-entity.patch | 8 ++-- ...-headless-pistons-from-being-created.patch | 2 +- ...-position-desync-causing-tp-exploit.patch} | 3 +- patches/server/Rewrite-chunk-system.patch | 6 +-- .../Support-old-UUID-format-for-NBT.patch | 16 ++++---- ...-Vanilla-Command-permission-checking.patch | 10 ++--- patches/server/Timings-v2.patch | 2 +- ...pdate-itemstack-legacy-name-and-lore.patch | 2 +- .../incremental-chunk-and-player-saving.patch | 26 ++++++------- 43 files changed, 134 insertions(+), 137 deletions(-) rename patches/server/{Add-and-implement-PlayerRecipeBookClickEvent.patch => Add-PlayerRecipeBookClickEvent.patch} (88%) rename patches/server/{Prevent-position-desync-in-playerconnection-causing-.patch => Prevent-position-desync-causing-tp-exploit.patch} (95%) diff --git a/patches/server/Actually-optimise-explosions.patch b/patches/server/Actually-optimise-explosions.patch index be9c9b93fa..4d3b290189 100644 --- a/patches/server/Actually-optimise-explosions.patch +++ b/patches/server/Actually-optimise-explosions.patch @@ -424,7 +424,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class Explosion { } } - // Paper end + // Paper end - prevent headless pistons from forming + } // Paper - optimise explosions } diff --git a/patches/server/Add-API-for-quit-reason.patch b/patches/server/Add-API-for-quit-reason.patch index f73364bccf..5985c4f9d6 100644 --- a/patches/server/Add-API-for-quit-reason.patch +++ b/patches/server/Add-API-for-quit-reason.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - public @Nullable String clientBrandName = null; // Paper - Brand name + public @Nullable String clientBrandName = null; // Paper - Brand support + public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event // Paper start - replace player chunk loader diff --git a/patches/server/Add-BlockPreDispenseEvent.patch b/patches/server/Add-BlockPreDispenseEvent.patch index 17682ef12d..35c3d9ea83 100644 --- a/patches/server/Add-BlockPreDispenseEvent.patch +++ b/patches/server/Add-BlockPreDispenseEvent.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 DispenseItemBehavior idispensebehavior = this.getDispenseMethod(itemstack); if (idispensebehavior != DispenseItemBehavior.NOOP) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent DispenserBlock.eventFired = false; // CraftBukkit - reset event status tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); } diff --git a/patches/server/Add-PlayerKickEvent-causes.patch b/patches/server/Add-PlayerKickEvent-causes.patch index 36df1a3a48..8f5eeb4ff8 100644 --- a/patches/server/Add-PlayerKickEvent-causes.patch +++ b/patches/server/Add-PlayerKickEvent-causes.patch @@ -413,7 +413,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { -- this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); // Paper +- this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); + this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause return; } diff --git a/patches/server/Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/server/Add-PlayerRecipeBookClickEvent.patch similarity index 88% rename from patches/server/Add-and-implement-PlayerRecipeBookClickEvent.patch rename to patches/server/Add-PlayerRecipeBookClickEvent.patch index 6a7242b3f0..f179b884c2 100644 --- a/patches/server/Add-and-implement-PlayerRecipeBookClickEvent.patch +++ b/patches/server/Add-PlayerRecipeBookClickEvent.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+JRoy@users.noreply.github.com> Date: Fri, 5 Jun 2020 18:24:06 -0400 -Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent +Subject: [PATCH] Add PlayerRecipeBookClickEvent diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!this.player.containerMenu.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); } else { -+ // Paper start ++ // Paper start - Add PlayerRecipeBookClickEvent + ResourceLocation recipeName = packet.getRecipe(); + boolean makeAll = packet.isShiftDown(); + com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent( @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + recipeName = CraftNamespacedKey.toMinecraft(paperEvent.getRecipe()); + makeAll = paperEvent.isMakeAll(); + if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ // Paper end ++ // Paper end - Add PlayerRecipeBookClickEvent // CraftBukkit start - implement PlayerRecipeBookClickEvent - org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(packet.getRecipe())); + org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(recipeName)); // Paper @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } - org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packet.isShiftDown()); -+ // Paper start ++ // Paper start - Add PlayerRecipeBookClickEvent + org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll); + recipeName = CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey()); + makeAll = event.isShiftClick(); @@ -40,16 +40,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!(this.player.containerMenu instanceof RecipeBookMenu recipeBookMenu)) { + return; + } -+ // Paper end ++ // Paper end - Add PlayerRecipeBookClickEvent // Cast to keyed should be safe as the recipe will never be a MerchantRecipe. - this.server.getRecipeManager().byKey(CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).ifPresent((recipeholder) -> { - ((RecipeBookMenu) this.player.containerMenu).handlePlacement(event.isShiftClick(), recipeholder, this.player); -+ // Paper start ++ // Paper start - Add PlayerRecipeBookClickEvent + final boolean finalMakeAll = makeAll; + this.server.getRecipeManager().byKey(recipeName).ifPresent((recipeholder) -> { + recipeBookMenu.handlePlacement(finalMakeAll, recipeholder, this.player); -+ // Paper end ++ // Paper end - Add PlayerRecipeBookClickEvent }); // CraftBukkit end } diff --git a/patches/server/Add-PrepareResultEvent.patch b/patches/server/Add-PrepareResultEvent.patch index b4ce2d5015..fbb8e05b26 100644 --- a/patches/server/Add-PrepareResultEvent.patch +++ b/patches/server/Add-PrepareResultEvent.patch @@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent return true; } else { return false; @@ -27,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.setupResultSlot(itemstack, itemstack1, itemstack2); } -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) { @@ -39,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.slotsChanged(inventory); if (inventory == this.repairSlots) { this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } } @@ -51,7 +51,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.slotsChanged(inventory); if (inventory == this.inputSlots) { this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper - Add PrepareResultEvent } } @@ -64,8 +64,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - this.broadcastChanges(); -+ // this.broadcastChanges(); // Paper - done below -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper ++ // this.broadcastChanges(); // Paper - Add PrepareResultEvent; done below ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper - Add PrepareResultEvent } else { this.resultSlot.set(ItemStack.EMPTY); this.selectablePatterns = List.of(); @@ -77,7 +77,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } @Override @@ -89,7 +89,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.setupRecipeList(inventory, itemstack); } -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } private void setupRecipeList(Container input, ItemStack stack) { @@ -104,41 +104,41 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 ++ // Paper start - Add PrepareResultEvent; 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); // Paper - disable event event.getInventory().setItem(2, event.getResult()); - return event; -+ //return event; // Paper ++ //return event; } -+ // Paper end ++ // Paper end - Add PrepareResultEvent - public static PrepareGrindstoneEvent callPrepareGrindstoneEvent(InventoryView view, ItemStack item) { - PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(view, CraftItemStack.asCraftMirror(item).clone()); - event.getView().getPlayer().getServer().getPluginManager().callEvent(event); -+ // Paper start - disable this method, handled below ++ // Paper start - Add PrepareResultEvent; disable this method, handled below + public static void callPrepareGrindstoneEvent(InventoryView view, ItemStack item) { + PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(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 ++ // return event; } -+ // Paper end ++ // Paper end - Add PrepareResultEvent - 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 ++ // Paper start - Add PrepareResultEvent; 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().setResult(event.getResult()); - return event; + //return event; // Paper - } -+ // Paper end ++ } ++ // Paper end - Add PrepareResultEvent + + // Paper start - support specific overrides for prepare result + public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) { @@ -158,8 +158,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + event.callEvent(); + event.getInventory().setItem(resultSlot, event.getResult()); + container.broadcastChanges();; -+ } -+ // Paper end + } ++ // Paper end - Add PrepareResultEvent /** * Mob spawner event. diff --git a/patches/server/Add-fire-tick-delay-option.patch b/patches/server/Add-fire-tick-delay-option.patch index f9dd19812f..ec80e863f2 100644 --- a/patches/server/Add-fire-tick-delay-option.patch +++ b/patches/server/Add-fire-tick-delay-option.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class FireBlock extends BaseFireBlock { public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext itemActionContext) { super.onPlace(iblockdata, world, blockposition, iblockdata1, flag, itemActionContext); - // Paper end + // Paper end - ItemActionContext param - world.scheduleTick(blockposition, this, getFireTickDelay(world.random)); + world.scheduleTick(blockposition, this, getFireTickDelay(world)); // Paper - Add fire-tick-delay option } diff --git a/patches/server/Add-more-Evoker-API.patch b/patches/server/Add-more-Evoker-API.patch index d771b60f4a..76a7234a55 100644 --- a/patches/server/Add-more-Evoker-API.patch +++ b/patches/server/Add-more-Evoker-API.patch @@ -23,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.getHandle().setIsCastingSpell(spell == null ? SpellcasterIllager.IllagerSpell.NONE : SpellcasterIllager.IllagerSpell.byId(spell.ordinal())); } + -+ // Paper start ++ // Paper start - Add more Evoker API + @Override + public org.bukkit.entity.Sheep getWololoTarget() { + Sheep sheep = getHandle().getWololoTarget(); @@ -34,5 +34,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void setWololoTarget(org.bukkit.entity.Sheep sheep) { + getHandle().setWololoTarget(sheep == null ? null : ((org.bukkit.craftbukkit.entity.CraftSheep) sheep).getHandle()); + } -+ // Paper end ++ // Paper end - Add more Evoker API } diff --git a/patches/server/Add-zombie-targets-turtle-egg-config.patch b/patches/server/Add-zombie-targets-turtle-egg-config.patch index 60878b5e6a..8a7c7ed04e 100644 --- a/patches/server/Add-zombie-targets-turtle-egg-config.patch +++ b/patches/server/Add-zombie-targets-turtle-egg-config.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override protected void registerGoals() { - this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); -+ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper ++ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); this.addBehaviourGoals(); diff --git a/patches/server/Beacon-API-custom-effect-ranges.patch b/patches/server/Beacon-API-custom-effect-ranges.patch index d88a3cb49b..4dc26c8009 100644 --- a/patches/server/Beacon-API-custom-effect-ranges.patch +++ b/patches/server/Beacon-API-custom-effect-ranges.patch @@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - Custom beacon ranges { - double d0 = (double) (i * 10 + 10); -+ double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10);// Paper - Custom beacon ranges ++ double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10); // Paper - Custom beacon ranges AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D); List list = world.getEntitiesOfClass(Player.class, axisalignedbb); diff --git a/patches/server/Brand-support.patch b/patches/server/Brand-support.patch index cc08d38b25..f277adc28a 100644 --- a/patches/server/Brand-support.patch +++ b/patches/server/Brand-support.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean isRealPlayer; // Paper public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper -+ public @Nullable String clientBrandName = null; // Paper - Brand name ++ public @Nullable String clientBrandName = null; // Paper - Brand support // Paper start - replace player chunk loader private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); @@ -32,11 +32,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { -+ // Paper start - handle brand payload packet ++ // Paper start - Brand support + if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload brandPayload) { + this.player.clientBrandName = brandPayload.brand(); + } -+ // Paper end - handle brand payload ++ // Paper end - Brand support if (!(packet.payload() instanceof ServerboundCustomPayloadPacket.UnknownPayload)) { return; } @@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 try { byte[] data = new byte[payload.readableBytes()]; payload.readBytes(data); -+ // Paper start - Brand support - Retain this incase upstream decides to 'break' the new mechanism in favour of backwards compat... ++ // Paper start - Brand support; Retain this incase upstream decides to 'break' the new mechanism in favour of backwards compat... + if (identifier.equals(MINECRAFT_BRAND)) { + try { + this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.copiedBuffer(data)).readUtf(256); @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.player.clientBrandName = "illegal"; + } + } -+ // Paper end ++ // Paper end - Brand support this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); } catch (Exception ex) { ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex); diff --git a/patches/server/Buffer-joins-to-world.patch b/patches/server/Buffer-joins-to-world.patch index 0ed64bd178..6318e1f1ae 100644 --- a/patches/server/Buffer-joins-to-world.patch +++ b/patches/server/Buffer-joins-to-world.patch @@ -15,29 +15,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper end - Optimize network -+ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper -+ private static int joinAttemptsThisTick; // Paper -+ private static int currTick; // Paper ++ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world ++ private static int joinAttemptsThisTick; // Paper - Buffer joins to world ++ private static int currTick; // Paper - Buffer joins to world public void tick() { this.flushQueue(); -+ // Paper start ++ // Paper start - Buffer joins to world + if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { + Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; + Connection.joinAttemptsThisTick = 0; + } -+ // Paper end ++ // Paper end - Buffer joins to world PacketListener packetlistener = this.packetListener; if (packetlistener instanceof TickablePacketListener) { TickablePacketListener tickablepacketlistener = (TickablePacketListener) packetlistener; -+ // Paper start - limit the number of joins which can be processed each tick ++ // Paper start - Buffer joins to world + if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) + || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING + || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { tickablepacketlistener.tick(); + } -+ // Paper end ++ // Paper end - Buffer joins to world } if (!this.isConnected() && !this.disconnectionHandled) { diff --git a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index 7dc9754b37..27914e4950 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -174,7 +174,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public class LoggerChunkProgressListener implements ChunkProgressListener { private static final Logger LOGGER = LogUtils.getLogger(); - private final int maxCount; -+ private int maxCount;// Paper - remove final ++ private int maxCount; // Paper - remove final private int count; private long startTime; private long nextTickTime = Long.MAX_VALUE; diff --git a/patches/server/Deep-clone-unhandled-nbt-tags.patch b/patches/server/Deep-clone-unhandled-nbt-tags.patch index 75d4f9ca5e..c06cf31649 100644 --- a/patches/server/Deep-clone-unhandled-nbt-tags.patch +++ b/patches/server/Deep-clone-unhandled-nbt-tags.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private CompoundTag internalTag; - final Map unhandledTags = new TreeMap(); // Visible for testing only // Paper -+ Map unhandledTags = new TreeMap(); // Visible for testing only // Paper & Deep clone unhandled nbt tags; remove final ++ Map unhandledTags = new TreeMap(); // Visible for testing only // Paper - Deep clone unhandled nbt tags; remove final private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftMetaItem.DATA_TYPE_REGISTRY); private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only diff --git a/patches/server/Detail-more-information-in-watchdog-dumps.patch b/patches/server/Detail-more-information-in-watchdog-dumps.patch index 890dea9a1f..da711708b8 100644 --- a/patches/server/Detail-more-information-in-watchdog-dumps.patch +++ b/patches/server/Detail-more-information-in-watchdog-dumps.patch @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + net.minecraft.network.protocol.PacketUtils.packetProcessing.pop(); + } // Paper end - detailed watchdog information } - // Paper end + // Paper end - Buffer joins to world } diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch index b612800b21..12d524cb87 100644 --- a/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch +++ b/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch @@ -16,13 +16,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 InProgressChunkHolder holder = loadChunk(world, poiStorage, chunkPos, nbt, true); return holder.protoChunk; } -+ // Paper start ++ // Paper start - Do not let the server load chunks from newer versions + private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion"); -+ // Paper end ++ // Paper end - Do not let the server load chunks from newer versions public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { -+ // Paper start - Do NOT attempt to load chunks saved with newer versions ++ // Paper start - Do not let the server load chunks from newer versions + if (nbt.contains("DataVersion", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { + int dataVersion = nbt.getInt("DataVersion"); + if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { diff --git a/patches/server/Don-t-require-FACING-data.patch b/patches/server/Don-t-require-FACING-data.patch index c1e6f9f969..1e31deecb8 100644 --- a/patches/server/Don-t-require-FACING-data.patch +++ b/patches/server/Don-t-require-FACING-data.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end public class DefaultDispenseItemBehavior implements DispenseItemBehavior { -+ private Direction enumdirection; // Paper ++ private Direction enumdirection; // Paper - cache facing direction // CraftBukkit start private boolean dropper; diff --git a/patches/server/Expand-PlayerGameModeChangeEvent.patch b/patches/server/Expand-PlayerGameModeChangeEvent.patch index e5e2454d03..4acb0cc595 100644 --- a/patches/server/Expand-PlayerGameModeChangeEvent.patch +++ b/patches/server/Expand-PlayerGameModeChangeEvent.patch @@ -101,7 +101,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public boolean changeGameModeForPlayer(GameType gameMode) { -+ // Paper end - Expand PlayerGameModeChangeEvent ++ // Paper start - Expand PlayerGameModeChangeEvent + PlayerGameModeChangeEvent event = this.changeGameModeForPlayer(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); + return event != null && event.isCancelled(); + } diff --git a/patches/server/Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/patches/server/Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch index e6b29876a0..b985d4e166 100644 --- a/patches/server/Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch +++ b/patches/server/Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public abstract class SimpleCriterionTrigger implements CriterionTrigger { - private final Map>> players = Maps.newIdentityHashMap(); -+ // private final Map>> players = Maps.newIdentityHashMap(); // Paper - moved into AdvancementDataPlayer to fix memory leak ++ // private final Map>> players = Maps.newIdentityHashMap(); // Paper - fix AdvancementDataPlayer leak; moved into AdvancementDataPlayer to fix memory leak @Override public final void addPlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener conditions) { diff --git a/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch index d3289ad920..cb26cd7e92 100644 --- a/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch +++ b/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch @@ -46,7 +46,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void moveTo(double x, double y, double z, float yaw, float pitch) { -+ // Paper - Fix Entity Teleportation and cancel velocity if teleported ++ // Paper start - Fix Entity Teleportation and cancel velocity if teleported + if (!preserveMotion) { + this.deltaMovement = Vec3.ZERO; + } else { diff --git a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch index 749bf8e845..b03065ab36 100644 --- a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -29,14 +29,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : difficulty); - this.updateMobSpawningFlags(); - this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); -+ // Paper start - remember per level difficulty ++ // Paper start - per level difficulty + public void setDifficulty(ServerLevel level, Difficulty difficulty, boolean forceUpdate) { + PrimaryLevelData worldData = level.serverLevelData; + if (forceUpdate || !worldData.isDifficultyLocked()) { + worldData.setDifficulty(worldData.isHardcore() ? Difficulty.HARD : difficulty); + level.setSpawnSettings(worldData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); + // this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); -+ // Paper end ++ // Paper end - per level difficulty } } @@ -58,7 +58,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 throw DifficultyCommand.ERROR_ALREADY_DIFFICULT.create(difficulty.getKey()); } else { - worldServer.serverLevelData.setDifficulty(difficulty); // CraftBukkit -+ minecraftserver.setDifficulty(worldServer, difficulty, true); // Paper - don't skip other difficulty-changing logic (fix upstream's fix) ++ minecraftserver.setDifficulty(worldServer, difficulty, true); // Paper - per level difficulty; don't skip other difficulty-changing logic (fix upstream's fix) source.sendSuccess(() -> { return Component.translatable("commands.difficulty.success", difficulty.getDisplayName()); }, true); @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void forceDifficulty() { - this.setDifficulty(this.getProperties().difficulty, true); -+ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - Don't overwrite level.dat's difficulty, keep current ++ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current } @Override @@ -84,7 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(worldserver), (byte) 3)); - this.connection.send(new ClientboundChangeDifficultyPacket(this.level().getDifficulty(), this.level().getLevelData().isDifficultyLocked())); -+ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level().getLevelData().isDifficultyLocked())); // Paper - fix difficulty sync issue ++ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level().getLevelData().isDifficultyLocked())); // Paper - per level difficulty PlayerList playerlist = this.server.getPlayerList(); playerlist.sendPlayerPermissionLevel(this); @@ -97,7 +97,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) { - this.server.setDifficulty(packet.getDifficulty(), false); -+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - don't allow clients to change this ++ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - per level difficulty; don't allow clients to change this } } @@ -125,7 +125,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void setDifficulty(Difficulty difficulty) { - this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue())); -+ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - don't skip other difficulty-changing logic ++ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - per level difficulty; don't skip other difficulty-changing logic } @Override diff --git a/patches/server/Fix-SPIGOT-5989.patch b/patches/server/Fix-SPIGOT-5989.patch index 43a6fe4515..92199cf270 100644 --- a/patches/server/Fix-SPIGOT-5989.patch +++ b/patches/server/Fix-SPIGOT-5989.patch @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + location = respawnEvent.getRespawnLocation(); + isLocAltered = true; + } -+ // Paper end ++ // Paper end - Fix SPIGOT-5989 if (!flag) entityplayer.reset(); // SPIGOT-4785 isRespawn = true; // Paper } else { @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + worldserver1.setBlock(blockposition, data.setValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE, data.getValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE) - 1), 3); + } + entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) location.getX(), (double) location.getY(), (double) location.getZ(), 1.0F, 1.0F, worldserver1.getRandom().nextLong())); -+ // Paper end ++ // Paper end - Fix SPIGOT-5989 } // Added from changeDimension this.sendAllPlayerInfo(entityplayer); // Update health, etc... diff --git a/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch index 38101fdbe8..8236e58f9c 100644 --- a/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch +++ b/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch @@ -12,11 +12,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void setDefaultSpawnPos(BlockPos pos, float angle) { // Paper - configurable spawn radius BlockPos prevSpawn = this.getSharedSpawnPos(); -+ Location prevSpawnLoc = this.getWorld().getSpawnLocation(); // Paper ++ Location prevSpawnLoc = this.getWorld().getSpawnLocation(); // Paper - Call SpawnChangeEvent //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c())); this.levelData.setSpawn(pos, angle); -+ new org.bukkit.event.world.SpawnChangeEvent(this.getWorld(), prevSpawnLoc).callEvent(); // Paper ++ new org.bukkit.event.world.SpawnChangeEvent(this.getWorld(), prevSpawnLoc).callEvent(); // Paper - Call SpawnChangeEvent if (this.keepSpawnInMemory) { // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, prevSpawn); @@ -30,16 +30,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 try { - Location previousLocation = this.getSpawnLocation(); - this.world.levelData.setSpawn(new BlockPos(x, y, z), angle); -+ // Location previousLocation = this.getSpawnLocation(); // Paper - moved to nms.ServerLevel ++ // Location previousLocation = this.getSpawnLocation(); // Paper - Call SpawnChangeEvent; moved to nms.ServerLevel + this.world.setDefaultSpawnPos(new BlockPos(x, y, z), angle); // Paper - use ServerLevel#setDefaultSpawnPos -+ // Paper start - move to nms.ServerLevel ++ // Paper start - Call SpawnChangeEvent; move to nms.ServerLevel // Notify anyone who's listening. - SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); - this.server.getPluginManager().callEvent(event); + // SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); + // server.getPluginManager().callEvent(event); -+ // Paper end ++ // Paper end - Call SpawnChangeEvent return true; } catch (Exception e) { diff --git a/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch index 63f795d830..9b8dbc5c18 100644 --- a/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch +++ b/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch @@ -23,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName())); // Spigot // Paper - Fix hex colors not working in some kick messages } -+ Component ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureComponent); // Paper ++ Component ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureComponent); // Paper - Fix hex colors not working in some kick messages + this.connection.send(new ClientboundLoginDisconnectPacket(ichatmutablecomponent)); this.connection.disconnect(ichatmutablecomponent); diff --git a/patches/server/Fix-some-rails-connecting-improperly.patch b/patches/server/Fix-some-rails-connecting-improperly.patch index d98510f28f..48459128b2 100644 --- a/patches/server/Fix-some-rails-connecting-improperly.patch +++ b/patches/server/Fix-some-rails-connecting-improperly.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 state = this.updateDir(world, pos, state, true); if (this.isStraight) { world.neighborChanged(state, pos, this, pos, notify); -+ state = world.getBlockState(pos); // Paper - don't desync, update again ++ state = world.getBlockState(pos); // Paper - Fix some rails connecting improperly } return state; @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private void checkPressed(Level world, BlockPos pos, BlockState state) { if (this.canSurvive(state, world, pos)) { -+ if (state.getBlock() != this) { return; } // Paper - not our block, don't do anything ++ if (state.getBlock() != this) { return; } // Paper - Fix some rails connecting improperly boolean flag = (Boolean) state.getValue(DetectorRailBlock.POWERED); boolean flag1 = false; List list = this.getInteractingMinecartOfType(world, pos, AbstractMinecart.class, (entity) -> { @@ -36,11 +36,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final boolean isStraight; private final List connections = Lists.newArrayList(); -+ // Paper start - prevent desync ++ // Paper start - Fix some rails connecting improperly + public boolean isValid() { + return this.level.getBlockState(this.pos).getBlock() == this.state.getBlock(); + } -+ // Paper end - prevent desync ++ // Paper end - Fix some rails connecting improperly + public RailState(Level world, BlockPos pos, BlockState state) { this.level = world; @@ -49,11 +49,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private void connectTo(RailState placementHelper) { -+ // Paper start - prevent desync ++ // Paper start - Fix some rails connecting improperly + if (!this.isValid() || !placementHelper.isValid()) { + return; + } -+ // Paper end - prevent desync ++ // Paper end - Fix some rails connecting improperly this.connections.add(placementHelper.pos); BlockPos blockPos = this.pos.north(); BlockPos blockPos2 = this.pos.south(); @@ -61,16 +61,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.state = this.state.setValue(this.block.getShapeProperty(), railShape2); if (forceUpdate || this.level.getBlockState(this.pos) != this.state) { this.level.setBlock(this.pos, this.state, 3); -+ // Paper start - prevent desync ++ // Paper start - Fix some rails connecting improperly + if (!this.isValid()) { + return this; + } -+ // Paper end - prevent desync ++ // Paper end - Fix some rails connecting improperly for(int i = 0; i < this.connections.size(); ++i) { RailState railState = this.getRail(this.connections.get(i)); - if (railState != null) { -+ if (railState != null && railState.isValid()) { // Paper - prevent desync ++ if (railState != null && railState.isValid()) { // Paper - Fix some rails connecting improperly railState.removeSoftConnections(); if (railState.canConnectTo(this)) { railState.connectTo(this); @@ -79,6 +79,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public BlockState getState() { - return this.state; -+ return this.level.getBlockState(this.pos); // Paper - prevent desync ++ return this.level.getBlockState(this.pos); // Paper - Fix some rails connecting improperly } } diff --git a/patches/server/Hide-sync-chunk-writes-behind-flag.patch b/patches/server/Hide-sync-chunk-writes-behind-flag.patch index e20d2ab23d..a8499fa156 100644 --- a/patches/server/Hide-sync-chunk-writes-behind-flag.patch +++ b/patches/server/Hide-sync-chunk-writes-behind-flag.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return Mth.clamp(integer, 1, 29999984); }, 29999984); - this.syncChunkWrites = this.get("sync-chunk-writes", true); -+ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - hide behind flag ++ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false); this.enableStatus = this.get("enable-status", true); this.hideOnlinePlayers = this.get("hide-online-players", false); diff --git a/patches/server/Improve-Legacy-Component-serialization-size.patch b/patches/server/Improve-Legacy-Component-serialization-size.patch index 1adb6079de..f1a3a08974 100644 --- a/patches/server/Improve-Legacy-Component-serialization-size.patch +++ b/patches/server/Improve-Legacy-Component-serialization-size.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Separate pattern with no group 3, new lines are part of previous string private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE); // ChatColor.b does not explicitly reset, its more of empty -+ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - OBFHELPER ++ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - Improve Legacy Component serialization size private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false); private final List list = new ArrayList(); @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message); String match = null; boolean needsAdd = false; -+ boolean hasReset = false; // Paper ++ boolean hasReset = false; // Paper - Improve Legacy Component serialization size while (matcher.find()) { int groupId = 0; while ((match = matcher.group(++groupId)) == null) { @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } else { // Color resets formatting - this.modifier = StringMessage.RESET.withColor(format); -+ // Paper start - improve legacy formatting ++ // Paper start - Improve Legacy Component serialization size + Style previous = modifier; + modifier = (!hasReset ? RESET : EMPTY).withColor(format); + hasReset = true; @@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (previous.isUnderlined()) { + modifier = modifier.withUnderlined(false); + } -+ // Paper end ++ // Paper end - Improve Legacy Component serialization size } needsAdd = true; break; diff --git a/patches/server/Improve-ServerGUI.patch b/patches/server/Improve-ServerGUI.patch index a34cb89b90..94ed7d4059 100644 --- a/patches/server/Improve-ServerGUI.patch +++ b/patches/server/Improve-ServerGUI.patch @@ -85,7 +85,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.timer.stop(); } + -+ // Paper - Improve ServerGUI ++ // Paper start - Improve ServerGUI + private static String format(double tps) { + return (( tps > 21.0 ) ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0); // only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise + } diff --git a/patches/server/Improve-boat-collision-performance.patch b/patches/server/Improve-boat-collision-performance.patch index 84630f026f..b30c5bbe4f 100644 --- a/patches/server/Improve-boat-collision-performance.patch +++ b/patches/server/Improve-boat-collision-performance.patch @@ -62,9 +62,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.oldStatus == Boat.Status.IN_AIR && this.status != Boat.Status.IN_AIR && this.status != Boat.Status.ON_LAND) { this.waterLevel = this.getY(1.0D); - this.setPos(this.getX(), (double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D, this.getZ()); -- this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); + this.move(MoverType.SELF, new Vec3(0.0, ((double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D) - this.getY(), 0.0)); // Paper - Improve boat collision performance -+ this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); // Paper - Improve boat collision performance + this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); this.lastYd = 0.0D; this.status = Boat.Status.IN_WATER; - } else { diff --git a/patches/server/Limit-recipe-packets.patch b/patches/server/Limit-recipe-packets.patch index da1ec3fbb3..b8ef3582df 100644 --- a/patches/server/Limit-recipe-packets.patch +++ b/patches/server/Limit-recipe-packets.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - auto recipe limit + if (!org.bukkit.Bukkit.isPrimaryThread()) { + if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { -+ this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); // Paper ++ this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); + return; + } + } diff --git a/patches/server/Optimize-Bit-Operations-by-inlining.patch b/patches/server/Optimize-Bit-Operations-by-inlining.patch index e7615b7a68..55f98cc7f6 100644 --- a/patches/server/Optimize-Bit-Operations-by-inlining.patch +++ b/patches/server/Optimize-Bit-Operations-by-inlining.patch @@ -23,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 ++ // Paper start - Optimize Bit Operations by inlining + private static final int PACKED_X_LENGTH = 26; + private static final int PACKED_Z_LENGTH = 26; + public static final int PACKED_Y_LENGTH = 12; @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private static final long PACKED_Z_MASK = 67108863; + private static final int Z_OFFSET = 12; + private static final int X_OFFSET = 38; -+ // Paper end ++ // Paper end - Optimize Bit Operations by inlining public BlockPos(int x, int y, int z) { super(x, y, z); diff --git a/patches/server/Optimize-NetworkManager-Exception-Handling.patch b/patches/server/Optimize-NetworkManager-Exception-Handling.patch index dbc28f4bf8..82e972c954 100644 --- a/patches/server/Optimize-NetworkManager-Exception-Handling.patch +++ b/patches/server/Optimize-NetworkManager-Exception-Handling.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public Packet createPacket(int id, FriendlyByteBuf buf) { -+ if (id < 0 || id >= this.idToDeserializer.size()) return null; // Paper ++ if (id < 0 || id >= this.idToDeserializer.size()) return null; // Paper - Perf: Optmize exception handling Function> function = this.idToDeserializer.get(id); return function != null ? function.apply(buf) : null; } @@ -24,12 +24,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { -+ // Paper start - if channel is not active just discard the packet ++ // Paper start - Perf: Optmize exception handling; if channel is not active just discard the packet + if (!channelHandlerContext.channel().isActive()) { + byteBuf.skipBytes(byteBuf.readableBytes()); + return; + } -+ // Paper end - if channel is not active just discard the packet ++ // Paper end - Perf: Optmize exception handling byteBuf.markReaderIndex(); this.helperBuf.clear(); if (!copyVarint(byteBuf, this.helperBuf)) { diff --git a/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch index 456f03ca12..b11cf324d9 100644 --- a/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch +++ b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable - private Path findPath(ProfilerFiller profiler, Node startNode, Map positions, float followRange, int distance, float rangeMultiplier) { -+ // Paper start - Perf: remove streams and optimize collection - optimize collection ++ // Paper start - Perf: remove streams and optimize collection + private Path findPath(ProfilerFiller profiler, Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { profiler.push("find_path"); profiler.markForCharting(MetricCategory.PATH_FINDING); diff --git a/patches/server/Optimize-player-lookups-for-beacons.patch b/patches/server/Optimize-player-lookups-for-beacons.patch index ea12fa6dbe..7fb5f746aa 100644 --- a/patches/server/Optimize-player-lookups-for-beacons.patch +++ b/patches/server/Optimize-player-lookups-for-beacons.patch @@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java @@ -0,0 +0,0 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10);// Paper - Custom beacon ranges + double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10); // Paper - Custom beacon ranges AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D); - List list = world.getEntitiesOfClass(Player.class, axisalignedbb); diff --git a/patches/server/PortalCreateEvent-needs-to-know-its-entity.patch b/patches/server/PortalCreateEvent-needs-to-know-its-entity.patch index da4d2e6639..50141c3fa0 100644 --- a/patches/server/PortalCreateEvent-needs-to-know-its-entity.patch +++ b/patches/server/PortalCreateEvent-needs-to-know-its-entity.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { - if (!oldState.is(state.getBlock())) { + public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, net.minecraft.world.item.context.UseOnContext itemActionContext) { -+ // Paper end ++ // Paper end - ItemActionContext param + if (!iblockdata1.is(iblockdata.getBlock())) { if (BaseFireBlock.inPortalDimension(world)) { - Optional optional = PortalShape.findEmptyPortalShape(world, pos, Direction.Axis.X); @@ -73,7 +73,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - ItemActionContext param + public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext itemActionContext) { + super.onPlace(iblockdata, world, blockposition, iblockdata1, flag, itemActionContext); -+ // Paper end ++ // Paper end - ItemActionContext param + world.scheduleTick(blockposition, this, getFireTickDelay(world.random)); } @@ -99,7 +99,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, UseOnContext itemActionContext) { + this.onPlace(iblockdata, world, blockposition, iblockdata1, flag); + } -+ // Paper end ++ // Paper end - ItemActionContext param /** @deprecated */ @Deprecated public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { @@ -123,7 +123,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - ItemActionContext param + @Deprecated public boolean createPortalBlocks() { return this.createPortalBlocks(null); } + public boolean createPortalBlocks(UseOnContext itemActionContext) { -+ // Paper end ++ // Paper end - ItemActionContext param org.bukkit.World bworld = this.level.getMinecraftWorld().getWorld(); // Copy below for loop diff --git a/patches/server/Prevent-headless-pistons-from-being-created.patch b/patches/server/Prevent-headless-pistons-from-being-created.patch index e3d93b13a2..755bc844da 100644 --- a/patches/server/Prevent-headless-pistons-from-being-created.patch +++ b/patches/server/Prevent-headless-pistons-from-being-created.patch @@ -21,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + set.add(blockposition.relative(direction.getOpposite())); + } + } -+ // Paper end ++ // Paper end - prevent headless pistons from forming } d4 += d0 * 0.30000001192092896D; diff --git a/patches/server/Prevent-position-desync-in-playerconnection-causing-.patch b/patches/server/Prevent-position-desync-causing-tp-exploit.patch similarity index 95% rename from patches/server/Prevent-position-desync-in-playerconnection-causing-.patch rename to patches/server/Prevent-position-desync-causing-tp-exploit.patch index 1e26ced1d9..73874ec250 100644 --- a/patches/server/Prevent-position-desync-in-playerconnection-causing-.patch +++ b/patches/server/Prevent-position-desync-causing-tp-exploit.patch @@ -1,8 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Fri, 12 Jun 2020 16:51:39 -0700 -Subject: [PATCH] Prevent position desync in playerconnection causing tp - exploit +Subject: [PATCH] Prevent position desync causing tp exploit Caused the server to revert to the player's overworld coordinates after teleporting into the end. diff --git a/patches/server/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch index 80c07a3dba..dacd07c942 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -16651,7 +16651,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 ++ 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, worldLoader.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new); @@ -16793,7 +16793,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end // CraftBukkit start - if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken + if (isOversleep) return canOversleep(); // Paper - because of our changes, this logic is broken return this.forceTicks || this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos); @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoopwill throw an NPE. */ public UUID getUUID(String key) { -+ // Paper start - support old format ++ // Paper start - Support old UUID format + if (!contains(key, 11) && this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { + return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least")); + } -+ // Paper end ++ // Paper end - Support old UUID format return NbtUtils.loadUUID(this.get(key)); } public boolean hasUUID(String key) { -+ // Paper start - support old format ++ // Paper start - Support old UUID format + if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { + return true; + } -+ // Paper end ++ // Paper end - Support old UUID format Tag tag = this.get(key); return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4; } @@ -53,14 +53,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public static GameProfile readGameProfile(CompoundTag nbt) { UUID uUID = nbt.hasUUID("Id") ? nbt.getUUID("Id") : Util.NIL_UUID; -+ // Paper start - Support string UUIDs ++ // Paper start - Support old UUID format + if (nbt.contains("Id", Tag.TAG_STRING)) { + try { + uUID = UUID.fromString(nbt.getString("Id")); + } catch (IllegalArgumentException ignored){ + } + } -+ // Paper end - Support string UUIDs ++ // Paper end - Support old UUID format String string = nbt.getString("Name"); try { diff --git a/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch index 4215ae9761..fe59e6ffed 100644 --- a/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch +++ b/patches/server/Thread-Safe-Vanilla-Command-permission-checking.patch @@ -17,11 +17,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (source instanceof CommandSourceStack) { try { - ((CommandSourceStack) source).currentCommand = this; -+ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper ++ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper - Thread Safe Vanilla Command permission checking return this.requirement.test(source); } finally { - ((CommandSourceStack) source).currentCommand = null; -+ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper ++ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper - Thread Safe Vanilla Command permission checking } } // CraftBukkit end @@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final CommandSigningContext signingContext; private final TaskChainer chatMessageChainer; - public volatile CommandNode currentCommand; // CraftBukkit -+ public java.util.Map currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper - make thread-safe ++ public java.util.Map currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper - Thread Safe Vanilla Command permission checking public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) { @@ -43,11 +43,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean hasPermission(int level) { // CraftBukkit start - CommandNode currentCommand = this.currentCommand; -+ // Paper start - fix concurrency issue ++ // Paper start - Thread Safe Vanilla Command permission checking + CommandNode currentCommand = this.currentCommand.get(Thread.currentThread()); if (currentCommand != null) { return this.hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand)); -+ // Paper end ++ // Paper end - Thread Safe Vanilla Command permission checking } // CraftBukkit end diff --git a/patches/server/Timings-v2.patch b/patches/server/Timings-v2.patch index 233c27ae60..7c4be6e83a 100644 --- a/patches/server/Timings-v2.patch +++ b/patches/server/Timings-v2.patch @@ -736,7 +736,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private boolean haveTime() { // CraftBukkit start -+ if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken ++ if (isOversleep) return canOversleep(); // Paper - because of our changes, this logic is broken return this.forceTicks || this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos); } diff --git a/patches/server/Update-itemstack-legacy-name-and-lore.patch b/patches/server/Update-itemstack-legacy-name-and-lore.patch index 28d59c7284..214d27a026 100644 --- a/patches/server/Update-itemstack-legacy-name-and-lore.patch +++ b/patches/server/Update-itemstack-legacy-name-and-lore.patch @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (nbttagcompound.contains("tag", 10)) { this.tag = nbttagcompound.getCompound("tag").copy(); this.processEnchantOrder(this.tag); // Paper -+ this.processText(); // Paper ++ this.processText(); // Paper - Update itemstack legacy name and lore this.getItem().verifyTagAfterLoad(this.tag); } diff --git a/patches/server/incremental-chunk-and-player-saving.patch b/patches/server/incremental-chunk-and-player-saving.patch index c69643b405..83aa6ded49 100644 --- a/patches/server/incremental-chunk-and-player-saving.patch +++ b/patches/server/incremental-chunk-and-player-saving.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 try { this.isSaving = true; - this.getPlayerList().saveAll(); -+ this.getPlayerList().saveAll(); // Diff on change ++ this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change flag3 = this.saveAllChunks(suppressLogs, flush, force); } finally { this.isSaving = false; @@ -30,11 +30,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.saveEverything(true, false, false); - this.profiler.pop(); - MinecraftServer.LOGGER.debug("Autosave finished"); -+ // Paper start - incremental chunk and player saving ++ // Paper start - Incremental chunk and player saving + int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate; + if (playerSaveInterval < 0) { + playerSaveInterval = autosavePeriod; - } ++ } + this.profiler.push("save"); + final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0; + try { @@ -49,9 +49,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } finally { + this.isSaving = false; -+ } + } + this.profiler.pop(); -+ // Paper end ++ // Paper end - Incremental chunk and player saving io.papermc.paper.util.CachedLists.reset(); // Paper // Paper start - move executeAll() into full server tick timing try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) { @@ -63,14 +63,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper - Timings } -+ // Paper start - duplicate save, but call incremental ++ // Paper start - Incremental chunk and player saving; duplicate save, but call incremental + public void saveIncrementally() { + this.runDistanceManagerUpdates(); + try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings + this.chunkMap.saveIncrementally(); + } // Paper - Timings + } -+ // Paper end ++ // Paper end - Incremental chunk and player saving + @Override public void close() throws IOException { @@ -83,7 +83,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos); } -+ // Paper start - derived from below ++ // Paper start - Incremental chunk and player saving + public void saveIncrementally(boolean doFull) { + ServerChunkCache chunkproviderserver = this.getChunkSource(); + @@ -112,7 +112,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // CraftBukkit end + } + } -+ // Paper end ++ // Paper end - Incremental chunk and player saving + public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { // Paper start - rewrite chunk system - add close param @@ -125,7 +125,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public class ServerPlayer extends Player { private static final Logger LOGGER = LogUtils.getLogger(); -+ public long lastSave = MinecraftServer.currentTick; // Paper ++ public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; private static final int FLY_STAT_RECORDING_SPEED = 25; @@ -137,7 +137,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void save(ServerPlayer player) { if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit -+ player.lastSave = MinecraftServer.currentTick; // Paper ++ player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving this.playerIo.save(player); ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit @@ -145,7 +145,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void saveAll() { -+ // Paper start - incremental player saving ++ // Paper start - Incremental chunk and player saving + this.saveAll(-1); + } + @@ -161,7 +161,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.save(entityplayer); + if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; } + } -+ // Paper end ++ // Paper end - Incremental chunk and player saving } MinecraftTimings.savePlayers.stopTiming(); // Paper return null; }); // Paper - ensure main