geforkt von Mirrors/Paper
async chunk patch progress (#6930)
Dieser Commit ist enthalten in:
Ursprung
682bb3f9c0
Commit
ddaf1cb4e2
@ -50,7 +50,7 @@ public net.minecraft.world.entity.player.Player removeEntitiesOnShoulder()V
|
||||
# LivingEntity setkiller
|
||||
public net.minecraft.world.entity.LivingEntity lastHurtByPlayerTime
|
||||
|
||||
# SkeletonHorse Addittions
|
||||
# SkeletonHorse Additions
|
||||
public net.minecraft.world.entity.animal.horse.SkeletonHorse trapTime
|
||||
|
||||
# Fix client rendering skulls
|
||||
@ -66,6 +66,7 @@ public-f net.minecraft.world.level.chunk.storage.RegionFileStorage
|
||||
public net.minecraft.world.level.chunk.storage.RegionFileStorage getFile(Lnet/minecraft/world/level/ChunkPos;Z)Lnet/minecraft/world/level/chunk/storage/RegionFile;
|
||||
public net.minecraft.world.level.chunk.storage.SectionStorage dirty
|
||||
public net.minecraft.util.thread.BlockableEventLoop runAllTasks()V
|
||||
public net.minecraft.server.level.ChunkMap getPoiManager()Lnet/minecraft/world/entity/ai/village/poi/PoiManager;
|
||||
|
||||
# Improve death events
|
||||
public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent;
|
||||
|
@ -3,8 +3,7 @@ From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
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)
|
||||
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
|
||||
@ -1540,8 +1539,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // apply fixes
|
||||
+
|
||||
+ try {
|
||||
+ chunkData.chunkData = chunkManager.getChunkData(this.world.getTypeKey(),
|
||||
+ chunkManager.overworldDataStorage, chunkData.chunkData, chunkPos, this.world); // clone data for safety, file IO thread does not clone
|
||||
+ chunkData.chunkData = chunkManager.upgradeChunkTag(this.world.getTypeKey(),
|
||||
+ chunkManager.overworldDataStorage, chunkData.chunkData, chunkManager.generator.getTypeNameForDataFixer(), chunkPos, this.world); // clone data for safety, file IO thread does not clone
|
||||
+ } catch (final Throwable ex) {
|
||||
+ PaperFileIOThread.LOGGER.error("Could not apply datafixers for chunk task: " + this.toString(), ex);
|
||||
+ this.complete(ChunkLoadTask.createEmptyHolder());
|
||||
@ -1552,8 +1551,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ chunkHolder = ChunkSerializer.loadChunk(this.world,
|
||||
+ chunkManager.structureManager, chunkManager.getVillagePlace(), chunkPos,
|
||||
+ chunkHolder = ChunkSerializer.loadChunk(this.world, chunkManager.getPoiManager(), chunkPos,
|
||||
+ chunkData.chunkData, true);
|
||||
+ } catch (final Throwable ex) {
|
||||
+ PaperFileIOThread.LOGGER.error("Could not de-serialize chunk data for task: " + this.toString(), ex);
|
||||
@ -2280,19 +2278,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- 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 {
|
||||
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) {
|
||||
+ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
@ -2322,25 +2307,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/mai
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
return chunkstatus;
|
||||
}
|
||||
}
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ public ChunkStatus getChunkHolderStatus() {
|
||||
+ for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) {
|
||||
+ CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr);
|
||||
+ Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null);
|
||||
+ if (either == null || !either.left().isPresent()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ return curr;
|
||||
+ }
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel);
|
||||
ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel);
|
||||
@ -2471,7 +2437,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ LOGGER.fatal("Failed to prepare async save, attempting synchronous save", ex);
|
||||
+ this.save(ichunkaccess);
|
||||
+ }
|
||||
+ // Paper end - async chunk savin
|
||||
+ // Paper end - async chunk saving
|
||||
if (this.entitiesInLevel.remove(pos) && ichunkaccess instanceof LevelChunk) {
|
||||
LevelChunk chunk = (LevelChunk) ichunkaccess;
|
||||
|
||||
@ -2504,6 +2470,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
+ 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);
|
||||
}
|
||||
@ -2629,15 +2596,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - async chunk io
|
||||
+ public ChunkAccess getChunkAtImmediately(int x, int z) {
|
||||
+ ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
|
||||
+ if (holder == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return holder.getLastAvailable();
|
||||
+ }
|
||||
+
|
||||
+ private long asyncLoadSeqCounter;
|
||||
+
|
||||
+ public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkAtAsynchronously(int x, int z, boolean gen, boolean isUrgent) {
|
||||
@ -2736,14 +2694,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return CompletableFuture.completedFuture(either);
|
||||
+ }, this.mainThreadProcessor);
|
||||
+ }
|
||||
+
|
||||
+ public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
||||
+ this.distanceManager.addTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
|
||||
+ }
|
||||
+
|
||||
+ public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
||||
+ this.distanceManager.removeTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
|
||||
+ }
|
||||
+ // Paper end - async chunk io
|
||||
|
||||
@Nullable
|
||||
@ -2812,21 +2762,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ public final com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController poiDataController = new com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController() {
|
||||
+ @Override
|
||||
+ public void writeData(int x, int z, net.minecraft.nbt.CompoundTag compound) throws java.io.IOException {
|
||||
+ ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().write(new ChunkPos(x, z), compound);
|
||||
+ ServerLevel.this.getChunkSource().chunkMap.getPoiManager().write(new ChunkPos(x, z), compound);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.minecraft.nbt.CompoundTag readData(int x, int z) throws java.io.IOException {
|
||||
+ return ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().read(new ChunkPos(x, z));
|
||||
+ return ServerLevel.this.getChunkSource().chunkMap.getPoiManager().read(new ChunkPos(x, z));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T> T computeForRegionFile(int chunkX, int chunkZ, java.util.function.Function<net.minecraft.world.level.chunk.storage.RegionFile, T> function) {
|
||||
+ synchronized (ServerLevel.this.getChunkSource().chunkMap.getVillagePlace()) {
|
||||
+ synchronized (ServerLevel.this.getChunkSource().chunkMap.getPoiManager()) {
|
||||
+ net.minecraft.world.level.chunk.storage.RegionFile file;
|
||||
+
|
||||
+ try {
|
||||
+ file = ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().getFile(new ChunkPos(chunkX, chunkZ), false);
|
||||
+ file = ServerLevel.this.getChunkSource().chunkMap.getPoiManager().getRegionFile(new ChunkPos(chunkX, chunkZ), false);
|
||||
+ } catch (java.io.IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
@ -2837,8 +2787,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+
|
||||
+ @Override
|
||||
+ public <T> T computeForRegionFileIfLoaded(int chunkX, int chunkZ, java.util.function.Function<net.minecraft.world.level.chunk.storage.RegionFile, T> function) {
|
||||
+ synchronized (ServerLevel.this.getChunkSource().chunkMap.getVillagePlace()) {
|
||||
+ net.minecraft.world.level.chunk.storage.RegionFile file = ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().getRegionFileIfLoaded(new ChunkPos(chunkX, chunkZ));
|
||||
+ synchronized (ServerLevel.this.getChunkSource().chunkMap.getPoiManager()) {
|
||||
+ net.minecraft.world.level.chunk.storage.RegionFile file = ServerLevel.this.getChunkSource().chunkMap.getPoiManager().getRegionFileIfLoaded(new ChunkPos(chunkX, chunkZ));
|
||||
+ return function.apply(file);
|
||||
+ }
|
||||
+ }
|
||||
@ -2861,7 +2811,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ net.minecraft.world.level.chunk.storage.RegionFile file;
|
||||
+
|
||||
+ try {
|
||||
+ file = ServerLevel.this.getChunkSource().chunkMap.regionFileCache.getFile(new ChunkPos(chunkX, chunkZ), false);
|
||||
+ file = ServerLevel.this.getChunkSource().chunkMap.regionFileCache.getRegionFile(new ChunkPos(chunkX, chunkZ), false);
|
||||
+ } catch (java.io.IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
@ -3085,9 +3035,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
- 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;
|
||||
@ -3107,9 +3057,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ this.fluidTickList = fluidTickList;
|
||||
+ this.blockEntities = blockEntities;
|
||||
+ this.worldTime = worldTime;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
}
|
||||
}
|
||||
|
||||
+ // must be called sync
|
||||
+ public static AsyncSaveData getAsyncSaveData(ServerLevel world, ChunkAccess chunk) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("preparation of chunk data for async save");
|
||||
@ -3139,22 +3089,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ net.minecraft.world.ticks.TickContainerAccess<Block> blockTickList = chunk.getBlockTicks();
|
||||
+
|
||||
+ //TODO check ChunkSerializer "block_ticks"
|
||||
+ ListTag blockTickListSerialized;
|
||||
+ if (blockTickList instanceof ProtoTickList || blockTickList instanceof ChunkTickList) {
|
||||
+ blockTickListSerialized = null;
|
||||
+ } else {
|
||||
+ blockTickListSerialized = world.getBlockTicks().save(chunkPos);
|
||||
+ }
|
||||
+ ListTag blockTickListSerialized = null; // Paper - remove null
|
||||
+ // if (blockTickList instanceof ProtoTickList || blockTickList instanceof ChunkTickList) {
|
||||
+ // blockTickListSerialized = null;
|
||||
+ // } else {
|
||||
+ // blockTickListSerialized = world.getBlockTicks().save(chunkPos);
|
||||
+ // }
|
||||
+
|
||||
+ net.minecraft.world.ticks.TickContainerAccess<Fluid> fluidTickList = chunk.getFluidTicks();
|
||||
+
|
||||
+ //TODO
|
||||
+ ListTag fluidTickListSerialized;
|
||||
+ if (fluidTickList instanceof ProtoTickList || fluidTickList instanceof ChunkTickList) {
|
||||
+ fluidTickListSerialized = null;
|
||||
+ } else {
|
||||
+ fluidTickListSerialized = world.getFluidTicks().save(chunkPos);
|
||||
+ }
|
||||
+ ListTag fluidTickListSerialized = null; // Paper - remove null
|
||||
+ // if (fluidTickList instanceof ProtoTickList || fluidTickList instanceof ChunkTickList) {
|
||||
+ // fluidTickListSerialized = null;
|
||||
+ // } else {
|
||||
+ // fluidTickListSerialized = world.getFluidTicks().save(chunkPos);
|
||||
+ // }
|
||||
+
|
||||
+ ListTag blockEntitiesSerialized = new ListTag();
|
||||
+ for (final BlockPos blockPos : chunk.getBlockEntitiesPos()) {
|
||||
@ -3182,9 +3132,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
CompoundTag nbttagcompound = new CompoundTag();
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
nbttagcompound.putInt("xPos", chunkcoordintpair.x);
|
||||
nbttagcompound.putInt("yPos", chunk.getMinSection());
|
||||
nbttagcompound.putInt("zPos", chunkcoordintpair.z);
|
||||
nbttagcompound.putLong("LastUpdate", world.getGameTime());
|
||||
- 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());
|
||||
@ -3333,6 +3284,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
|
||||
public ChunkScanAccess chunkScanner() {
|
||||
- return this.worker;
|
||||
+ // Paper start - nuke IO worker
|
||||
+ return ((chunkPos, streamTagVisitor) -> {
|
||||
+ try {
|
||||
+ this.regionFileCache.scanChunk(chunkPos, streamTagVisitor);
|
||||
+ return java.util.concurrent.CompletableFuture.completedFuture(null);
|
||||
+ } catch (IOException e) {
|
||||
+ throw new RuntimeException(e);
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
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
|
||||
@ -3384,27 +3348,27 @@ 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
|
||||
|
||||
- private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
+ // Paper start
|
||||
+ public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) {
|
||||
+ return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()));
|
||||
+ }
|
||||
+
|
||||
+ public synchronized boolean chunkExists(ChunkPos pos) throws IOException {
|
||||
+ RegionFile regionfile = getFile(pos, true);
|
||||
+ RegionFile regionfile = getRegionFile(pos, true);
|
||||
+
|
||||
+ return regionfile != null ? regionfile.hasChunk(pos) : false;
|
||||
+ }
|
||||
+
|
||||
+ public synchronized RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
+ return this.getFile(chunkcoordintpair, existingOnly, false);
|
||||
+ public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
+ return this.getRegionFile(chunkcoordintpair, existingOnly, false);
|
||||
+ }
|
||||
+ public synchronized RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
|
||||
+ public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
|
||||
+ // Paper end
|
||||
long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
|
||||
RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i);
|
||||
|
||||
|
||||
if (regionfile != null) {
|
||||
+ // Paper start
|
||||
+ if (lock) {
|
||||
@ -3416,8 +3380,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
} else {
|
||||
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);
|
||||
|
||||
RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
|
||||
|
||||
this.regionCache.putAndMoveToFirst(i, regionfile1);
|
||||
+ // Paper start
|
||||
+ if (lock) {
|
||||
@ -3432,54 +3396,58 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
@Nullable
|
||||
public CompoundTag read(ChunkPos pos) throws IOException {
|
||||
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
||||
- RegionFile regionfile = this.getFile(pos, true);
|
||||
+ RegionFile regionfile = this.getFile(pos, true, true); // Paper
|
||||
- RegionFile regionfile = this.getRegionFile(pos, true);
|
||||
+ RegionFile regionfile = this.getRegionFile(pos, true, true); // Paper
|
||||
if (regionfile == null) {
|
||||
return null;
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
public void scanChunk(ChunkPos chunkcoordintpair, StreamTagVisitor streamtagvisitor) throws IOException {
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
|
||||
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
|
||||
- RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit
|
||||
+ RegionFile regionfile = this.getRegionFile(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);
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk", laste);
|
||||
}
|
||||
// Paper end
|
||||
+ } finally { // Paper start
|
||||
+ regionfile.fileLock.unlock();
|
||||
+ } // Paper end
|
||||
}
|
||||
|
||||
|
||||
- public void close() throws IOException {
|
||||
+ public synchronized void close() throws IOException { // Paper -> synchronized
|
||||
ExceptionCollector<IOException> 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
|
||||
@ -3488,7 +3456,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<R> implements AutoCloseable {
|
||||
+public class SectionStorage<R> extends RegionFileStorage implements AutoCloseable { // Paper - nuke IOWorker
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
@ -3500,22 +3468,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
private final Function<Runnable, Codec<R>> codec;
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
|
||||
protected final LevelHeightAccessor levelHeightAccessor;
|
||||
|
||||
public SectionStorage(File directory, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) {
|
||||
+ super(directory, dsync); // Paper - nuke IOWorker
|
||||
|
||||
public SectionStorage(Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) {
|
||||
+ super(path, dsync);
|
||||
this.codec = codecFactory;
|
||||
this.factory = factory;
|
||||
this.fixerUpper = dataFixer;
|
||||
this.type = dataFixTypes;
|
||||
this.levelHeightAccessor = world;
|
||||
- this.worker = new IOWorker(directory, dsync, directory.getName());
|
||||
- this.worker = new IOWorker(path, dsync, path.getFileName().toString());
|
||||
+ // Paper - remove mojang I/O thread
|
||||
}
|
||||
|
||||
|
||||
protected void tick(BooleanSupplier shouldKeepTicking) {
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
|
||||
}
|
||||
|
||||
|
||||
private void readColumn(ChunkPos chunkPos) {
|
||||
- this.readColumn(chunkPos, NbtOps.INSTANCE, this.tryRead(chunkPos));
|
||||
+ // Paper start - expose function to load in data
|
||||
@ -3525,7 +3493,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 {
|
||||
@ -3543,9 +3511,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<Tag> dynamic = this.writeColumn(chunkcoordintpair, NbtOps.INSTANCE);
|
||||
@ -3561,7 +3529,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper end
|
||||
private <T> Dynamic<T> writeColumn(ChunkPos chunkPos, DynamicOps<T> dynamicOps) {
|
||||
Map<T, T> map = Maps.newHashMap();
|
||||
|
||||
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
|
@ -10,7 +10,7 @@ rootProject.name = "Paper"
|
||||
include(
|
||||
"Paper-API",
|
||||
"Paper-Server",
|
||||
// "Paper-MojangAPI", // todo
|
||||
"Paper-MojangAPI",
|
||||
)
|
||||
|
||||
val testPlugin = file("test-plugin.settings.gradle.kts")
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren