From 88aa8528c9a5c8f5bdab7f1487aff64c1b6c3af8 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 27 Oct 2024 10:26:44 +0100 Subject: [PATCH] More patches --- ...er-desync-when-new-players-are-added.patch | 20 +-- .../Incremental-chunk-and-player-saving.patch | 26 ++- .../server/Lag-compensation-ticks.patch | 14 +- ...on-checking-in-player-move-packet-ha.patch | 0 .../server/Optimise-general-POI-access.patch | 24 +-- .../server/Write-SavedData-IO-async.patch | 164 ------------------ 6 files changed, 39 insertions(+), 209 deletions(-) rename patches/{unapplied => }/server/Fix-entity-tracker-desync-when-new-players-are-added.patch (82%) rename patches/{unapplied => }/server/Incremental-chunk-and-player-saving.patch (90%) rename patches/{unapplied => }/server/Lag-compensation-ticks.patch (93%) rename patches/{unapplied => }/server/Optimise-collision-checking-in-player-move-packet-ha.patch (100%) rename patches/{unapplied => }/server/Optimise-general-POI-access.patch (98%) delete mode 100644 patches/unapplied/server/Write-SavedData-IO-async.patch diff --git a/patches/unapplied/server/Fix-entity-tracker-desync-when-new-players-are-added.patch b/patches/server/Fix-entity-tracker-desync-when-new-players-are-added.patch similarity index 82% rename from patches/unapplied/server/Fix-entity-tracker-desync-when-new-players-are-added.patch rename to patches/server/Fix-entity-tracker-desync-when-new-players-are-added.patch index ca5a99f81a..e80eb74101 100644 --- a/patches/unapplied/server/Fix-entity-tracker-desync-when-new-players-are-added.patch +++ b/patches/server/Fix-entity-tracker-desync-when-new-players-are-added.patch @@ -83,18 +83,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) { + if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) { // Paper - fix desync when a player is added to the tracker - int i; - int j; - + byte b0 = Mth.packDegrees(this.entity.getYRot()); + byte b1 = Mth.packDegrees(this.entity.getXRot()); + boolean flag = Math.abs(b0 - this.lastSentYRot) >= 1 || Math.abs(b1 - this.lastSentXRot) >= 1; @@ -0,0 +0,0 @@ public class ServerEntity { - long i1 = this.positionCodec.encodeZ(vec3d); - boolean flag6 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; + long k = this.positionCodec.encodeZ(vec3d); + boolean flag5 = i < -32768L || i > 32767L || j < -32768L || j > 32767L || k < -32768L || k > 32767L; -- if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { -+ if (!this.forceStateResync && !flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker - if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { - if (flag2) { - packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.onGround()); +- if (!flag5 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { ++ if (!this.forceStateResync && !flag5 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker + if ((!flag2 || !flag) && !(this.entity instanceof AbstractArrow)) { + if (flag2) { + packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) i), (short) ((int) j), (short) ((int) k), this.entity.onGround()); @@ -0,0 +0,0 @@ public class ServerEntity { } diff --git a/patches/unapplied/server/Incremental-chunk-and-player-saving.patch b/patches/server/Incremental-chunk-and-player-saving.patch similarity index 90% rename from patches/unapplied/server/Incremental-chunk-and-player-saving.patch rename to patches/server/Incremental-chunk-and-player-saving.patch index 91f76e3917..49a1b487a9 100644 --- a/patches/unapplied/server/Incremental-chunk-and-player-saving.patch +++ b/patches/server/Incremental-chunk-and-player-saving.patch @@ -21,28 +21,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } --this.ticksUntilAutosave; -- // CraftBukkit start -- if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { -- this.ticksUntilAutosave = this.autosavePeriod; -- // CraftBukkit end -- MinecraftServer.LOGGER.debug("Autosave started"); -- this.profiler.push("save"); -- this.saveEverything(true, false, false); -- this.profiler.pop(); -- MinecraftServer.LOGGER.debug("Autosave finished"); +- if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { // CraftBukkit +- this.autoSave(); + // Paper start - Incremental chunk and player saving ++ final ProfilerFiller profiler = Profiler.get(); + int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate; + if (playerSaveInterval < 0) { + playerSaveInterval = autosavePeriod; + } -+ this.profiler.push("save"); ++ profiler.push("save"); + final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0; + try { + this.isSaving = true; + if (playerSaveInterval > 0) { + this.playerList.saveAll(playerSaveInterval); + } -+ for (ServerLevel level : this.getAllLevels()) { ++ for (final ServerLevel level : this.getAllLevels()) { + if (level.paperConfig().chunks.autoSaveInterval.value() > 0) { + level.saveIncrementally(fullSave); + } @@ -50,16 +44,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } finally { + this.isSaving = false; } -+ this.profiler.pop(); ++ profiler.pop(); + // Paper end - Incremental chunk and player saving - // Paper start - move executeAll() into full server tick timing - try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) { - this.runAllTasks(); + + ProfilerFiller gameprofilerfiller = Profiler.get(); + diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos); } diff --git a/patches/unapplied/server/Lag-compensation-ticks.patch b/patches/server/Lag-compensation-ticks.patch similarity index 93% rename from patches/unapplied/server/Lag-compensation-ticks.patch rename to patches/server/Lag-compensation-ticks.patch index c3676628b1..3cce14c6d4 100644 --- a/patches/unapplied/server/Lag-compensation-ticks.patch +++ b/patches/server/Lag-compensation-ticks.patch @@ -25,16 +25,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers + worldserver.updateLagCompensationTick(); // Paper - lag compensation - this.profiler.push(() -> { + gameprofilerfiller.push(() -> { String s = String.valueOf(worldserver); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. - return this.entityTickingChunks; +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ); } - // Paper end - rewrite chunk system + // Paper end - chunk tick iteration + // Paper start - lag compensation + private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT; + @@ -78,13 +78,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.isUsingItem()) { if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) { @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.triggerItemUseEffects(stack, 5); - } + protected void updateUsingItem(ItemStack stack) { + stack.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); - if (--this.useItemRemaining == 0 && !this.level().isClientSide && !stack.useOnRelease()) { + // Paper start - lag compensate eating + // we add 1 to the expected time to avoid lag compensating when we should not -+ boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L)); ++ final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L)); + if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !stack.useOnRelease()) { + this.useItemRemaining = 0; + // Paper end - lag compensate eating diff --git a/patches/unapplied/server/Optimise-collision-checking-in-player-move-packet-ha.patch b/patches/server/Optimise-collision-checking-in-player-move-packet-ha.patch similarity index 100% rename from patches/unapplied/server/Optimise-collision-checking-in-player-move-packet-ha.patch rename to patches/server/Optimise-collision-checking-in-player-move-packet-ha.patch diff --git a/patches/unapplied/server/Optimise-general-POI-access.patch b/patches/server/Optimise-general-POI-access.patch similarity index 98% rename from patches/unapplied/server/Optimise-general-POI-access.patch rename to patches/server/Optimise-general-POI-access.patch index 97eaa883b3..431f0ffebf 100644 --- a/patches/unapplied/server/Optimise-general-POI-access.patch +++ b/patches/server/Optimise-general-POI-access.patch @@ -889,7 +889,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager. index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im public Optional find( Predicate> typePredicate, Predicate posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus ) { @@ -903,10 +903,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Optional findClosest(Predicate> typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) { - return this.getInRange(typePredicate, pos, radius, occupationStatus) - .map(PoiRecord::getPos) -- .min(Comparator.comparingDouble(blockPos2 -> blockPos2.distSqr(pos))); +- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos))); + // Paper start - re-route to faster logic -+ BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false); -+ return Optional.ofNullable(ret); ++ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false); ++ return Optional.ofNullable(closestPos); + // Paper end - re-route to faster logic } @@ -929,27 +929,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return this.getInRange(typePredicate, pos, radius, occupationStatus) - .map(PoiRecord::getPos) - .filter(posPredicate) -- .min(Comparator.comparingDouble(blockPos2 -> blockPos2.distSqr(pos))); +- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos))); + // Paper start - re-route to faster logic -+ BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false); -+ return Optional.ofNullable(ret); ++ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false); ++ return Optional.ofNullable(closestPos); + // Paper end - re-route to faster logic } - public Optional take(Predicate> typePredicate, BiPredicate, BlockPos> biPredicate, BlockPos pos, int radius) { + public Optional take(Predicate> typePredicate, BiPredicate, BlockPos> posPredicate, BlockPos pos, int radius) { - return this.getInRange(typePredicate, pos, radius, PoiManager.Occupancy.HAS_SPACE) -- .filter(poi -> biPredicate.test(poi.getPoiType(), poi.getPos())) +- .filter(poi -> posPredicate.test(poi.getPoiType(), poi.getPos())) - .findFirst() + // Paper start - re-route to faster logic + final @javax.annotation.Nullable PoiRecord closest = io.papermc.paper.util.PoiAccess.findClosestPoiDataRecord( -+ this, typePredicate, biPredicate, pos, radius, radius * radius, Occupancy.HAS_SPACE, false ++ this, typePredicate, posPredicate, pos, radius, radius * radius, Occupancy.HAS_SPACE, false + ); + return Optional.ofNullable(closest) + // Paper end - re-route to faster logic .map(poi -> { poi.acquireTicket(); return poi.getPos(); -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im int radius, RandomSource random ) { @@ -990,7 +990,7 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorag index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -@@ -0,0 +0,0 @@ public abstract class SectionStorage implements AutoCloseable, ca.spottedleaf +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable, ca.spottedleaf.moonr } @Nullable diff --git a/patches/unapplied/server/Write-SavedData-IO-async.patch b/patches/unapplied/server/Write-SavedData-IO-async.patch deleted file mode 100644 index 13f5c104c4..0000000000 --- a/patches/unapplied/server/Write-SavedData-IO-async.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cryptite -Date: Tue, 27 Jun 2023 11:35:52 -0500 -Subject: [PATCH] Write SavedData IO async - -Co-Authored-By: Shane Freeder - -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - - public void close(boolean save) throws IOException { - ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(save, true); // Paper - rewrite chunk system -+ // Paper start - Write SavedData IO async -+ try { -+ this.dataStorage.close(); -+ } catch (final IOException e) { -+ LOGGER.error("Failed to close persistent world data", e); -+ } -+ // Paper end - Write SavedData IO async - } - - // CraftBukkit start - modelled on below -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. - progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); - } - -- this.saveLevelData(); -+ this.saveLevelData(!close); // Paper - Write SavedData IO async - if (progressListener != null) { - progressListener.progressStage(Component.translatable("menu.savingChunks")); - } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. - // CraftBukkit end - } - -- private void saveLevelData() { -+ private void saveLevelData(boolean async) { // Paper - Write SavedData IO async - if (this.dragonFight != null) { - this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit - } - -- this.getChunkSource().getDataStorage().save(); -+ this.getChunkSource().getDataStorage().save(async); // Paper - Write SavedData IO async - } - - public List getEntities(EntityTypeTest filter, Predicate predicate) { -diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -@@ -0,0 +0,0 @@ public class WorldUpgrader { - (new WorldUpgrader.PoiUpgrader(this)).upgrade(); - WorldUpgrader.LOGGER.info("Upgrading blocks"); - (new WorldUpgrader.ChunkUpgrader()).upgrade(); -- this.overworldDataStorage.save(); -+ // Paper start - Write SavedData IO async -+ try { -+ this.overworldDataStorage.close(); -+ } catch (final IOException e) { -+ LOGGER.error("Failed to close persistent world data", e); -+ } -+ // Paper end - Write SavedData IO async - i = Util.getMillis() - i; - WorldUpgrader.LOGGER.info("World optimizaton finished after {} seconds", i / 1000L); - this.finished = true; -diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -@@ -0,0 +0,0 @@ public abstract class SavedData { - return this.dirty; - } - -+ // Paper start - Write SavedData IO async - joining is evil, but we assume the old blocking behavior here just for safety -+ @io.papermc.paper.annotation.DoNotUse - public void save(File file, HolderLookup.Provider registryLookup) { -+ save(file, registryLookup, null).join(); -+ } -+ -+ public java.util.concurrent.CompletableFuture save(File file, HolderLookup.Provider registryLookup, @org.jetbrains.annotations.Nullable java.util.concurrent.ExecutorService ioExecutor) { -+ // Paper end - Write SavedData IO async - if (this.isDirty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.put("data", this.save(new CompoundTag(), registryLookup)); - NbtUtils.addCurrentDataVersion(compoundTag); - -+ Runnable writeRunnable = () -> { // Paper - Write SavedData IO async - try { - NbtIo.writeCompressed(compoundTag, file.toPath()); - } catch (IOException var5) { - LOGGER.error("Could not save data {}", this, var5); - } -+ }; // Paper - Write SavedData IO async - - this.setDirty(false); -+ // Paper start - Write SavedData IO async -+ if (ioExecutor == null) { -+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable); // No executor, just use common pool -+ } -+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable, ioExecutor); - } -+ return java.util.concurrent.CompletableFuture.completedFuture(null); -+ // Paper end - Write SavedData IO async - } - - public static record Factory( -diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -@@ -0,0 +0,0 @@ import net.minecraft.util.datafix.DataFixTypes; - import net.minecraft.world.level.saveddata.SavedData; - import org.slf4j.Logger; - --public class DimensionDataStorage { -+public class DimensionDataStorage implements java.io.Closeable { // Paper - Write SavedData IO async - private static final Logger LOGGER = LogUtils.getLogger(); - public final Map cache = Maps.newHashMap(); - private final DataFixer fixerUpper; - private final HolderLookup.Provider registries; - private final File dataFolder; -+ protected final java.util.concurrent.ExecutorService ioExecutor; // Paper - Write SavedData IO async - - public DimensionDataStorage(File directory, DataFixer dataFixer, HolderLookup.Provider registryLookup) { - this.fixerUpper = dataFixer; - this.dataFolder = directory; - this.registries = registryLookup; -+ this.ioExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("DimensionDataIO - " + dataFolder.getParent() + " - %d").setDaemon(true).build()); // Paper - Write SavedData IO async - } - - private File getDataFile(String id) { -@@ -0,0 +0,0 @@ public class DimensionDataStorage { - return bl; - } - -- public void save() { -+ // Paper start - Write SavedData IO async -+ @Override -+ public void close() throws IOException { -+ save(false); -+ this.ioExecutor.shutdown(); -+ } -+ // Paper end - Write SavedData IO async -+ -+ public void save(boolean async) { // Paper - Write SavedData IO async - this.cache.forEach((id, state) -> { - if (state != null) { -- state.save(this.getDataFile(id), this.registries); -+ // Paper start - Write SavedData IO async -+ final java.util.concurrent.CompletableFuture save = state.save(this.getDataFile(id), this.registries, this.ioExecutor); -+ if (!async) { -+ save.join(); -+ } -+ // Paper end - Write SavedData IO async - } - }); - }