From 07ee610d8e2e65ef20b87928cfa0fcc21bfda75a Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Wed, 7 Jun 2023 15:41:25 -0700 Subject: [PATCH] more patches --- ...dd-PlayerAttackEntityCooldownResetEvent.patch | 0 ...phantom-creative-and-insomniac-controls.patch | 8 ++++---- ...Dead-Player-s-shouldn-t-be-able-to-move.patch | 0 ...-allow-bees-to-load-chunks-for-beehives.patch | 16 ++++++++-------- ...f-player-is-attempted-to-be-removed-fro.patch | 2 +- ...on-t-fire-BlockFade-on-worldgen-threads.patch | 0 ...-t-move-existing-players-to-world-spawn.patch | 4 ++-- ...run-entity-collision-code-if-not-needed.patch | 12 ++++++------ .../server/Don-t-tick-dead-players.patch | 0 ...ding-Broken-behavior-of-PlayerJoinEvent.patch | 0 ...item-duplication-issues-and-teleport-is.patch | 12 ++++++------ .../Implement-Player-Client-Options-API.patch | 0 .../server/Improved-Watchdog-Support.patch | 16 ++++++++-------- ...o-spawn-point-if-spawn-in-unloaded-worl.patch | 0 .../Optimize-Collision-to-not-load-chunks.patch | 4 ++-- ...e-GoalSelector-Goal.Flag-Set-operations.patch | 0 .../server/Optimize-Pathfinding.patch | 0 ...ol-spawn-settings-and-per-player-option.patch | 0 ...ble-PlayerChunkMap-adds-crashing-server.patch | 0 ...Prevent-opening-inventories-when-frozen.patch | 8 ++++---- .../Reduce-Either-Optional-allocation.patch | 0 ...duce-memory-footprint-of-NBTTagCompound.patch | 0 ...-Connections-shouldn-t-hold-up-shutdown.patch | 0 23 files changed, 41 insertions(+), 41 deletions(-) rename patches/{unapplied => }/server/Add-PlayerAttackEntityCooldownResetEvent.patch (100%) rename patches/{unapplied => }/server/Add-phantom-creative-and-insomniac-controls.patch (87%) rename patches/{unapplied => }/server/Dead-Player-s-shouldn-t-be-able-to-move.patch (100%) rename patches/{unapplied => }/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch (70%) rename patches/{unapplied => }/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch (92%) rename patches/{unapplied => }/server/Don-t-fire-BlockFade-on-worldgen-threads.patch (100%) rename patches/{unapplied => }/server/Don-t-move-existing-players-to-world-spawn.patch (96%) rename patches/{unapplied => }/server/Don-t-run-entity-collision-code-if-not-needed.patch (73%) rename patches/{unapplied => }/server/Don-t-tick-dead-players.patch (100%) rename patches/{unapplied => }/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch (100%) rename patches/{unapplied => }/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch (94%) rename patches/{unapplied => }/server/Implement-Player-Client-Options-API.patch (100%) rename patches/{unapplied => }/server/Improved-Watchdog-Support.patch (97%) rename patches/{unapplied => }/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch (100%) rename patches/{unapplied => }/server/Optimize-Collision-to-not-load-chunks.patch (98%) rename patches/{unapplied => }/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch (100%) rename patches/{unapplied => }/server/Optimize-Pathfinding.patch (100%) rename patches/{unapplied => }/server/Pillager-patrol-spawn-settings-and-per-player-option.patch (100%) rename patches/{unapplied => }/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch (100%) rename patches/{unapplied => }/server/Prevent-opening-inventories-when-frozen.patch (87%) rename patches/{unapplied => }/server/Reduce-Either-Optional-allocation.patch (100%) rename patches/{unapplied => }/server/Reduce-memory-footprint-of-NBTTagCompound.patch (100%) rename patches/{unapplied => }/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch (100%) diff --git a/patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch similarity index 100% rename from patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch rename to patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch diff --git a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch b/patches/server/Add-phantom-creative-and-insomniac-controls.patch similarity index 87% rename from patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch rename to patches/server/Add-phantom-creative-and-insomniac-controls.patch index 3399991fb9..6606f37f53 100644 --- a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch +++ b/patches/server/Add-phantom-creative-and-insomniac-controls.patch @@ -34,10 +34,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java @@ -0,0 +0,0 @@ public class PhantomSpawner implements CustomSpawner { while (iterator.hasNext()) { - Player entityhuman = (Player) iterator.next(); + ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- if (!entityhuman.isSpectator()) { -+ if (!entityhuman.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityhuman.isCreative())) { // Paper - BlockPos blockposition = entityhuman.blockPosition(); +- if (!entityplayer.isSpectator()) { ++ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper + BlockPos blockposition = entityplayer.blockPosition(); if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { diff --git a/patches/unapplied/server/Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/Dead-Player-s-shouldn-t-be-able-to-move.patch similarity index 100% rename from patches/unapplied/server/Dead-Player-s-shouldn-t-be-able-to-move.patch rename to patches/server/Dead-Player-s-shouldn-t-be-able-to-move.patch diff --git a/patches/unapplied/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch b/patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch similarity index 70% rename from patches/unapplied/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch rename to patches/server/Do-not-allow-bees-to-load-chunks-for-beehives.patch index fbaa55bfb0..d8c8d8a245 100644 --- a/patches/unapplied/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,31 +12,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.hivePos == null) { return false; } else { -+ if (!this.level.isLoadedAndInBounds(hivePos)) return false; // Paper - BlockEntity tileentity = this.level.getBlockEntity(this.hivePos); ++ if (!this.level().isLoadedAndInBounds(this.hivePos)) return false; // Paper + BlockEntity tileentity = this.level().getBlockEntity(this.hivePos); return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby(); @@ -0,0 +0,0 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { } private boolean doesHiveHaveSpace(BlockPos pos) { -+ if (!this.level.isLoadedAndInBounds(pos)) return false; // Paper - BlockEntity tileentity = this.level.getBlockEntity(pos); ++ if (!this.level().isLoadedAndInBounds(pos)) return false; // Paper + BlockEntity tileentity = this.level().getBlockEntity(pos); return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false; @@ -0,0 +0,0 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @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 - BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos); ++ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper + BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos); if (tileentity instanceof BeehiveBlockEntity) { @@ -0,0 +0,0 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public void start() { -+ if (!Bee.this.level.isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos); ++ if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper + BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos); if (tileentity instanceof BeehiveBlockEntity) { diff --git a/patches/unapplied/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 similarity index 92% rename from patches/unapplied/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch rename to patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch index ff04083261..c143fab0de 100644 --- a/patches/unapplied/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 @@ -20,4 +20,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); - //this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used + this.playerTicketManager.update(i, Integer.MAX_VALUE, false); diff --git a/patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch similarity index 100% rename from patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch rename to patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch diff --git a/patches/unapplied/server/Don-t-move-existing-players-to-world-spawn.patch b/patches/server/Don-t-move-existing-players-to-world-spawn.patch similarity index 96% rename from patches/unapplied/server/Don-t-move-existing-players-to-world-spawn.patch rename to patches/server/Don-t-move-existing-players-to-world-spawn.patch index 2253367ead..f04bca47dd 100644 --- a/patches/unapplied/server/Don-t-move-existing-players-to-world-spawn.patch +++ b/patches/server/Don-t-move-existing-players-to-world-spawn.patch @@ -28,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { position = Vec3.atCenterOf(world.getSharedSpawnPos()); } - this.level = world; + this.setLevel(world); - this.setPos(position); + this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet } @@ -45,4 +45,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + player.fudgeSpawnLocation(worldserver1); // only move to spawn on first login, otherwise, stay where you are.... } // Paper end - player.setLevel(worldserver1); + player.setServerLevel(worldserver1); diff --git a/patches/unapplied/server/Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch similarity index 73% rename from patches/unapplied/server/Don-t-run-entity-collision-code-if-not-needed.patch rename to patches/server/Don-t-run-entity-collision-code-if-not-needed.patch index 71283a5e3d..9421551a00 100644 --- a/patches/unapplied/server/Don-t-run-entity-collision-code-if-not-needed.patch +++ b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch @@ -16,8 +16,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (this.level.isClientSide()) { - this.level.getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush); + if (this.level().isClientSide()) { + this.level().getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush); } else { + // Paper start - don't run getEntities if we're not going to use its result + if (!this.isPushable()) { @@ -28,15 +28,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + -+ int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); -+ if (i <= 0 && level.paperConfig().collisions.maxEntityCollisions <= 0) { ++ int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); ++ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) { + return; + } + // Paper end - don't run getEntities if we're not going to use its result - List list = this.level.getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); + List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); if (!list.isEmpty()) { -- int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); +- int i = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); + // Paper - moved up int j; diff --git a/patches/unapplied/server/Don-t-tick-dead-players.patch b/patches/server/Don-t-tick-dead-players.patch similarity index 100% rename from patches/unapplied/server/Don-t-tick-dead-players.patch rename to patches/server/Don-t-tick-dead-players.patch diff --git a/patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch similarity index 100% rename from patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch rename to patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch diff --git a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch similarity index 94% rename from patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch rename to patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch index d91260c361..64f50e6165 100644 --- a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch +++ b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch @@ -28,8 +28,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return null; } // CraftBukkit end -- ItemEntity entityitem = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack); -+ ItemEntity entityitem = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - clone so we can destroy original +- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack); ++ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original + stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe entityitem.setDefaultPickUpDelay(); @@ -39,18 +39,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Entity teleportTo(ServerLevel worldserver, PositionImpl location) { // CraftBukkit end + // Paper start - fix bad state entities causing dupes -+ if (!isAlive() || !valid) { ++ if (!this.isAlive() || !this.valid) { + LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable()); + return null; + } + // Paper end - if (this.level instanceof ServerLevel && !this.isRemoved()) { - this.level.getProfiler().push("changeDimension"); + if (this.level() instanceof ServerLevel && !this.isRemoved()) { + this.level().getProfiler().push("changeDimension"); // CraftBukkit start @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { // CraftBukkit end - this.level.getProfiler().popPush("reloading"); + this.level().getProfiler().popPush("reloading"); + // Paper start - Change lead drop timing to prevent dupe + if (this instanceof Mob) { + ((Mob) this).dropLeash(true, true); // Paper drop lead diff --git a/patches/unapplied/server/Implement-Player-Client-Options-API.patch b/patches/server/Implement-Player-Client-Options-API.patch similarity index 100% rename from patches/unapplied/server/Implement-Player-Client-Options-API.patch rename to patches/server/Implement-Player-Client-Options-API.patch diff --git a/patches/unapplied/server/Improved-Watchdog-Support.patch b/patches/server/Improved-Watchdog-Support.patch similarity index 97% rename from patches/unapplied/server/Improved-Watchdog-Support.patch rename to patches/server/Improved-Watchdog-Support.patch index f8e0d113f0..d7ab2f8288 100644 --- a/patches/unapplied/server/Improved-Watchdog-Support.patch +++ b/patches/server/Improved-Watchdog-Support.patch @@ -92,7 +92,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); - Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system + Thread thread = new Thread(() -> { @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - protected VoxelShape computeNext() { +@@ -0,0 +0,0 @@ public class BlockCollisions extends AbstractIterator { + protected T computeNext() { while(true) { if (this.cursor.advance()) { - int i = this.cursor.nextX(); diff --git a/patches/unapplied/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch similarity index 100% rename from patches/unapplied/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch rename to patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch diff --git a/patches/unapplied/server/Optimize-Pathfinding.patch b/patches/server/Optimize-Pathfinding.patch similarity index 100% rename from patches/unapplied/server/Optimize-Pathfinding.patch rename to patches/server/Optimize-Pathfinding.patch diff --git a/patches/unapplied/server/Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch similarity index 100% rename from patches/unapplied/server/Pillager-patrol-spawn-settings-and-per-player-option.patch rename to patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch diff --git a/patches/unapplied/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch similarity index 100% rename from patches/unapplied/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch rename to patches/server/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch diff --git a/patches/unapplied/server/Prevent-opening-inventories-when-frozen.patch b/patches/server/Prevent-opening-inventories-when-frozen.patch similarity index 87% rename from patches/unapplied/server/Prevent-opening-inventories-when-frozen.patch rename to patches/server/Prevent-opening-inventories-when-frozen.patch index 370b369832..da1f19a2e9 100644 --- a/patches/unapplied/server/Prevent-opening-inventories-when-frozen.patch +++ b/patches/server/Prevent-opening-inventories-when-frozen.patch @@ -9,11 +9,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { - containerUpdateDelay = level.paperConfig().tickRates.containerUpdate; + containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate; } // Paper end -- if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) { -+ if (!this.level.isClientSide && this.containerMenu != this.inventoryMenu && (isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - auto close while frozen +- 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 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 (!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 // CraftBukkit end this.initMenu(container); return OptionalInt.of(this.containerCounter); diff --git a/patches/unapplied/server/Reduce-Either-Optional-allocation.patch b/patches/server/Reduce-Either-Optional-allocation.patch similarity index 100% rename from patches/unapplied/server/Reduce-Either-Optional-allocation.patch rename to patches/server/Reduce-Either-Optional-allocation.patch diff --git a/patches/unapplied/server/Reduce-memory-footprint-of-NBTTagCompound.patch b/patches/server/Reduce-memory-footprint-of-NBTTagCompound.patch similarity index 100% rename from patches/unapplied/server/Reduce-memory-footprint-of-NBTTagCompound.patch rename to patches/server/Reduce-memory-footprint-of-NBTTagCompound.patch diff --git a/patches/unapplied/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch similarity index 100% rename from patches/unapplied/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch rename to patches/server/Remote-Connections-shouldn-t-hold-up-shutdown.patch