diff --git a/patches/server/Ability-to-control-player-s-insomnia-and-phantoms.patch b/patches/server/Ability-to-control-player-s-insomnia-and-phantoms.patch index 2001683f37..489466a9fd 100644 --- a/patches/server/Ability-to-control-player-s-insomnia-and-phantoms.patch +++ b/patches/server/Ability-to-control-player-s-insomnia-and-phantoms.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return !entity.isSpectator(); }; public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith); -- public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper +- public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper - Add phantom creative and insomniac controls + // Paper start - Ability to control player's insomnia and phantoms + public static Predicate<Player> IS_INSOMNIAC = (player) -> { + net.minecraft.server.level.ServerPlayer serverPlayer = (net.minecraft.server.level.ServerPlayer) player; diff --git a/patches/server/Actually-optimise-explosions.patch b/patches/server/Actually-optimise-explosions.patch index 4d3b290189..758a26ff5e 100644 --- a/patches/server/Actually-optimise-explosions.patch +++ b/patches/server/Actually-optimise-explosions.patch @@ -370,7 +370,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { - BlockPos blockposition = BlockPos.containing(d4, d5, d6); - BlockState iblockdata = this.level.getBlockState(blockposition); -- if (!iblockdata.isDestroyable()) continue; // Paper +- if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed - FluidState fluid = iblockdata.getFluidState(); // Paper + // Paper start - optimise explosions + final int blockX = Mth.floor(d4); @@ -403,11 +403,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (optional.isPresent()) { - f -= ((Float) optional.get() + 0.3F) * 0.3F; - } -- -- if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { + if (!iblockdata.isDestroyable()) continue; // Paper + // Paper - optimise explosions -+ + +- if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { + f -= cachedBlock.resistance; // Paper - optimise explosions + + if (f > 0.0F && cachedBlock.shouldExplode == null) { // Paper - optimise explosions diff --git a/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch index 34aad73b10..0a98ed6f03 100644 --- a/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch +++ b/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); + } -+ // Paper end ++ // Paper end - PlayerAttackEntityCooldownResetEvent } if (event.isCancelled()) { return false; diff --git a/patches/server/Add-PlayerPickItemEvent.patch b/patches/server/Add-PlayerPickItemEvent.patch index ee60f1e4d8..3d7090c4f8 100644 --- a/patches/server/Add-PlayerPickItemEvent.patch +++ b/patches/server/Add-PlayerPickItemEvent.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } - this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed - // Paper end + // Paper end - validate pick item position + // Paper start - Add PlayerPickItemEvent + Player bukkitPlayer = this.player.getBukkitEntity(); + int targetSlot = this.player.getInventory().getSuitableHotbarSlot(); diff --git a/patches/server/Add-phantom-creative-and-insomniac-controls.patch b/patches/server/Add-phantom-creative-and-insomniac-controls.patch index d2e2b523c3..f8cdbb0aa9 100644 --- a/patches/server/Add-phantom-creative-and-insomniac-controls.patch +++ b/patches/server/Add-phantom-creative-and-insomniac-controls.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return !entity.isSpectator(); }; public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith); -+ public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper ++ public static Predicate<Player> IS_INSOMNIAC = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper - Add phantom creative and insomniac controls private EntitySelector() {} // Paper start @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Player entityhuman = (Player) iterator.next(); if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) { -+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper ++ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper - Add phantom creative and insomniac controls Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason return true; } @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - if (!entityplayer.isSpectator()) { -+ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper ++ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls BlockPos blockposition = entityplayer.blockPosition(); if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { diff --git a/patches/server/Add-tick-times-API-and-mspt-command.patch b/patches/server/Add-tick-times-API-and-mspt-command.patch index 11479ba47e..753a50cd37 100644 --- a/patches/server/Add-tick-times-API-and-mspt-command.patch +++ b/patches/server/Add-tick-times-API-and-mspt-command.patch @@ -132,11 +132,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private int playerIdleTimeout; private final long[] tickTimesNanos; private long aggregatedTickTimesNanos; -+ // Paper start ++ // Paper start - Add tick times API and /mspt command + public final TickTimes tickTimes5s = new TickTimes(100); + public final TickTimes tickTimes10s = new TickTimes(200); + public final TickTimes tickTimes60s = new TickTimes(1200); -+ // Paper end ++ // Paper end - Add tick times API and /mspt command @Nullable private KeyPair keyPair; @Nullable @@ -144,11 +144,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) j / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F; long l = Util.getNanos(); -+ // Paper start ++ // Paper start - Add tick times API and /mspt command + tickTimes5s.add(this.tickCount, j); + tickTimes10s.add(this.tickCount, j); + tickTimes60s.add(this.tickCount, j); -+ // Paper end ++ // Paper end - Add tick times API and /mspt command this.logTickTime(l - i); this.profiler.pop(); org.spigotmc.WatchdogThread.tick(); // Spigot @@ -157,7 +157,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + -+ // Paper start ++ // Paper start - Add tick times API and /mspt command + public static class TickTimes { + private final long[] times; + @@ -181,7 +181,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return ((double) total / (double) times.length) * 1.0E-6D; + } + } -+ // Paper end ++ // Paper end - Add tick times API and /mspt command } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Add-titleOverride-to-InventoryOpenEvent.patch b/patches/server/Add-titleOverride-to-InventoryOpenEvent.patch index 440c669b0b..41209eb54b 100644 --- a/patches/server/Add-titleOverride-to-InventoryOpenEvent.patch +++ b/patches/server/Add-titleOverride-to-InventoryOpenEvent.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { // CraftBukkit start this.containerMenu = container; -- if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper +- if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen + if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), Objects.requireNonNullElseGet(title, container::getTitle))); // Paper - Add titleOverride to InventoryOpenEvent // CraftBukkit end this.initMenu(container); @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper + if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen @@ -0,0 +0,0 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { } @@ -74,9 +74,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 //String title = inventory.getTitle(); // Paper - comment net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper -+ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent ++ if (result.getFirst() != null) adventure$title = result.getFirst(); // Paper - Add titleOverride to InventoryOpenEvent //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper + if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen player.containerMenu = container; diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Add-villager-reputation-API.patch b/patches/server/Add-villager-reputation-API.patch index 554d3c9167..fdd3d8f901 100644 --- a/patches/server/Add-villager-reputation-API.patch +++ b/patches/server/Add-villager-reputation-API.patch @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING; + }; + } -+ // Paper end ++ // Paper end - Add villager reputation API } static record GossipEntry(UUID target, GossipType type, int value) { diff --git a/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch index 9629bfd1aa..1f9a7b294d 100644 --- a/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch +++ b/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch @@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - Climbing should not bypass cramming gamerule if (!list.isEmpty()) { - // Paper - moved up + // Paper - don't run getEntities if we're not going to use its result; moved up @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { return !this.isRemoved() && this.collides; // CraftBukkit } diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index ae50f7c08b..79ab1d74e5 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -586,12 +586,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java @@ -0,0 +0,0 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); - // Paper start + // Paper start - Debugging if (MinecraftServer.getServer().isDebugging()) { - exception.printStackTrace(); + io.papermc.paper.util.TraceUtil.printStackTrace(exception); } - // Paper end + // Paper end - Debugging this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA)); diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch b/patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch index d8c8d8a245..fe92df7e90 100644 --- a/patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch +++ b/patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.hivePos == null) { return false; } else { -+ if (!this.level().isLoadedAndInBounds(this.hivePos)) return false; // Paper ++ if (!this.level().isLoadedAndInBounds(this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives BlockEntity tileentity = this.level().getBlockEntity(this.hivePos); return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby(); @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private boolean doesHiveHaveSpace(BlockPos pos) { -+ if (!this.level().isLoadedAndInBounds(pos)) return false; // Paper ++ if (!this.level().isLoadedAndInBounds(pos)) return false; // Paper - Do not allow bees to load chunks for beehives BlockEntity tileentity = this.level().getBlockEntity(pos); return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false; @@ -28,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean canBeeUse() { if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerToCenterThan(Bee.this.position(), 2.0D)) { -+ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper ++ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos); if (tileentity instanceof BeehiveBlockEntity) { @@ -36,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void start() { -+ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper ++ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - Do not allow bees to load chunks for beehives BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos); if (tileentity instanceof BeehiveBlockEntity) { diff --git a/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch index ff04083261..4fac73d4f3 100644 --- a/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch +++ b/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch @@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - objectset.remove(player); - if (objectset.isEmpty()) { -+ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully. ++ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully + if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); diff --git a/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch index 15a2e801cf..40eec0ec1b 100644 --- a/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch +++ b/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch @@ -3,7 +3,6 @@ From: Aikar <aikar@aikar.co> Date: Thu, 23 Apr 2020 01:36:39 -0400 Subject: [PATCH] Don't fire BlockFade on worldgen threads -Caused a deadlock diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -22,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } - return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); -+ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - diff on change, see "don't fire events in world generation" ++ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation" // CraftBukkit end } diff --git a/patches/server/Don-t-move-existing-players-to-world-spawn.patch b/patches/server/Don-t-move-existing-players-to-world-spawn.patch index 50a2b65ecc..7e3e8694db 100644 --- a/patches/server/Don-t-move-existing-players-to-world-spawn.patch +++ b/patches/server/Don-t-move-existing-players-to-world-spawn.patch @@ -21,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.advancements = server.getPlayerList().getPlayerAdvancements(this); this.setMaxUpStep(1.0F); - this.fudgeSpawnLocation(world); -+ // this.fudgeSpawnLocation(world); // Paper - don't move to spawn on login, only first join ++ // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn this.updateOptions(clientOptions); this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper @@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start if (nbttagcompound == null) { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login -+ player.fudgeSpawnLocation(worldserver1); // only move to spawn on first login, otherwise, stay where you are.... ++ player.fudgeSpawnLocation(worldserver1); // Paper - Don't move existing players to world spawn } // Paper end player.setServerLevel(worldserver1); diff --git a/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch index 79256d1a2a..f65857cd30 100644 --- a/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch +++ b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!list.isEmpty()) { - int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); -+ // Paper - moved up ++ // Paper - don't run getEntities if we're not going to use its result; moved up if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) { int j = 0; diff --git a/patches/server/Ensure-safe-gateway-teleport.patch b/patches/server/Ensure-safe-gateway-teleport.patch index ed45257899..51168bd3bd 100644 --- a/patches/server/Ensure-safe-gateway-teleport.patch +++ b/patches/server/Ensure-safe-gateway-teleport.patch @@ -13,14 +13,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!list.isEmpty()) { - TheEndGatewayBlockEntity.teleportEntity(world, pos, state, (Entity) list.get(world.random.nextInt(list.size())), blockEntity); -+ // Paper start ++ // Paper start - Ensure safe gateway teleport + for (Entity entity : list) { + if (entity.canChangeDimensions()) { + TheEndGatewayBlockEntity.teleportEntity(world, pos, state, entity, blockEntity); + break; + } + } -+ // Paper end ++ // Paper end - Ensure safe gateway teleport } if (blockEntity.age % 2400L == 0L) { diff --git a/patches/server/ExperienceOrb-should-call-EntitySpawnEvent.patch b/patches/server/ExperienceOrb-should-call-EntitySpawnEvent.patch index e3a04d5d50..42e8d8b920 100644 --- a/patches/server/ExperienceOrb-should-call-EntitySpawnEvent.patch +++ b/patches/server/ExperienceOrb-should-call-EntitySpawnEvent.patch @@ -13,10 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { double radius = world.spigotConfig.expMerge; - if (radius > 0) { -+ // Paper start - Call EntitySpawnEvent for ExperienceOrb entities -+ event = CraftEventFactory.callEntitySpawnEvent(entity); ++ event = CraftEventFactory.callEntitySpawnEvent(entity); // Call spawn event for ExperienceOrb entities + if (radius > 0 && !event.isCancelled() && !entity.isRemoved()) { -+ // Paper end - Call EntitySpawnEvent for ExperienceOrb entities - // Paper start - Maximum exp value when merging - Whole section has been tweaked, see comments for specifics + // Paper start - Maximum exp value when merging; Whole section has been tweaked, see comments for specifics final int maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue; final boolean mergeUnconditionally = world.paperConfig().entities.behavior.experienceMergeMaxValue <= 0; diff --git a/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch similarity index 79% rename from patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch rename to patches/server/Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch index 717f3e3f48..3ce338b7ea 100644 --- a/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch +++ b/patches/server/Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar <aikar@aikar.co> Date: Sun, 19 Apr 2020 00:05:46 -0400 -Subject: [PATCH] Fix Longstanding Broken behavior of PlayerJoinEvent +Subject: [PATCH] Fire PlayerJoinEvent when Player is actually ready For years, plugin developers have had to delay many things they do inside of the PlayerJoinEvent by 1 tick to make it actually work. @@ -35,13 +35,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable()); return; } -+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets - // Paper end + // Paper end - ignore and warn about illegal addEntity calls instead of crashing server ++ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets if (!(entity instanceof EnderDragonPart)) { EntityType<?> entitytypes = entity.getType(); + int i = entitytypes.clientTrackingRange() * 16; diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public double maxHealthCache; public boolean joining = true; public boolean sentListPacket = false; -+ public boolean supressTrackerForLogin = false; // Paper ++ public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent // CraftBukkit end public boolean isRealPlayer; // Paper @@ -62,12 +62,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.playersByUUID.put(player.getUUID(), player); // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below -+ // Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks ++ // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks + player.supressTrackerForLogin = true; + worldserver1.addNewPlayer(player); + this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer); + mountSavedVehicle(player, worldserver1, nbttagcompound); -+ // Paper end ++ // Paper end - Fire PlayerJoinEvent when Player is actually ready // CraftBukkit start CraftPlayer bukkitPlayer = player.getBukkitEntity(); @@ -75,8 +75,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); } player.sentListPacket = true; -+ player.supressTrackerForLogin = false; // Paper -+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now ++ player.supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready ++ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now // CraftBukkit end player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn @@ -84,11 +84,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect)); } -+ // Paper start - move vehicle into method so it can be called above - short circuit around that code ++ // Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code + onPlayerJoinFinish(player, worldserver1, s1); + } + private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) { -+ // Paper end ++ // Paper end - Fire PlayerJoinEvent when Player is actually ready if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) { CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle"); // CraftBukkit start @@ -96,10 +96,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ // Paper start ++ // Paper start - Fire PlayerJoinEvent when Player is actually ready + } + public void onPlayerJoinFinish(ServerPlayer player, ServerLevel worldserver1, String s1) { -+ // Paper end ++ // Paper end - Fire PlayerJoinEvent when Player is actually ready player.initInventoryMenu(); // CraftBukkit - Moved from above, added world // Paper start - Add to collideRule team if needed diff --git a/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/Fix-item-duplication-and-teleport-issues.patch similarity index 94% rename from patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch rename to patches/server/Fix-item-duplication-and-teleport-issues.patch index 5e7474e221..8b90fcb3c6 100644 --- a/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch +++ b/patches/server/Fix-item-duplication-and-teleport-issues.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar <aikar@aikar.co> Date: Sat, 25 Apr 2020 06:46:35 -0400 -Subject: [PATCH] Fix numerous item duplication issues and teleport issues +Subject: [PATCH] Fix item duplication and teleport issues This notably fixes the newest "Donkey Dupe", but also fixes a lot of dupe bugs in general around nether portals and entity world transfer @@ -38,12 +38,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public Entity teleportTo(ServerLevel worldserver, Vec3 location) { // CraftBukkit end -+ // Paper start - fix bad state entities causing dupes ++ // Paper start - Fix item duplication and teleport issues + if (!this.isAlive() || !this.valid) { + LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable()); + return null; + } -+ // Paper end ++ // Paper end - Fix item duplication and teleport issues if (this.level() instanceof ServerLevel && !this.isRemoved()) { this.level().getProfiler().push("changeDimension"); // CraftBukkit start @@ -51,11 +51,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end this.level().getProfiler().popPush("reloading"); -+ // Paper start - Change lead drop timing to prevent dupe ++ // Paper start - Fix item duplication and teleport issues + if (this instanceof Mob) { + ((Mob) this).dropLeash(true, true); // Paper drop lead + } -+ // Paper end ++ // Paper end - Fix item duplication and teleport issues Entity entity = this.getType().create(worldserver); if (entity != null) { @@ -75,7 +75,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean canChangeDimensions() { - return !this.isPassenger() && !this.isVehicle(); -+ return !this.isPassenger() && !this.isVehicle() && isAlive() && valid; // Paper ++ return !this.isPassenger() && !this.isVehicle() && isAlive() && valid; // Paper - Fix item duplication and teleport issues } public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) { @@ -90,7 +90,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (this.deathScore >= 0 && entityliving != null) { - entityliving.awardKillScore(this, this.deathScore, damageSource); - } -+ // if (this.deathScore >= 0 && entityliving != null) { // Paper moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent ++ // if (this.deathScore >= 0 && entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent + // entityliving.awardKillScore(this, this.deathScore, damageSource); + // } // Paper start - clear equipment if event is not cancelled diff --git a/patches/server/Fix-kick-event-leave-message-not-being-sent.patch b/patches/server/Fix-kick-event-leave-message-not-being-sent.patch index 485b62ca0b..976512fe59 100644 --- a/patches/server/Fix-kick-event-leave-message-not-being-sent.patch +++ b/patches/server/Fix-kick-event-leave-message-not-being-sent.patch @@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { public boolean joining = true; public boolean sentListPacket = false; - public boolean supressTrackerForLogin = false; // Paper + public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready - public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent // CraftBukkit end public boolean isRealPlayer; // Paper diff --git a/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch index e660772089..638a857c76 100644 --- a/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch +++ b/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch @@ -74,7 +74,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos); if (blockState.isAir()) { - world.setBlock(pos, blockEntity.movedState, 84); -+ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air ++ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3); } else { if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) { diff --git a/patches/server/Fix-sticky-pistons-and-BlockPistonRetractEvent.patch b/patches/server/Fix-sticky-pistons-and-BlockPistonRetractEvent.patch index 76a0cb0b45..01fee3afd6 100644 --- a/patches/server/Fix-sticky-pistons-and-BlockPistonRetractEvent.patch +++ b/patches/server/Fix-sticky-pistons-and-BlockPistonRetractEvent.patch @@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - Fix sticky pistons and BlockPistonRetractEvent world.setBlock(pos, iblockdata2, 20); - world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change + world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change world.blockUpdated(pos, iblockdata2.getBlock()); @@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock { if (type == 1 && !iblockdata3.isAir() && PistonBaseBlock.isPushable(iblockdata3, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata3.getPistonPushReaction() == PushReaction.NORMAL || iblockdata3.is(Blocks.PISTON) || iblockdata3.is(Blocks.STICKY_PISTON))) { diff --git a/patches/server/Fix-villager-trading-demand-MC-163962.patch b/patches/server/Fix-villager-trading-demand-MC-163962.patch index f1b2d790d5..bcb3116f73 100644 --- a/patches/server/Fix-villager-trading-demand-MC-163962.patch +++ b/patches/server/Fix-villager-trading-demand-MC-163962.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void updateDemand() { - this.demand = this.demand + this.uses - (this.maxUses - this.uses); -+ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper ++ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 } public ItemStack assemble() { diff --git a/patches/server/Force-close-world-loading-screen.patch b/patches/server/Force-close-world-loading-screen.patch index df9baa45d5..bd6a56f358 100644 --- a/patches/server/Force-close-world-loading-screen.patch +++ b/patches/server/Force-close-world-loading-screen.patch @@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -0,0 +0,0 @@ public abstract class PlayerList { - // Paper start - move vehicle into method so it can be called above - short circuit around that code + // Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code onPlayerJoinFinish(player, worldserver1, s1); + // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead + if (player.isDeadOrDying()) { @@ -29,4 +29,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - Send empty chunk } private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) { - // Paper end + // Paper end - Fire PlayerJoinEvent when Player is actually ready diff --git a/patches/server/Implement-Mob-Goal-API.patch b/patches/server/Implement-Mob-Goal-API.patch index 9a86d4fe20..b5d80da29b 100644 --- a/patches/server/Implement-Mob-Goal-API.patch +++ b/patches/server/Implement-Mob-Goal-API.patch @@ -751,13 +751,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be. private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector -+ // Paper start make sure goaltypes is never empty ++ // Paper start - Mob goal API; make sure goaltypes is never empty + public Goal() { + if (this.goalTypes.size() == 0) { + this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR); + } + } -+ // Paper end ++ // Paper end - Mob goal API + public abstract boolean canUse(); @@ -777,7 +777,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return Mth.positiveCeilDiv(serverTicks, 2); } -+ // Paper start - mob goal api ++ // Paper start - Mob goal api + private com.destroystokyo.paper.entity.ai.PaperVanillaGoal<?> vanillaGoal = null; + public <T extends org.bukkit.entity.Mob> com.destroystokyo.paper.entity.ai.Goal<T> asPaperVanillaGoal() { + if(this.vanillaGoal == null) { @@ -786,7 +786,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + //noinspection unchecked + return (com.destroystokyo.paper.entity.ai.Goal<T>) this.vanillaGoal; + } -+ // Paper end - mob goal api ++ // Paper end - Mob goal api + public static enum Flag { + UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR diff --git a/patches/server/Implement-Player-Client-Options-API.patch b/patches/server/Implement-Player-Client-Options-API.patch index 4992c23751..584240c6f3 100644 --- a/patches/server/Implement-Player-Client-Options-API.patch +++ b/patches/server/Implement-Player-Client-Options-API.patch @@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { this.advancements = server.getPlayerList().getPlayerAdvancements(this); this.setMaxUpStep(1.0F); - // this.fudgeSpawnLocation(world); // Paper - don't move to spawn on login, only first join + // this.fudgeSpawnLocation(world); // Paper - Don't move existing players to world spawn - this.updateOptions(clientOptions); + this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login diff --git a/patches/server/Improve-and-expand-AsyncCatcher.patch b/patches/server/Improve-and-expand-AsyncCatcher.patch index e8c3112bdb..12851c6776 100644 --- a/patches/server/Improve-and-expand-AsyncCatcher.patch +++ b/patches/server/Improve-and-expand-AsyncCatcher.patch @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) { // Paper + org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper - // Paper start + // Paper start - Prevent teleporting dead entities if (player.isRemoved()) { LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java diff --git a/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch index c443ce9196..2a4bd288ed 100644 --- a/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -79,11 +79,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start if (nbttagcompound == null) { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login -+ // Paper start - reset to main world spawn if first spawn or invalid world ++ // Paper start - reset to main world spawn if first spawn or invalid world + } + if (nbttagcompound == null || invalidPlayerWorld) { -+ // Paper end - player.fudgeSpawnLocation(worldserver1); // only move to spawn on first login, otherwise, stay where you are.... ++ // Paper end - reset to main world spawn if first spawn or invalid world + player.fudgeSpawnLocation(worldserver1); // Paper - Don't move existing players to world spawn } // Paper end diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java diff --git a/patches/server/Optimise-chunk-tick-iteration.patch b/patches/server/Optimise-chunk-tick-iteration.patch index e5a5615f81..e53d4070f2 100644 --- a/patches/server/Optimise-chunk-tick-iteration.patch +++ b/patches/server/Optimise-chunk-tick-iteration.patch @@ -162,7 +162,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 //this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used } @@ -0,0 +0,0 @@ public abstract class DistanceManager { - if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully. + if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); - this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); diff --git a/patches/server/Optimize-Pathfinding.patch b/patches/server/Optimize-Pathfinding.patch index f32745f2c0..327e70e688 100644 --- a/patches/server/Optimize-Pathfinding.patch +++ b/patches/server/Optimize-Pathfinding.patch @@ -14,20 +14,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.moveTo(this.createPath(x, y, z, 1), speed); } -+ // Paper start - optimise pathfinding ++ // Paper start - Perf: Optimise pathfinding + private int lastFailure = 0; + private int pathfindFailures = 0; -+ // Paper end ++ // Paper end - Perf: Optimise pathfinding + public boolean moveTo(Entity entity, double speed) { -+ // Paper start - Pathfinding optimizations ++ // Paper start - Perf: Optimise pathfinding + if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) { + return false; + } -+ // Paper end ++ // Paper end - Perf: Optimise pathfinding Path path = this.createPath(entity, 1); - return path != null && this.moveTo(path, speed); -+ // Paper start - Pathfinding optimizations ++ // Paper start - Perf: Optimise pathfinding + if (path != null && this.moveTo(path, speed)) { + this.lastFailure = 0; + this.pathfindFailures = 0; @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.lastFailure = net.minecraft.server.MinecraftServer.currentTick; + return false; + } -+ // Paper end ++ // Paper end - Perf: Optimise pathfinding } public boolean moveTo(@Nullable Path path, double speed) { diff --git a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch index 2e2cc71dd1..e47d59976b 100644 --- a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch +++ b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { double radius = world.spigotConfig.expMerge; if (radius > 0) { -+ // Paper start - Maximum exp value when merging - Whole section has been tweaked, see comments for specifics ++ // Paper start - Maximum exp value when merging; Whole section has been tweaked, see comments for specifics + final int maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue; + final boolean mergeUnconditionally = world.paperConfig().entities.behavior.experienceMergeMaxValue <= 0; + if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { xp.value += loopItem.value; loopItem.discard(); -+ } // Paper end ++ } // Paper end - Maximum exp value when merging } } } diff --git a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch index bc6257ed45..b63029fa43 100644 --- a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean wonGame; private int containerUpdateDelay; // Paper public long loginTime; // Paper -+ public int patrolSpawnDelay; // Paper - per player patrol spawns ++ public int patrolSpawnDelay; // Paper - Pillager patrol spawn settings and per player options // Paper start - cancellable death event public boolean queueHealthUpdatePacket = false; public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; @@ -30,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { - if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper -+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Pillager patrol spawn settings and per player options if (!spawnMonsters) { return 0; } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - --this.nextTick; - if (this.nextTick > 0) { -+ // Paper start - Patrol settings ++ // Paper start - Pillager patrol spawn settings and per player options + // Random player selection moved up for per player spawning and configuration + int j = world.players().size(); + if (j < 1) { @@ -82,7 +82,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (randomsource.nextInt(5) != 0) { + if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) { + if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { -+ // Paper end ++ // Paper end - Pillager patrol spawn settings and per player options return 0; } else { - int j = world.players().size(); diff --git a/patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch index 23272bbc9f..02d92dfad2 100644 --- a/patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch +++ b/patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable()); + return; + } -+ // Paper end ++ // Paper end - ignore and warn about illegal addEntity calls instead of crashing server if (!(entity instanceof EnderDragonPart)) { EntityType<?> entitytypes = entity.getType(); int i = entitytypes.clientTrackingRange() * 16; @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void onTrackingStart(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot - ServerLevel.this.getChunkSource().addEntity(entity); -+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - moved down below valid=true ++ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; diff --git a/patches/server/Prevent-opening-inventories-when-frozen.patch b/patches/server/Prevent-opening-inventories-when-frozen.patch index da1f19a2e9..96567da3ef 100644 --- a/patches/server/Prevent-opening-inventories-when-frozen.patch +++ b/patches/server/Prevent-opening-inventories-when-frozen.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper end - if (!this.level().isClientSide && !this.containerMenu.stillValid(this)) { -+ if (!this.level().isClientSide && this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - auto close while frozen ++ if (!this.level().isClientSide && this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - Prevent opening inventories when frozen this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper this.containerMenu = this.inventoryMenu; } @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start this.containerMenu = container; - this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); -+ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper ++ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen // CraftBukkit end this.initMenu(container); return OptionalInt.of(this.containerCounter); @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper -+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper ++ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen player.containerMenu = container; player.initMenu(container); } @@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(inventory.getTitle()); // Paper //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment - player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper -+ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper ++ if (!player.isImmobile()) player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper - Prevent opening inventories when frozen player.containerMenu = container; player.initMenu(container); } diff --git a/patches/server/Prevent-teleporting-dead-entities.patch b/patches/server/Prevent-teleporting-dead-entities.patch index d3a80aee8b..45b4ea4b30 100644 --- a/patches/server/Prevent-teleporting-dead-entities.patch +++ b/patches/server/Prevent-teleporting-dead-entities.patch @@ -12,13 +12,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) { // Paper -+ // Paper start ++ // Paper start - Prevent teleporting dead entities + if (player.isRemoved()) { + LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); + if (server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player"); + return; + } -+ // Paper end ++ // Paper end - Prevent teleporting dead entities // CraftBukkit start if (Float.isNaN(f)) { f = 0; diff --git a/patches/server/Properly-resend-entities.patch b/patches/server/Properly-resend-entities.patch index 99ccc56552..67f7a67639 100644 --- a/patches/server/Properly-resend-entities.patch +++ b/patches/server/Properly-resend-entities.patch @@ -102,7 +102,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -0,0 +0,0 @@ public abstract class PlayerList { - ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now + ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now // CraftBukkit end - player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn diff --git a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch index 51a191a670..01cfcaa196 100644 --- a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { BlockPos blockposition = BlockPos.containing(d4, d5, d6); BlockState iblockdata = this.level.getBlockState(blockposition); -+ if (!iblockdata.isDestroyable()) continue; // Paper ++ if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed FluidState fluid = iblockdata.getFluidState(); // Paper if (!this.level.isInWorldBounds(blockposition)) { @@ -32,10 +32,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { // CraftBukkit start - tree generation if (this.captureTreeGeneration) { -+ // Paper start ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed + BlockState type = getBlockState(pos); + if (!type.isDestroyable()) return false; -+ // Paper end ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed CraftBlockState blockstate = this.capturedBlockStates.get(pos); if (blockstate == null) { blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags); @@ -71,12 +71,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) { Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING); -+ // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) + Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below + if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) { + return false; + } -+ // Paper end - prevent retracting when we're facing the wrong way ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true); if (!world.isClientSide) { @@ -85,7 +85,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 world.setBlock(pos, iblockdata2, 20); - world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); -+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change ++ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change world.blockUpdated(pos, iblockdata2.getBlock()); iblockdata2.updateNeighbourShapes(world, pos, 2); if (this.isSticky) { @@ -94,14 +94,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } else { - world.removeBlock(pos.relative(enumdirection), false); -+ // Paper start - fix headless pistons breaking blocks ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks + BlockPos headPos = pos.relative(enumdirection); + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston. + world.removeBlock(headPos, false); + } else { -+ ((ServerLevel)world).getChunkSource().blockChanged(headPos); // ... fix client desync ++ ((ServerLevel) world).getChunkSource().blockChanged(headPos); // ... fix client desync + } -+ // Paper end - fix headless pistons breaking blocks ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed } world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F); @@ -114,7 +114,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Deprecated public void onExplosionHit(BlockState state, Level world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) { - if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) { -+ if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper ++ if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed Block block = state.getBlock(); boolean flag = explosion.getIndirectSourceEntity() instanceof Player; @@ -123,7 +123,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Deprecated public boolean canBeReplaced(BlockState state, BlockPlaceContext context) { - return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())); -+ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper; ++ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed } /** @deprecated */ @@ -131,11 +131,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.legacySolid; } -+ // Paper start ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed + public final boolean isDestroyable() { + return getBlock().isDestroyable(); + } -+ // Paper end ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType<?> type) { return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type); @@ -145,7 +145,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public PushReaction getPistonPushReaction() { - return this.pushReaction; -+ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper ++ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper - Protect Bedrock and End Portal/Frames from being destroyed } public boolean isSolidRender(BlockGetter world, BlockPos pos) { @@ -157,13 +157,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int j = -1; j < 3; ++j) { for (int k = -1; k < 4; ++k) { temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); -+ // Paper start - prevent destroying unbreakable blocks ++ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed + if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { + if (!this.level.getBlockState(temp).isDestroyable()) { + return false; + } + } -+ // Paper end - prevent destroying unbreakable blocks ++ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed if (k < 0 && !this.level.getBlockState(temp).isSolid()) { return false; } diff --git a/patches/server/Reduce-Either-Optional-allocation.patch b/patches/server/Reduce-Either-Optional-allocation.patch index ce6fe7068b..ea84670064 100644 --- a/patches/server/Reduce-Either-Optional-allocation.patch +++ b/patches/server/Reduce-Either-Optional-allocation.patch @@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static final class Left<L, R> extends Either<L, R> { - private final L value; -+ private final L value; private Optional<L> valueOptional; // Paper - reduce the optional allocation... ++ private final L value; private Optional<L> valueOptional; // Paper - Perf: Reduce Either Optional allocation public Left(final L value) { this.value = value; @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public Optional<L> left() { - return Optional.of(value); -+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation... ++ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation } @Override @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static final class Right<L, R> extends Either<L, R> { - private final R value; -+ private final R value; private Optional<R> valueOptional; // Paper - reduce the optional allocation... ++ private final R value; private Optional<R> valueOptional; // Paper - Perf: Reduce Either Optional allocation public Right(final R value) { this.value = value; @@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public Optional<R> right() { - return Optional.of(value); -+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - reduce the optional allocation... ++ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation } @Override diff --git a/patches/server/Reduce-memory-footprint-of-NBTTagCompound.patch b/patches/server/Reduce-memory-footprint-of-CompoundTag.patch similarity index 86% rename from patches/server/Reduce-memory-footprint-of-NBTTagCompound.patch rename to patches/server/Reduce-memory-footprint-of-CompoundTag.patch index d96a736ac6..d7fbad64df 100644 --- a/patches/server/Reduce-memory-footprint-of-NBTTagCompound.patch +++ b/patches/server/Reduce-memory-footprint-of-CompoundTag.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf <Spottedleaf@users.noreply.github.com> Date: Mon, 6 Apr 2020 17:39:25 -0700 -Subject: [PATCH] Reduce memory footprint of NBTTagCompound +Subject: [PATCH] Reduce memory footprint of CompoundTag Fastutil maps are going to have a lower memory footprint - which is important because we clone chunk data after reading it for safety. @@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static CompoundTag loadCompound(DataInput input, NbtAccounter tracker) throws IOException { tracker.accountBytes(48L); - Map<String, Tag> map = Maps.newHashMap(); -+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - reduce memory footprint of NBTTagCompound ++ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag byte b; while((b = input.readByte()) != 0) { @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public CompoundTag() { - this(Maps.newHashMap()); -+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - reduce memory footprint of NBTTagCompound ++ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - Reduce memory footprint of CompoundTag } @Override @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public CompoundTag copy() { - Map<String, Tag> map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy)); - return new CompoundTag(map); -+ // Paper start - reduce memory footprint of NBTTagCompound ++ // Paper start - Reduce memory footprint of CompoundTag + it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<String, Tag> ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f); + java.util.Iterator<java.util.Map.Entry<String, Tag>> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator(); + while (iterator.hasNext()) { @@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + return new CompoundTag(ret); -+ // Paper end - reduce memory footprint of NBTTagCompound ++ // Paper end - Reduce memory footprint of CompoundTag } @Override diff --git a/patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch index ca87a1bbe9..2b5f319fe4 100644 --- a/patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch +++ b/patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch @@ -31,14 +31,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.clients.clear(); } -+ // Paper start ++ // Paper start - don't wait for remote connections + public void stopNonBlocking() { + this.running = false; + for (RconClient client : this.clients) { + client.running = false; + } + } -+ // Paper stop ++ // Paper stop - don't wait for remote connections private void closeSocket(ServerSocket socket) { LOGGER.debug("closeSocket: {}", (Object)socket); diff --git a/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch index 6267920ffd..ac1ec90499 100644 --- a/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch +++ b/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper end // Todo: Installation script -+ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size ++ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html OptionParser parser = new OptionParser() { { this.acceptsAll(Main.asList("?", "help"), "Show the help"); diff --git a/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch index 81719fe157..643f0e86f4 100644 --- a/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch +++ b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch @@ -21,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (j1 = 0; j1 < 128; ++j1) { for (k1 = 0; k1 < 128; ++k1) { - Holder<Biome> holder = world.getBiome(blockposition_mutableblockposition.set((l + k1) * i, 0, (i1 + j1) * i)); -+ Holder<Biome> holder = world.getUncachedNoiseBiome((l + k1) * i, 0, (i1 + j1) * i); // Paper ++ Holder<Biome> holder = world.getUncachedNoiseBiome((l + k1) * i, 0, (i1 + j1) * i); // Paper - Perf: Use seed based lookup for treasure maps aboolean[j1 * 128 + k1] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES); } diff --git a/patches/server/Use-single-player-info-update-packet-on-join.patch b/patches/server/Use-single-player-info-update-packet-on-join.patch index d1e1688957..cd9466b9b2 100644 --- a/patches/server/Use-single-player-info-update-packet-on-join.patch +++ b/patches/server/Use-single-player-info-update-packet-on-join.patch @@ -47,5 +47,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - Use single player info update packet on join player.sentListPacket = true; - player.supressTrackerForLogin = false; // Paper - ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now + player.supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready + ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now diff --git a/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch index edcd10c966..8cdf990217 100644 --- a/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch +++ b/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed -+ // Paper end ++ // Paper end - validate pick item position this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, this.player.getInventory().selected, this.player.getInventory().getItem(this.player.getInventory().selected))); this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, packet.getSlot(), this.player.getInventory().getItem(packet.getSlot()))); this.player.connection.send(new ClientboundSetCarriedItemPacket(this.player.getInventory().selected)); diff --git a/patches/server/Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/Wait-for-Async-Tasks-during-shutdown.patch index bb40d7de24..f199ceaa6f 100644 --- a/patches/server/Wait-for-Async-Tasks-during-shutdown.patch +++ b/patches/server/Wait-for-Async-Tasks-during-shutdown.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start if (this.server != null) { this.server.disablePlugins(); -+ this.server.waitForAsyncTasksShutdown(); // Paper ++ this.server.waitForAsyncTasksShutdown(); // Paper - Wait for Async Tasks during shutdown } // CraftBukkit end this.getConnection().stop(); @@ -29,7 +29,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload } -+ // Paper start ++ // Paper start - Wait for Async Tasks during shutdown + public void waitForAsyncTasksShutdown() { + int pollCount = 0; + @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + )); + } + } -+ // Paper end ++ // Paper end - Wait for Async Tasks during shutdown + @Override public void reloadData() { diff --git a/patches/server/misc-debugging-dumps.patch b/patches/server/misc-debugging-dumps.patch index 18f0e71375..08dfc42c83 100644 --- a/patches/server/misc-debugging-dumps.patch +++ b/patches/server/misc-debugging-dumps.patch @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 MutableComponent ichatmutablecomponent = Component.literal(exception.getMessage() == null ? exception.getClass().getName() : exception.getMessage()); - if (Commands.LOGGER.isDebugEnabled()) { -+ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper ++ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper - Debugging Commands.LOGGER.error("Command exception: /{}", s, exception); StackTraceElement[] astacktraceelement = exception.getStackTrace(); @@ -49,7 +49,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start private boolean hasStopped = false; public volatile boolean hasFullyShutdown = false; // Paper -+ private boolean hasLoggedStop = false; // Paper ++ private boolean hasLoggedStop = false; // Paper - Debugging private final Object stopLock = new Object(); public final boolean hasStopped() { synchronized (this.stopLock) { @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.hasStopped) return; this.hasStopped = true; } -+ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper ++ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging // Paper start - kill main thread, and kill it hard shutdownThread = Thread.currentThread(); org.spigotmc.WatchdogThread.doStop(); // Paper @@ -65,8 +65,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void safeShutdown(boolean waitForShutdown, boolean isRestarting) { this.isRestarting = isRestarting; -+ this.hasLoggedStop = true; // Paper -+ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper ++ this.hasLoggedStop = true; // Paper - Debugging ++ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging // Paper end this.running = false; if (waitForShutdown) { @@ -78,11 +78,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.connection.resumeInboundAfterProtocolChange(); } catch (Exception exception) { ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); -+ // Paper start ++ // Paper start - Debugging + if (MinecraftServer.getServer().isDebugging()) { + exception.printStackTrace(); + } -+ // Paper end ++ // Paper end - Debugging this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA)); this.connection.disconnect(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA); } @@ -94,7 +94,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 plugin.getDescription().getFullName(), "This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin" )); -+ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper ++ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging } io.papermc.paper.plugin.PluginInitializerManager.reload(this.console); // Paper this.loadPlugins();