From fb2577e08a5619452c8b537bbe4a1756dc77532c Mon Sep 17 00:00:00 2001 From: Aurora Date: Sun, 13 Jun 2021 15:46:28 +0200 Subject: [PATCH] more work --- .../Fix-World-isChunkGenerated-calls.patch | 160 ++++++++---------- 1 file changed, 69 insertions(+), 91 deletions(-) rename patches/{server-remapped => server}/Fix-World-isChunkGenerated-calls.patch (75%) diff --git a/patches/server-remapped/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch similarity index 75% rename from patches/server-remapped/Fix-World-isChunkGenerated-calls.patch rename to patches/server/Fix-World-isChunkGenerated-calls.patch index 3fdca15eb0..3b0d5bbd3b 100644 --- a/patches/server-remapped/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -0,0 +0,0 @@ public class ChunkHolder { Either either = (Either) statusFuture.getNow(null); - return either == null ? null : (LevelChunk) either.left().orElse(null); + return (either == null) ? null : (LevelChunk) either.left().orElse(null); } + + public ChunkAccess getAvailableChunkNow() { @@ -28,15 +28,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + return null; + } - // Paper end + // CraftBukkit end public CompletableFuture> getFutureIfPresentUnchecked(ChunkStatus leastStatus) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ProtoChunk; + import net.minecraft.world.level.chunk.UpgradeData; + import net.minecraft.world.level.chunk.storage.ChunkSerializer; + import net.minecraft.world.level.chunk.storage.ChunkStorage; ++import net.minecraft.world.level.chunk.storage.RegionFile; + import net.minecraft.world.level.entity.ChunkStatusUpdateListener; + import net.minecraft.world.level.levelgen.structure.StructureStart; + import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } + // Paper end @Nullable - private CompoundTag readChunk(ChunkPos pos) throws IOException { @@ -60,15 +68,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // Paper start - chunk status cache "api" + public ChunkStatus getChunkStatusOnDiskIfCached(ChunkPos chunkPos) { -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getRegionFileIfLoaded(chunkPos); -+ ++ RegionFile regionFile = regionFileCache.getRegionFileIfLoaded(chunkPos); + +- return nbttagcompound == null ? null : this.getChunkData(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, pos, level); // CraftBukkit + return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); -+ } -+ + } + + public ChunkStatus getChunkStatusOnDisk(ChunkPos chunkPos) throws IOException { -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, true); ++ RegionFile regionFile = regionFileCache.getFile(chunkPos, true); + -+ if (regionFile == null || !regionFile.chunkExists(chunkPos)) { ++ if (regionFile == null || !regionFileCache.chunkExists(chunkPos)) { + return null; + } + @@ -79,13 +88,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + this.readChunk(chunkPos); - -- return nbttagcompound == null ? null : this.getChunkData(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, pos, level); // CraftBukkit ++ + return regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); - } - ++ } ++ + public void updateChunkStatusOnDisk(ChunkPos chunkPos, @Nullable CompoundTag compound) throws IOException { -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ RegionFile regionFile = regionFileCache.getFile(chunkPos, false); + + regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkSerializer.getStatus(compound)); + } @@ -96,52 +104,44 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - boolean noPlayersCloseForSpawning(ChunkPos chunkcoordintpair) { + boolean noPlayersCloseForSpawning(ChunkPos chunkPos) { // Spigot start - return isOutsideOfRange(chunkcoordintpair, false); + return this.isOutsideOfRange(chunkPos, false); 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 { - private final ServerLevel level; - public final Thread mainThread; // Paper - private -> public - private final ThreadedLevelLightEngine lightEngine; -- private final ServerChunkCache.MainThreadExecutor mainThreadProcessor; + private static final List CHUNK_STATUSES = ChunkStatus.getStatusList(); public static final List getPossibleChunkStatuses() { return ServerChunkCache.CHUNK_STATUSES; } // Paper - OBFHELPER + private final DistanceManager distanceManager; + public final ChunkGenerator generator; +- final ServerLevel level; +- public final Thread mainThread; // Paper - package-private -> public +- final ThreadedLevelLightEngine lightEngine; +- public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; // Paper - private -> public ++ private final ServerLevel level; ++ public final Thread mainThread; // Paper - private -> public ++ private final ThreadedLevelLightEngine lightEngine; + public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; // Paper private -> public public final ChunkMap chunkMap; private final DimensionDataStorage dataStorage; private long lastInhabitedUpdate; @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - - return ret; } -+ -+ @Nullable -+ public ChunkAccess getChunkAtImmediately(int x, int z) { -+ long k = ChunkPos.asLong(x, z); -+ -+ // Note: Bypass cache to make this MT-Safe -+ -+ ChunkHolder playerChunk = this.getVisibleChunkIfPresent(k); -+ if (playerChunk == null) { -+ return null; -+ } -+ -+ return playerChunk.getAvailableChunkNow(); -+ -+ } // Paper end - - @Nullable + // Paper start - async chunk io ++ @Nullable + public ChunkAccess getChunkAtImmediately(int x, int z) { + ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); + if (holder == null) { @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { return this.lastSpawnState; } -- final class MainThreadExecutor extends BlockableEventLoop { +- private final class MainThreadExecutor extends BlockableEventLoop { + public final class MainThreadExecutor extends BlockableEventLoop { // Paper - package -> public - private MainThreadExecutor(Level world) { + MainThreadExecutor(Level world) { super("Chunk source main thread executor for " + world.dimension().location()); diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -178,8 +178,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 @@ public class ChunkSerializer { + return nbttagcompound; } - // Paper end + // Paper start + public static ChunkStatus getStatus(CompoundTag compound) { @@ -192,29 +192,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - public static ChunkStatus.ChunkType getChunkTypeFromTag(@Nullable CompoundTag tag) { - if (tag != null) { - ChunkStatus chunkstatus = ChunkStatus.byName(tag.getCompound("Level").getString("Status")); -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 { - -- private final IOWorker worker; -+ private final IOWorker worker; public IOWorker getIOWorker() { return worker; } // Paper - OBFHELPER - protected final DataFixer fixerUpper; - @Nullable - private LegacyStructureDataHandler legacyStructureHandler; + public static ChunkStatus.ChunkType getChunkTypeFromTag(@Nullable CompoundTag nbt) { + if (nbt != null) { + ChunkStatus chunkstatus = ChunkStatus.byName(nbt.getCompound("Level").getString("Status")); 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 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -0,0 +0,0 @@ import net.minecraft.Util; - import net.minecraft.nbt.CompoundTag; - import net.minecraft.nbt.NbtIo; +@@ -0,0 +0,0 @@ import java.nio.file.StandardOpenOption; + import javax.annotation.Nullable; + import net.minecraft.Util; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; import org.apache.logging.log4j.LogManager; @@ -222,7 +209,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { protected final RegionBitmap usedSectors; - public final File file; // Paper + public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper + // Paper start - Cache chunk status + private final ChunkStatus[] statuses = new ChunkStatus[32 * 32]; @@ -259,8 +246,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static int getOffsetIndex(ChunkPos pos) { return pos.getRegionLocalX() + pos.getRegionLocalZ() * 32; } - - public void close() throws IOException { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { + synchronized (this) { + try { + // Paper end + this.closed = true; // Paper try { this.padToFullSector(); @@ -269,30 +258,19 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSto index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable { - this.sync = dsync; +@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { // Paper - no final + + try { + NbtIo.write(nbt, (DataOutput) dataoutputstream); ++ regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - cache status on disk + } catch (Throwable throwable) { + if (dataoutputstream != null) { + try { +@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { // Paper - no final + } - -- private RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit + } + -+ // Paper start -+ public RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { -+ return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ())); -+ } -+ -+ // Paper end -+ public RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - private > public - long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); - RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); - -@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable { - - try { - NbtIo.write(tag, (DataOutput) dataoutputstream); -+ regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(tag)); // Paper - cache status on disk - regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone - } catch (Throwable throwable1) { - throwable = throwable1; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -323,7 +301,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return chunk instanceof ImposterProtoChunk || chunk instanceof net.minecraft.world.level.chunk.LevelChunk; + } try { -- return world.getChunkSource().getChunkAtIfCachedImmediately(x, z) != null || world.getChunkSource().chunkMap.read(new ChunkPos(x, z)) != null; // Paper (TODO check if the first part can be removed) +- return this.world.getChunkSource().getChunkAtIfCachedImmediately(x, z) != null || this.world.getChunkSource().chunkMap.read(new ChunkPos(x, z)) != null; // Paper (TODO check if the first part can be removed) + return world.getChunkSource().chunkMap.getChunkStatusOnDisk(new ChunkPos(x, z)) == ChunkStatus.FULL; + // Paper end } catch (IOException ex) { @@ -333,14 +311,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean loadChunk(int x, int z, boolean generate) { org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot -- ChunkAccess chunk = world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper +- ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper + // Paper start - Optimize this method + ChunkPos chunkPos = new ChunkPos(x, z); - // If generate = false, but the chunk already exists, we will get this back. - if (chunk instanceof ImposterProtoChunk) { - // We then cycle through again to get the full chunk immediately, rather than after the ticket addition -- chunk = world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); +- chunk = this.world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); - } + if (!generate) { + ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z); @@ -357,11 +335,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } - if (chunk instanceof net.minecraft.world.level.chunk.LevelChunk) { -- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); +- this.world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); - return true; + net.minecraft.world.level.chunk.storage.RegionFile file; + try { -+ file = world.getChunkSource().chunkMap.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ file = world.getChunkSource().chunkMap.regionFileCache.getFile(chunkPos, false); + } catch (IOException ex) { + throw new RuntimeException(ex); + }