From c36c2d46d34f4170a0aaccc9fd4c3a93afb2b241 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Tue, 23 Nov 2021 16:50:18 +0100 Subject: [PATCH] More more more more more more more work --- .../api/Add-More-Creeper-API.patch | 0 .../api/Add-PhantomPreSpawnEvent.patch | 0 ...Blocks-to-be-accessed-via-a-long-key.patch | 0 ...hots-for-Timings-Tile-Entity-reports.patch | 0 .../api/Slime-Pathfinder-Events.patch | 0 .../server/Add-More-Creeper-API.patch | 0 .../server/Add-PhantomPreSpawnEvent.patch | 4 +- ...le-speed-for-water-flowing-over-lava.patch | 12 +- ...urable-sprint-interruption-on-attack.patch | 5 - .../server/Inventory-removeItemAnySlot.patch | 0 ...loadChunk-int-int-false-load-unconve.patch | 0 ...ptimize-BlockPosition-helper-methods.patch | 0 .../Optimize-CraftBlockData-Creation.patch | 0 patches/server/Optimize-MappedRegistry.patch | 39 +++ ...efault-mob-spawn-range-and-water-ani.patch | 0 .../server/Slime-Pathfinder-Events.patch | 10 +- .../Asynchronous-chunk-IO-and-loading.patch | 286 ++++++++---------- ...-max-squid-spawn-height-configurable.patch | 0 ...more-aggressive-in-the-chunk-unload-.patch | 0 .../server/Optimize-MappedRegistry.patch | 35 --- 20 files changed, 179 insertions(+), 212 deletions(-) rename patches/{unapplied => }/api/Add-More-Creeper-API.patch (100%) rename patches/{unapplied => }/api/Add-PhantomPreSpawnEvent.patch (100%) rename patches/{unapplied => }/api/Allow-Blocks-to-be-accessed-via-a-long-key.patch (100%) rename patches/{unapplied => }/api/Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch (100%) rename patches/{unapplied => }/api/Slime-Pathfinder-Events.patch (100%) rename patches/{unapplied => }/server/Add-More-Creeper-API.patch (100%) rename patches/{unapplied => }/server/Add-PhantomPreSpawnEvent.patch (95%) rename patches/{unapplied => }/server/Configurable-speed-for-water-flowing-over-lava.patch (85%) rename patches/{unapplied => }/server/Inventory-removeItemAnySlot.patch (100%) rename patches/{unapplied => }/server/Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch (100%) rename patches/{unapplied => }/server/Optimize-BlockPosition-helper-methods.patch (100%) rename patches/{unapplied => }/server/Optimize-CraftBlockData-Creation.patch (100%) create mode 100644 patches/server/Optimize-MappedRegistry.patch rename patches/{unapplied => }/server/Restore-vanlla-default-mob-spawn-range-and-water-ani.patch (100%) rename patches/{unapplied => }/server/Slime-Pathfinder-Events.patch (96%) rename patches/unapplied/{ => server}/Make-max-squid-spawn-height-configurable.patch (100%) rename patches/unapplied/{ => server}/Make-targetSize-more-aggressive-in-the-chunk-unload-.patch (100%) delete mode 100644 patches/unapplied/server/Optimize-MappedRegistry.patch diff --git a/patches/unapplied/api/Add-More-Creeper-API.patch b/patches/api/Add-More-Creeper-API.patch similarity index 100% rename from patches/unapplied/api/Add-More-Creeper-API.patch rename to patches/api/Add-More-Creeper-API.patch diff --git a/patches/unapplied/api/Add-PhantomPreSpawnEvent.patch b/patches/api/Add-PhantomPreSpawnEvent.patch similarity index 100% rename from patches/unapplied/api/Add-PhantomPreSpawnEvent.patch rename to patches/api/Add-PhantomPreSpawnEvent.patch diff --git a/patches/unapplied/api/Allow-Blocks-to-be-accessed-via-a-long-key.patch b/patches/api/Allow-Blocks-to-be-accessed-via-a-long-key.patch similarity index 100% rename from patches/unapplied/api/Allow-Blocks-to-be-accessed-via-a-long-key.patch rename to patches/api/Allow-Blocks-to-be-accessed-via-a-long-key.patch diff --git a/patches/unapplied/api/Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch b/patches/api/Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch similarity index 100% rename from patches/unapplied/api/Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch rename to patches/api/Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch diff --git a/patches/unapplied/api/Slime-Pathfinder-Events.patch b/patches/api/Slime-Pathfinder-Events.patch similarity index 100% rename from patches/unapplied/api/Slime-Pathfinder-Events.patch rename to patches/api/Slime-Pathfinder-Events.patch diff --git a/patches/unapplied/server/Add-More-Creeper-API.patch b/patches/server/Add-More-Creeper-API.patch similarity index 100% rename from patches/unapplied/server/Add-More-Creeper-API.patch rename to patches/server/Add-More-Creeper-API.patch diff --git a/patches/unapplied/server/Add-PhantomPreSpawnEvent.patch b/patches/server/Add-PhantomPreSpawnEvent.patch similarity index 95% rename from patches/unapplied/server/Add-PhantomPreSpawnEvent.patch rename to patches/server/Add-PhantomPreSpawnEvent.patch index 04b70c1728..fbed26b552 100644 --- a/patches/unapplied/server/Add-PhantomPreSpawnEvent.patch +++ b/patches/server/Add-PhantomPreSpawnEvent.patch @@ -72,12 +72,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + // Paper end - Phantom entityphantom = (Phantom) EntityType.PHANTOM.create((Level) world); + Phantom entityphantom = (Phantom) EntityType.PHANTOM.create(world); - + entityphantom.setSpawningEntity(entityhuman.getUUID()); // Paper entityphantom.moveTo(blockposition1, 0.0F, 0.0F); groupdataentity = entityphantom.finalizeSpawn(world, difficultydamagescaler, MobSpawnType.NATURAL, groupdataentity, (CompoundTag) null); - world.addAllEntities(entityphantom, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit + world.addFreshEntityWithPassengers(entityphantom, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java diff --git a/patches/unapplied/server/Configurable-speed-for-water-flowing-over-lava.patch b/patches/server/Configurable-speed-for-water-flowing-over-lava.patch similarity index 85% rename from patches/unapplied/server/Configurable-speed-for-water-flowing-over-lava.patch rename to patches/server/Configurable-speed-for-water-flowing-over-lava.patch index 27d6888dd5..7a06e9d1e0 100644 --- a/patches/unapplied/server/Configurable-speed-for-water-flowing-over-lava.patch +++ b/patches/server/Configurable-speed-for-water-flowing-over-lava.patch @@ -23,9 +23,9 @@ diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/sr index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -@@ -0,0 +0,0 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty; +@@ -0,0 +0,0 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; + import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.material.FlowingFluid; - import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Material; import net.minecraft.world.level.pathfinder.PathComputationType; @@ -35,8 +35,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { if (this.shouldSpreadLiquid(world, pos, state)) { -- world.getLiquidTicks().scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay((LevelReader) world)); -+ world.getLiquidTicks().scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper +- world.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(world)); ++ world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper } } @@ -64,8 +64,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { if (this.shouldSpreadLiquid(world, pos, state)) { -- world.getLiquidTicks().scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay((LevelReader) world)); -+ world.getLiquidTicks().scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper +- world.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(world)); ++ world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper } } diff --git a/patches/server/Configurable-sprint-interruption-on-attack.patch b/patches/server/Configurable-sprint-interruption-on-attack.patch index a4d8d3452d..a955e2e5f2 100644 --- a/patches/server/Configurable-sprint-interruption-on-attack.patch +++ b/patches/server/Configurable-sprint-interruption-on-attack.patch @@ -14,11 +14,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 log("Creeper lingering effect: " + disableCreeperLingeringEffect); } + -+ public double squidMaxSpawnHeight; -+ private void squidMaxSpawnHeight() { -+ squidMaxSpawnHeight = getDouble("squid-spawn-height.maximum", 0.0D); -+ } -+ + public boolean disableSprintInterruptionOnAttack; + private void disableSprintInterruptionOnAttack() { + disableSprintInterruptionOnAttack = getBoolean("game-mechanics.disable-sprint-interruption-on-attack", false); diff --git a/patches/unapplied/server/Inventory-removeItemAnySlot.patch b/patches/server/Inventory-removeItemAnySlot.patch similarity index 100% rename from patches/unapplied/server/Inventory-removeItemAnySlot.patch rename to patches/server/Inventory-removeItemAnySlot.patch diff --git a/patches/unapplied/server/Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch b/patches/server/Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch similarity index 100% rename from patches/unapplied/server/Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch rename to patches/server/Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch diff --git a/patches/unapplied/server/Optimize-BlockPosition-helper-methods.patch b/patches/server/Optimize-BlockPosition-helper-methods.patch similarity index 100% rename from patches/unapplied/server/Optimize-BlockPosition-helper-methods.patch rename to patches/server/Optimize-BlockPosition-helper-methods.patch diff --git a/patches/unapplied/server/Optimize-CraftBlockData-Creation.patch b/patches/server/Optimize-CraftBlockData-Creation.patch similarity index 100% rename from patches/unapplied/server/Optimize-CraftBlockData-Creation.patch rename to patches/server/Optimize-CraftBlockData-Creation.patch diff --git a/patches/server/Optimize-MappedRegistry.patch b/patches/server/Optimize-MappedRegistry.patch new file mode 100644 index 0000000000..84e67d9ba8 --- /dev/null +++ b/patches/server/Optimize-MappedRegistry.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 26 Aug 2018 20:49:50 -0400 +Subject: [PATCH] Optimize MappedRegistry + +Use larger initial sizes to increase bucket capacity on the BiMap + +BiMap.get was seen to be using a good bit of CPU time. + +diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/core/MappedRegistry.java ++++ b/src/main/java/net/minecraft/core/MappedRegistry.java +@@ -0,0 +0,0 @@ public class MappedRegistry extends WritableRegistry { + + protected static final Logger LOGGER = LogManager.getLogger(); + private final ObjectList byId = new ObjectArrayList(256); +- private final Object2IntMap toId = (Object2IntMap) Util.make(new Object2IntOpenCustomHashMap(Util.identityStrategy()), (object2intopencustomhashmap) -> { +- object2intopencustomhashmap.defaultReturnValue(-1); +- }); +- private final BiMap storage = HashBiMap.create(); +- private final BiMap, T> keyStorage = HashBiMap.create(); +- private final Map lifecycles = Maps.newIdentityHashMap(); ++ private final it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap toId = new it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap(2048);// Paper - use bigger expected size to reduce collisions and direct intent for FastUtil to be identity map ++ private final BiMap storage = HashBiMap.create(2048); // Paper - use bigger expected size to reduce collisions ++ private final BiMap, T> keyStorage = HashBiMap.create(2048); // Paper - use bigger expected size to reduce collisions ++ private final Map lifecycles = new java.util.IdentityHashMap<>(2048); // Paper - use bigger expected size to reduce collisions + private Lifecycle elementsLifecycle; + @Nullable + protected Object[] randomCache; +@@ -0,0 +0,0 @@ public class MappedRegistry extends WritableRegistry { + + public MappedRegistry(ResourceKey> key, Lifecycle lifecycle) { + super(key, lifecycle); +- this.elementsLifecycle = lifecycle; ++ this.toId.defaultReturnValue(-1); // Paper + } + + public static MapCodec> withNameAndId(ResourceKey> key, MapCodec entryCodec) { diff --git a/patches/unapplied/server/Restore-vanlla-default-mob-spawn-range-and-water-ani.patch b/patches/server/Restore-vanlla-default-mob-spawn-range-and-water-ani.patch similarity index 100% rename from patches/unapplied/server/Restore-vanlla-default-mob-spawn-range-and-water-ani.patch rename to patches/server/Restore-vanlla-default-mob-spawn-range-and-water-ani.patch diff --git a/patches/unapplied/server/Slime-Pathfinder-Events.patch b/patches/server/Slime-Pathfinder-Events.patch similarity index 96% rename from patches/unapplied/server/Slime-Pathfinder-Events.patch rename to patches/server/Slime-Pathfinder-Events.patch index 71f7298b2d..740aaa3ca7 100644 --- a/patches/unapplied/server/Slime-Pathfinder-Events.patch +++ b/patches/server/Slime-Pathfinder-Events.patch @@ -85,7 +85,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override @@ -0,0 +0,0 @@ public class Slime extends Mob implements Enemy { - this.slime.lookAt((Entity) this.slime.getTarget(), 10.0F, 10.0F); + ((Slime.SlimeMoveControl) this.slime.getMoveControl()).setDirection(this.slime.getYRot(), this.slime.isDealsDamage()); } + @@ -107,12 +107,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @Override - public void tick() { +@@ -0,0 +0,0 @@ public class Slime extends Mob implements Enemy { if (--this.nextRandomizeTime <= 0) { - this.nextRandomizeTime = 40 + this.slime.getRandom().nextInt(60); -- this.chosenDegrees = (float) this.slime.getRandom().nextInt(360); + this.nextRandomizeTime = this.adjustedTickDelay(40 + this.slime.getRandom().nextInt(60)); + this.chosenDegrees = (float) this.slime.getRandom().nextInt(360); + // Paper start -+ SlimeChangeDirectionEvent event = new SlimeChangeDirectionEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), (float) this.slime.getRandom().nextInt(360)); ++ SlimeChangeDirectionEvent event = new SlimeChangeDirectionEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), this.chosenDegrees); + if (!this.slime.canWander || !event.callEvent()) return; + this.chosenDegrees = event.getNewYaw(); + // Paper end diff --git a/patches/unapplied/server/Asynchronous-chunk-IO-and-loading.patch b/patches/unapplied/server/Asynchronous-chunk-IO-and-loading.patch index b78e4ea511..53fd0a6de3 100644 --- a/patches/unapplied/server/Asynchronous-chunk-IO-and-loading.patch +++ b/patches/unapplied/server/Asynchronous-chunk-IO-and-loading.patch @@ -3,6 +3,9 @@ From: Spottedleaf Date: Sat, 13 Jul 2019 09:23:10 -0700 Subject: [PATCH] Asynchronous chunk IO and loading +# UPDATE NOTES: RegionFileStorage and SectionStorage need resolving (will conflict on apply) +# ChunkSerializer needs the new tick lists to be saved (see added todos) + This patch re-adds a file IO thread as well as shoving de-serializing chunk NBT data onto worker threads. This patch also will shove chunk data serialization onto the same worker threads when the chunk @@ -2282,8 +2285,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/MCUtil.java +++ b/src/main/java/net/minecraft/server/MCUtil.java @@ -0,0 +0,0 @@ public final class MCUtil { - return null; - } + public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { + return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); } + + public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { @@ -2296,7 +2299,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/Main.java @@ -0,0 +0,0 @@ public class Main { - convertable_conversionsession.a((IRegistryCustom) iregistrycustom_dimension, (SaveData) object); + convertable_conversionsession.saveDataTag(iregistrycustom_dimension, (SaveData) object); */ + Class.forName(net.minecraft.world.entity.npc.VillagerTrades.class.getName());// Paper - load this sync so it won't fail later async final DedicatedServer dedicatedserver = (DedicatedServer) MinecraftServer.spin((thread) -> { @@ -2364,18 +2367,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return true; }); - this.flushWorker(); ++ //this.flushWorker(); // Paper - nuke IOWorker + this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour -+// this.i(); // Paper - nuke IOWorker } else { this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> { ChunkAccess ichunkaccess = (ChunkAccess) playerchunk.getChunkToSave().getNow(null); // CraftBukkit - decompile error @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - } - -- private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.96; // Spigot -+ private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.90; // Spigot // Paper - unload more - protected void tick(BooleanSupplier shouldKeepTicking) { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); @@ -2387,10 +2384,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!this.level.noSave()) { + try (Timing ignored = this.level.timings.chunkUnload.startTiming()) { // Paper this.processUnloads(shouldKeepTicking); -+ }// Paper ++ } // Paper } gameprofilerfiller.pop(); + } + +- private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.96; // Spigot ++ private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.90; // Spigot // Paper - unload more + + private void processUnloads(BooleanSupplier shouldKeepTicking) { + LongIterator longiterator = this.toDrop.iterator(); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (playerchunk != null) { this.pendingUnloads.put(j, playerchunk); @@ -2402,7 +2406,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Spigot end - this.scheduleUnload(j, playerchunk); -+ //this.a(j, playerchunk); // Paper - move up because spigot did a dumb ++ //this.scheduleUnload(j, playerchunk); // Paper - move up because spigot did a dumb } } activityAccountant.endActivity(); // Spigot @@ -2418,7 +2422,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ChunkPos chunkPos = chunk.getPos(); + CompoundTag poiData; + try (Timing ignored = this.level.timings.chunkUnloadPOISerialization.startTiming()) { -+ poiData = this.getVillagePlace().getData(chunk.getPos()); ++ poiData = this.poiManager.getData(chunk.getPos()); + } + + com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.level, chunkPos.x, chunkPos.z, @@ -2467,7 +2471,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + LOGGER.fatal("Failed to prepare async save, attempting synchronous save", ex); + this.save(ichunkaccess); + } -+ // Paper end - async chunk saving ++ // Paper end - async chunk savin if (this.entitiesInLevel.remove(pos) && ichunkaccess instanceof LevelChunk) { LevelChunk chunk = (LevelChunk) ichunkaccess; @@ -2484,30 +2488,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - try (Timing ignored2 = this.level.timings.chunkIO.startTimingIfSync()) { // Paper start - timings - nbttagcompound = this.readChunk(pos); - } // Paper end +- +- if (nbttagcompound != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings +- boolean flag = nbttagcompound.contains("Status", 8); +- +- if (flag) { +- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, pos, nbttagcompound); + // Paper start + if (ioThrowable != null) { + com.destroystokyo.paper.util.SneakyThrow.sneaky(ioThrowable); + } - -- if (nbttagcompound != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings -- boolean flag = nbttagcompound.contains("Level", 10) && nbttagcompound.getCompound("Level").contains("Status", 8); -+ this.getVillagePlace().loadInData(pos, chunkHolder.poiData); ++ this.poiManager.loadInData(pos, chunkHolder.poiData); + chunkHolder.tasks.forEach(Runnable::run); + // Paper end -- if (flag) { -- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.structureManager, this.poiManager, pos, nbttagcompound); + if (chunkHolder.protoChunk != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings // Paper - chunk is created async -+ + if (true) { -+ ProtoChunk protochunk = chunkHolder.protoChunk; - this.markPosition(pos, protochunk.getStatus().getChunkType()); return Either.left(protochunk); + } @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.markPositionReplaceable(pos); - return Either.left(new ProtoChunk(pos, UpgradeData.EMPTY, this.level)); + return Either.left(new ProtoChunk(pos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), (BlendingData) null)); - }, this.mainThreadExecutor); + // Paper start - Async chunk io + }; @@ -2537,7 +2540,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end } - private void markPositionReplaceable(ChunkPos chunkcoordintpair) { + private void markPositionReplaceable(ChunkPos pos) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -2560,13 +2563,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.level.getProfiler().incrementCounter("chunkSave"); - CompoundTag nbttagcompound = ChunkSerializer.write(this.level, chunk); +- +- this.write(chunkcoordintpair, nbttagcompound); + CompoundTag nbttagcompound; + try (co.aikar.timings.Timing ignored1 = this.level.timings.chunkSaveDataSerialization.startTiming()) { // Paper + nbttagcompound = ChunkSerializer.write(this.level, chunk); -+ } // Paper ++ } // Paper; + - -- this.write(chunkcoordintpair, nbttagcompound); + // Paper start - async chunk io + com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.level, chunkcoordintpair.x, chunkcoordintpair.z, + null, nbttagcompound, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); @@ -2581,7 +2584,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } // Paper } - private boolean isExistingChunkFull(ChunkPos chunkcoordintpair) { + private boolean isExistingChunkFull(ChunkPos pos) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -2618,14 +2621,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public CompoundTag readChunk(ChunkPos pos) throws IOException { CompoundTag nbttagcompound = this.read(pos); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - } - -+ @Deprecated public PoiManager getVillagePlace() { return this.getPoiManager(); } // Paper - OBFHELPER - protected PoiManager getPoiManager() { - return this.poiManager; - } 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 @@ -2765,7 +2760,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 gameprofilerfiller.incrementCounter("getChunkCacheMiss"); - CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); + CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create, true); // Paper - ServerChunkCache.MainThreadExecutor chunkproviderserver_a = this.mainThreadProcessor; + ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; Objects.requireNonNull(completablefuture); if (!completablefuture.isDone()) { // Paper @@ -2774,7 +2769,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.level, x1, z1); + // Paper end this.level.timings.syncChunkLoad.startTiming(); // Paper - chunkproviderserver_a.managedBlock(completablefuture::isDone); + chunkproviderserver_b.managedBlock(completablefuture::isDone); + com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug this.level.timings.syncChunkLoad.stopTiming(); // Paper } // Paper @@ -2937,8 +2932,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final LongSet loadedChunks = new LongOpenHashSet(); + private final net.minecraft.server.level.ServerLevel world; // Paper - public PoiManager(File directory, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) { - super(directory, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world); + public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) { + super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world); + this.world = (net.minecraft.server.level.ServerLevel)world; // Paper this.distanceTracker = new PoiManager.DistanceTracker(); } @@ -2999,32 +2994,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static enum Occupancy { HAS_SPACE(PoiRecord::hasSpace), IS_OCCUPIED(PoiRecord::isOccupied), -diff --git a/src/main/java/net/minecraft/world/level/TickNextTickData.java b/src/main/java/net/minecraft/world/level/TickNextTickData.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/TickNextTickData.java -+++ b/src/main/java/net/minecraft/world/level/TickNextTickData.java -@@ -0,0 +0,0 @@ import java.util.Comparator; - import net.minecraft.core.BlockPos; - - public class TickNextTickData { -- private static long counter; -+ private static final java.util.concurrent.atomic.AtomicLong COUNTER = new java.util.concurrent.atomic.AtomicLong(); // Paper - async chunk loading - private final T type; - public final BlockPos pos; - public final long triggerTick; -@@ -0,0 +0,0 @@ public class TickNextTickData { - } - - public TickNextTickData(BlockPos pos, T t, long time, TickPriority priority) { -- this.c = (long)(counter++); -+ this.c = (TickNextTickData.COUNTER.getAndIncrement()); // Paper - async chunk loading - this.pos = pos.immutable(); - this.type = t; - this.triggerTick = time; diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +@@ -0,0 +0,0 @@ import net.minecraft.world.level.lighting.LevelLightEngine; + import net.minecraft.world.level.material.Fluid; + import net.minecraft.world.ticks.LevelChunkTicks; + import net.minecraft.world.ticks.ProtoChunkTicks; ++import net.minecraft.world.ticks.TickContainerAccess; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + @@ -0,0 +0,0 @@ public class ChunkSerializer { public ChunkSerializer() {} @@ -3044,56 +3025,50 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - public static ProtoChunk read(ServerLevel world, StructureManager structureManager, PoiManager poiStorage, ChunkPos pos, CompoundTag nbt) { + public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt) { + // Paper start - add variant for async calls -+ InProgressChunkHolder holder = loadChunk(world, structureManager, poiStorage, pos, nbt, true); ++ InProgressChunkHolder holder = loadChunk(world, poiStorage, chunkPos, nbt, true); + holder.tasks.forEach(Runnable::run); + return holder.protoChunk; + } -+ public static InProgressChunkHolder loadChunk(ServerLevel world, StructureManager structureManager, PoiManager poiStorage, ChunkPos pos, CompoundTag nbt, boolean distinguish) { ++ ++ public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { + java.util.ArrayDeque tasksToExecuteOnMain = new java.util.ArrayDeque<>(); + // Paper end - ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator(); - BiomeSource worldchunkmanager = chunkgenerator.getBiomeSource(); - CompoundTag nbttagcompound1 = nbt.getCompound("Level"); + ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); + + if (!Objects.equals(chunkPos, chunkcoordintpair1)) { @@ -0,0 +0,0 @@ public class ChunkSerializer { LevelLightEngine lightengine = chunkproviderserver.getLightEngine(); if (flag) { + tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main - lightengine.retainData(pos, true); + lightengine.retainData(chunkPos, true); + }); // Paper - delay this task since we're executing off-main } - for (int j = 0; j < nbttaglist.size(); ++j) { + Registry iregistry = world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -0,0 +0,0 @@ public class ChunkSerializer { - achunksection[world.getSectionIndexFromSectionY(b0)] = chunksection; - } - -+ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main - poiStorage.checkConsistencyWithBlocks(pos, chunksection); -+ }); // Paper - delay this task since we're executing off-main - } if (flag) { - if (nbttagcompound2.contains("BlockLight", 7)) { -- lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(pos, b0), new DataLayer(nbttagcompound2.getByteArray("BlockLight")), true); + if (nbttagcompound1.contains("BlockLight", 7)) { +- lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("BlockLight")), true); + // Paper start - delay this task since we're executing off-main -+ DataLayer blockLight = new DataLayer(nbttagcompound2.getByteArray("BlockLight")); ++ DataLayer blockLight = new DataLayer(nbttagcompound1.getByteArray("BlockLight")); + tasksToExecuteOnMain.add(() -> { + lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkcoordintpair1, b0), blockLight, true); + }); + // Paper end - delay this task since we're executing off-main } - if (flag1 && nbttagcompound2.contains("SkyLight", 7)) { -- lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(pos, b0), new DataLayer(nbttagcompound2.getByteArray("SkyLight")), true); + if (flag1 && nbttagcompound1.contains("SkyLight", 7)) { +- lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("SkyLight")), true); + // Paper start - delay this task since we're executing off-main -+ DataLayer skyLight = new DataLayer(nbttagcompound2.getByteArray("SkyLight")); ++ DataLayer skyLight = new DataLayer(nbttagcompound1.getByteArray("SkyLight")); + tasksToExecuteOnMain.add(() -> { + lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkcoordintpair1, b0), skyLight, true); + }); -+ // Paper end - delay this task since we're executing off-main ++ // Paper end - delay this task since we're executing off-mai } } } @@ -3101,20 +3076,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) { -- return new ImposterProtoChunk((LevelChunk) object); -+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object), tasksToExecuteOnMain); // Paper - Async chunk loading +- return new ImposterProtoChunk((LevelChunk) object, false); ++ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object, false), tasksToExecuteOnMain); // Paper - Async chunk loading } else { ProtoChunk protochunk1 = (ProtoChunk) object; @@ -0,0 +0,0 @@ public class ChunkSerializer { - protochunk1.setCarvingMask(worldgenstage_features, BitSet.valueOf(nbttagcompound5.getByteArray(s1))); + protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object).getMinBuildHeight())); } - return protochunk1; + return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading -+ } -+ } -+ + } + } + + // Paper start - async chunk save for unload + public static final class AsyncSaveData { + public final DataLayer[] blockLight; @@ -3163,8 +3138,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + skyLight[i - lightenginethreaded.getMinLightSection()] = skyArray; + } + -+ TickList blockTickList = chunk.getBlockTicks(); ++ TickContainerAccess blockTickList = chunk.getBlockTicks(); + ++ //TODO check ChunkSerializer "block_ticks" + ListTag blockTickListSerialized; + if (blockTickList instanceof ProtoTickList || blockTickList instanceof ChunkTickList) { + blockTickListSerialized = null; @@ -3172,13 +3148,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + blockTickListSerialized = world.getBlockTicks().save(chunkPos); + } + -+ TickList fluidTickList = chunk.getLiquidTicks(); ++ TickContainerAccess fluidTickList = chunk.getFluidTicks(); + ++ //TODO + ListTag fluidTickListSerialized; + if (fluidTickList instanceof ProtoTickList || fluidTickList instanceof ChunkTickList) { + fluidTickListSerialized = null; + } else { -+ fluidTickListSerialized = world.getLiquidTicks().save(chunkPos); ++ fluidTickListSerialized = world.getFluidTicks().save(chunkPos); + } + + ListTag blockEntitiesSerialized = new ListTag(); @@ -3187,9 +3164,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (blockEntityNbt != null) { + blockEntitiesSerialized.add(blockEntityNbt); + } - } ++ } + + return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime()); ++ } ++ + private static void logErrors(ChunkPos chunkPos, int y, String message) { + ChunkSerializer.LOGGER.error("Recoverable errors when loading section [" + chunkPos.x + ", " + y + ", " + chunkPos.z + "]: " + message); + } +@@ -0,0 +0,0 @@ public class ChunkSerializer { } public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { @@ -3199,23 +3182,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end ChunkPos chunkcoordintpair = chunk.getPos(); CompoundTag nbttagcompound = new CompoundTag(); - CompoundTag nbttagcompound1 = new CompoundTag(); + @@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound.put("Level", nbttagcompound1); - nbttagcompound1.putInt("xPos", chunkcoordintpair.x); - nbttagcompound1.putInt("zPos", chunkcoordintpair.z); -- nbttagcompound1.putLong("LastUpdate", world.getGameTime()); -+ nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading - nbttagcompound1.putLong("InhabitedTime", chunk.getInhabitedTime()); - nbttagcompound1.putString("Status", chunk.getStatus().getName()); - UpgradeData chunkconverter = chunk.getUpgradeData(); + nbttagcompound.putInt("yPos", chunk.getMinSection()); + nbttagcompound.putInt("zPos", chunkcoordintpair.z); + nbttagcompound.putLong("LastUpdate", world.getGameTime()); ++ nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading + nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); + nbttagcompound.putString("Status", chunk.getStatus().getName()); + BlendingData blendingdata = chunk.getBlendingData(); @@ -0,0 +0,0 @@ public class ChunkSerializer { - LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> { - return chunksection1 != null && SectionPos.blockToSectionCoord(chunksection1.bottomBlockY()) == finalI; // CraftBukkit - decompile errors - }).findFirst().orElse(LevelChunk.EMPTY_SECTION); + for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { + int j = chunk.getSectionIndexFromSectionY(i); + boolean flag1 = j >= 0 && j < achunksection.length; - DataLayer nibblearray = lightenginethreaded.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); - DataLayer nibblearray1 = lightenginethreaded.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); -- + // Paper start - async chunk save for unload + DataLayer nibblearray; // block light + DataLayer nibblearray1; // sky light @@ -3227,11 +3208,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + nibblearray1 = asyncsavedata.skyLight[i - lightenginethreaded.getMinLightSection()]; + } + // Paper end - if (chunksection != LevelChunk.EMPTY_SECTION || nibblearray != null || nibblearray1 != null) { - CompoundTag nbttagcompound2 = new CompoundTag(); + if (flag1 || nibblearray != null || nibblearray1 != null) { + CompoundTag nbttagcompound1 = new CompoundTag(); @@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound1.putIntArray("Biomes", biomestorage.writeBiomes()); + nbttagcompound.putBoolean("isLightOn", true); } - ListTag nbttaglist1 = new ListTag(); @@ -3248,38 +3229,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - CompoundTag nbttagcompound3; + CompoundTag nbttagcompound2; @@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound1.put("ToBeTicked", ((ProtoTickList) ticklist).save()); - } else if (ticklist instanceof ChunkTickList) { - nbttagcompound1.put("TileTicks", ((ChunkTickList) ticklist).save()); -+ // Paper start - async chunk save for unload -+ } else if (asyncsavedata != null) { -+ nbttagcompound1.put("TileTicks", asyncsavedata.blockTickList); -+ // Paper end - } else { - nbttagcompound1.put("TileTicks", world.getBlockTicks().save(chunkcoordintpair)); - } -@@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound1.put("LiquidsToBeTicked", ((ProtoTickList) ticklist1).save()); - } else if (ticklist1 instanceof ChunkTickList) { - nbttagcompound1.put("LiquidTicks", ((ChunkTickList) ticklist1).save()); -+ // Paper start - async chunk save for unload -+ } else if (asyncsavedata != null) { -+ nbttagcompound1.put("LiquidTicks", asyncsavedata.fluidTickList); -+ // Paper end - } else { - nbttagcompound1.put("LiquidTicks", world.getLiquidTicks().save(chunkcoordintpair)); - } + private static void saveTicks(ServerLevel world, CompoundTag nbt, ChunkAccess.TicksToSave tickSchedulers) { + long i = world.getLevelData().getGameTime(); + ++ //TODO original patch line 3259 + nbt.put("block_ticks", tickSchedulers.blocks().save(i, (block) -> { + return Registry.BLOCK.getKey(block).toString(); + })); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java @@ -0,0 +0,0 @@ import net.minecraft.world.level.storage.DimensionDataStorage; - public class ChunkStorage implements AutoCloseable { + public static final int LAST_MONOLYTH_STRUCTURE_DATA_VERSION = 1493; - private final IOWorker worker; + // Paper - nuke IO worker protected final DataFixer fixerUpper; @@ -3291,7 +3258,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public final RegionFileStorage regionFileCache; + // Paper end - async chunk loading - public ChunkStorage(File directory, DataFixer dataFixer, boolean dsync) { + public ChunkStorage(Path directory, DataFixer dataFixer, boolean dsync) { this.fixerUpper = dataFixer; - this.worker = new IOWorker(directory, dsync, "chunk"); + // Paper start - async chunk io @@ -3366,7 +3333,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.worker.close(); + this.regionFileCache.close(); // Paper - nuke IO worker } - } + + public ChunkScanAccess chunkScanner() { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -3377,8 +3345,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected final RegionBitmap usedSectors; + public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper - public RegionFile(File file, File directory, boolean dsync) throws IOException { - this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); + public RegionFile(Path path, Path path1, boolean dsync) throws IOException { + this(path, path1, RegionFileVersion.VERSION_DEFLATE, dsync); @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { return (byteCount + 4096 - 1) / 4096; } @@ -3410,7 +3378,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } // Paper end } - + diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -3418,7 +3386,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { this.sync = dsync; } - + - public RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit + // Paper start + public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { @@ -3438,7 +3406,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); - + if (regionfile != null) { + // Paper start + if (lock) { @@ -3451,7 +3419,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.regionCache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync); - + this.regionCache.putAndMoveToFirst(i, regionfile1); + // Paper start + if (lock) { @@ -3474,23 +3442,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end + try { // Paper DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); - + CompoundTag nbttagcompound; @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { } - + return nbttagcompound; + } finally { // Paper start + regionfile.fileLock.unlock(); + } // Paper end } - + protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { - RegionFile regionfile = this.getFile(pos, false); // CraftBukkit + RegionFile regionfile = this.getFile(pos, false, true); // CraftBukkit // Paper + try { // Paper int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper - + if (nbt == null) { @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { MinecraftServer.LOGGER.error("Failed to save chunk", laste); @@ -3500,20 +3468,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + regionfile.fileLock.unlock(); + } // Paper end } - + - public void close() throws IOException { + public synchronized void close() throws IOException { // Paper -> synchronized ExceptionCollector exceptionsuppressor = new ExceptionCollector<>(); ObjectIterator objectiterator = this.regionCache.values().iterator(); - + @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { exceptionsuppressor.throwIfPresent(); } - + - public void flush() throws IOException { + public synchronized void flush() throws IOException { // Paper - synchronize ObjectIterator objectiterator = this.regionCache.values().iterator(); - + while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -3522,7 +3490,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ import net.minecraft.world.level.LevelHeightAccessor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; - + -public class SectionStorage implements AutoCloseable { +public class SectionStorage extends RegionFileStorage implements AutoCloseable { // Paper - nuke IOWorker private static final Logger LOGGER = LogManager.getLogger(); @@ -3534,7 +3502,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final Function> codec; @@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { protected final LevelHeightAccessor levelHeightAccessor; - + public SectionStorage(File directory, Function> codecFactory, Function factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) { + super(directory, dsync); // Paper - nuke IOWorker this.codec = codecFactory; @@ -3545,11 +3513,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.worker = new IOWorker(directory, dsync, directory.getName()); + // Paper - remove mojang I/O thread } - + protected void tick(BooleanSupplier shouldKeepTicking) { @@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { } - + private void readColumn(ChunkPos chunkPos) { - this.readColumn(chunkPos, NbtOps.INSTANCE, this.tryRead(chunkPos)); + // Paper start - expose function to load in data @@ -3559,7 +3527,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.readColumn(chunkPos, NbtOps.INSTANCE, compound); + // Paper end - expose function to load in data } - + @Nullable private CompoundTag tryRead(ChunkPos pos) { try { @@ -3577,9 +3545,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { LOGGER.error("Expected compound tag, got {}", (Object)tag); } - + } - + + // Paper start - internal get data function, copied from above + private CompoundTag getDataInternal(ChunkPos chunkcoordintpair) { + Dynamic dynamic = this.writeColumn(chunkcoordintpair, NbtOps.INSTANCE); @@ -3595,9 +3563,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end private Dynamic writeColumn(ChunkPos chunkPos, DynamicOps dynamicOps) { Map map = Maps.newHashMap(); - + @@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { - + @Override public void close() throws IOException { - this.worker.close(); diff --git a/patches/unapplied/Make-max-squid-spawn-height-configurable.patch b/patches/unapplied/server/Make-max-squid-spawn-height-configurable.patch similarity index 100% rename from patches/unapplied/Make-max-squid-spawn-height-configurable.patch rename to patches/unapplied/server/Make-max-squid-spawn-height-configurable.patch diff --git a/patches/unapplied/Make-targetSize-more-aggressive-in-the-chunk-unload-.patch b/patches/unapplied/server/Make-targetSize-more-aggressive-in-the-chunk-unload-.patch similarity index 100% rename from patches/unapplied/Make-targetSize-more-aggressive-in-the-chunk-unload-.patch rename to patches/unapplied/server/Make-targetSize-more-aggressive-in-the-chunk-unload-.patch diff --git a/patches/unapplied/server/Optimize-MappedRegistry.patch b/patches/unapplied/server/Optimize-MappedRegistry.patch deleted file mode 100644 index e2fee46601..0000000000 --- a/patches/unapplied/server/Optimize-MappedRegistry.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 26 Aug 2018 20:49:50 -0400 -Subject: [PATCH] Optimize MappedRegistry - -Use larger initial sizes to increase bucket capacity on the BiMap - -BiMap.get was seen to be using a good bit of CPU time. - -diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/core/MappedRegistry.java -+++ b/src/main/java/net/minecraft/core/MappedRegistry.java -@@ -0,0 +0,0 @@ import org.apache.logging.log4j.Logger; - public class MappedRegistry extends WritableRegistry { - protected static final Logger LOGGER = LogManager.getLogger(); - private final ObjectList byId = new ObjectArrayList<>(256); -- private final Object2IntMap toId = new Object2IntOpenCustomHashMap<>(Util.identityStrategy()); -+ private final it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap toId = new it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap(2048);// Paper - use bigger expected size to reduce collisions and direct intent for FastUtil to be identity map - private final BiMap storage; - private final BiMap, T> keyStorage; - private final Map lifecycles; -@@ -0,0 +0,0 @@ public class MappedRegistry extends WritableRegistry { - public MappedRegistry(ResourceKey> key, Lifecycle lifecycle) { - super(key, lifecycle); - this.toId.defaultReturnValue(-1); -- this.storage = HashBiMap.create(); -- this.keyStorage = HashBiMap.create(); -- this.lifecycles = Maps.newIdentityHashMap(); -+ this.storage = HashBiMap.create(2048); // Paper - use bigger expected size to reduce collisions -+ this.keyStorage = HashBiMap.create(2048); // Paper - use bigger expected size to reduce collisions -+ this.lifecycles = new java.util.IdentityHashMap<>(2048); // Paper - use bigger expected size to reduce collisions - this.elementsLifecycle = lifecycle; - } -