hate jmp and his gradle

This commit is contained in:
Spottedleaf 2022-06-07 17:15:06 -07:00
parent a4ed02355a
commit e83c74a0a0
13 changed files with 195 additions and 171 deletions

View file

@ -846,16 +846,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ write = this.inProgressWrite;
+ }
+
+ // check if another process is writing
+ /*try { TODO: Can we restore this?
+ ((WorldServer)this.world).checkSession();
+ } catch (final Exception ex) {
+ LOGGER.fatal("Couldn't save chunk; already in use by another instance of Minecraft?", ex);
+ // we don't need to set the write counter to -1 as we know at this stage there's no point in re-scheduling
+ // writes since they'll fail anyways.
+ return;
+ }
+*/
+ for (;;) {
+ final long writeCounter;
+ final CompoundTag data;
@ -1487,13 +1477,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import com.destroystokyo.paper.io.IOUtil;
+import java.util.ArrayDeque;
+import java.util.function.Consumer;
+import com.mojang.logging.LogUtils;
+import net.minecraft.server.level.ChunkMap;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.storage.ChunkSerializer;
+import org.slf4j.Logger;
+
+public final class ChunkLoadTask extends ChunkTask {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+
+ public boolean cancelled;
+
+ Consumer<ChunkSerializer.InProgressChunkHolder> onComplete;
@ -1519,7 +1513,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ try {
+ this.executeTask();
+ } catch (final Throwable ex) {
+ PaperFileIOThread.LOGGER.error("Failed to execute chunk load task: " + this.toString(), ex);
+ LOGGER.error("Failed to execute chunk load task: " + this.toString(), ex);
+ if (!this.hasCompleted) {
+ this.complete(ChunkLoadTask.createEmptyHolder());
+ }
@ -1552,7 +1546,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final PaperFileIOThread.ChunkData chunkData = this.chunkData;
+
+ if (chunkData.poiData == PaperFileIOThread.FAILURE_VALUE || chunkData.chunkData == PaperFileIOThread.FAILURE_VALUE) {
+ PaperFileIOThread.LOGGER.error("Could not load chunk for task: " + this.toString() + ", file IO thread has dumped the relevant exception above");
+ LOGGER.error("Could not load chunk for task: " + this.toString() + ", file IO thread has dumped the relevant exception above");
+ this.complete(ChunkLoadTask.createEmptyHolder());
+ return;
+ }
@ -1563,6 +1557,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return;
+ }
+
+ if (!ChunkMap.isChunkDataValid(chunkData.chunkData)) {
+ LOGGER.error("Chunk file at {} is missing level data, skipping", new ChunkPos(this.chunkX, this.chunkZ));
+ this.complete(ChunkLoadTask.createEmptyHolder());
+ return;
+ }
+
+ final ChunkPos chunkPos = new ChunkPos(this.chunkX, this.chunkZ);
+
+ final ChunkMap chunkManager = this.world.getChunkSource().chunkMap;
@ -1576,7 +1576,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ 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);
+ LOGGER.error("Could not apply datafixers for chunk task: " + this.toString(), ex);
+ this.complete(ChunkLoadTask.createEmptyHolder());
+ return;
+ }
@ -1589,7 +1589,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ 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);
+ LOGGER.error("Could not de-serialize chunk data for task: " + this.toString(), ex);
+ this.complete(ChunkLoadTask.createEmptyHolder());
+ return;
+ }
@ -1612,7 +1612,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ try {
+ ChunkLoadTask.this.onComplete.accept(holder);
+ } catch (final Throwable thr) {
+ PaperFileIOThread.LOGGER.error("Failed to complete chunk data for task: " + this.toString(), thr);
+ LOGGER.error("Failed to complete chunk data for task: " + this.toString(), thr);
+ }
+ return null;
+ });
@ -2315,7 +2315,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
*/
+ 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) -> {
DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), minecraftsessionservice, gameprofilerepository, usercache, LoggerChunkProgressListener::new);
DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
@ -2330,19 +2330,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
public String getLocalIp() {
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
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 {
ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel);
ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel);
boolean flag = this.oldTicketLevel <= ChunkMap.MAX_CHUNK_DISTANCE;
- boolean flag1 = this.ticketLevel <= ChunkMap.MAX_CHUNK_DISTANCE;
+ boolean flag1 = this.ticketLevel <= ChunkMap.MAX_CHUNK_DISTANCE; // Paper - diff on change: (flag1 = new ticket level is in loadable range)
ChunkHolder.FullChunkStatus playerchunk_state = ChunkHolder.getFullChunkStatus(this.oldTicketLevel);
ChunkHolder.FullChunkStatus playerchunk_state1 = ChunkHolder.getFullChunkStatus(this.ticketLevel);
// CraftBukkit start
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
@ -2403,41 +2390,32 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> scheduleChunkLoad(ChunkPos pos) {
- return CompletableFuture.supplyAsync(() -> {
- return this.readChunk(pos).thenApply((optional) -> {
- return optional.filter((nbttagcompound) -> {
- boolean flag = ChunkMap.isChunkDataValid(nbttagcompound);
+ // Paper start - Async chunk io
+ final java.util.function.BiFunction<ChunkSerializer.InProgressChunkHolder, Throwable, Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> syncLoadComplete = (chunkHolder, ioThrowable) -> {
try (Timing ignored = this.level.timings.chunkLoad.startTimingIfSync()) { // Paper
this.level.getProfiler().incrementCounter("chunkLoad");
- CompoundTag nbttagcompound; // Paper
- 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
+ try (Timing ignored = this.level.timings.chunkLoad.startTimingIfSync()) { // Paper
+ this.level.getProfiler().incrementCounter("chunkLoad");
+ if (ioThrowable != null) {
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioThrowable);
+ return this.handleChunkLoadFailure(ioThrowable, pos);
+ }
+ this.poiManager.loadInData(pos, chunkHolder.poiData);
+ chunkHolder.tasks.forEach(Runnable::run);
+ // Paper end
+ 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
- if (!flag) {
- ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", pos);
+ if (chunkHolder.protoChunk != null) {
+ ProtoChunk protochunk = chunkHolder.protoChunk;
+ this.markPosition(pos, protochunk.getStatus().getChunkType());
+ return Either.left(protochunk);
}
+ } catch (Exception ex) {
+ return this.handleChunkLoadFailure(ex, pos);
+ }
this.markPositionReplaceable(pos);
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
- return flag;
+ return Either.left(this.createEmptyChunk(pos));
+ };
+ CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> ret = new CompletableFuture<>();
+
@ -2449,9 +2427,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } catch (Exception e) {
+ ret.completeExceptionally(e);
+ }
+ });
});
- }).thenApplyAsync((optional) -> {
- this.level.getProfiler().incrementCounter("chunkLoad");
- if (optional.isPresent()) {
- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, pos, (CompoundTag) optional.get());
+ };
+
- this.markPosition(pos, protochunk.getStatus().getChunkType());
- return Either.<ChunkAccess, ChunkHolder.ChunkLoadingFailure>left(protochunk); // CraftBukkit - decompile error
- } else {
- return Either.<ChunkAccess, ChunkHolder.ChunkLoadingFailure>left(this.createEmptyChunk(pos)); // CraftBukkit - decompile error
- }
- }, this.mainThreadExecutor).exceptionallyAsync((throwable) -> {
- return this.handleChunkLoadFailure(throwable, pos);
- }, this.mainThreadExecutor);
+ CompletableFuture<CompoundTag> chunkSaveFuture = this.level.asyncChunkTaskManager.getChunkSaveFuture(pos.x, pos.z);
+ if (chunkSaveFuture != null) {
+ this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z,
@ -2462,10 +2452,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY, chunkHolderConsumer, false);
+ }
+ return ret;
+ // Paper end
+ // Paper end - Async chunk io
}
- private static boolean isChunkDataValid(CompoundTag nbt) {
+ public static boolean isChunkDataValid(CompoundTag nbt) { // Paper - async chunk loading
return nbt.contains("Status", 8);
}
private void markPositionReplaceable(ChunkPos pos) {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
@ -2557,7 +2551,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start - Asynchronous chunk io
+ @Nullable
+ @Override
+ public CompoundTag read(ChunkPos chunkcoordintpair) throws IOException {
+ public CompoundTag readSync(ChunkPos chunkcoordintpair) throws IOException {
+ if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ CompoundTag ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE
+ .loadChunkDataAsyncFuture(this.level, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(),
@ -2568,7 +2562,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ return ret;
+ }
+ return super.read(chunkcoordintpair);
+ return super.readSync(chunkcoordintpair);
+ }
+
+ @Override
@ -2583,9 +2577,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ // Paper end
+
@Nullable
public CompoundTag readChunk(ChunkPos pos) throws IOException {
CompoundTag nbttagcompound = this.read(pos);
private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkPos) {
return this.read(chunkPos).thenApplyAsync((optional) -> {
return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
@ -2814,7 +2808,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ @Override
+ public net.minecraft.nbt.CompoundTag readData(int x, int z) throws java.io.IOException {
+ return ServerLevel.this.getChunkSource().chunkMap.read(new ChunkPos(x, z));
+ return ServerLevel.this.getChunkSource().chunkMap.readSync(new ChunkPos(x, z));
+ }
+
+ @Override
@ -2843,7 +2837,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager;
// Paper end
// Add env and gen to constructor, WorldData -> WorldDataServer
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.sleepStatus = new SleepStatus();
@ -2870,13 +2864,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper
server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper
return;
}
+ // Paper start
+ String str = packet.getCommand(); int index = -1;
+ if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) {
+ server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper
+ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper
+ return;
+ }
+ // Paper end
@ -2893,8 +2887,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private final LongSet loadedChunks = new LongOpenHashSet();
+ private final net.minecraft.server.level.ServerLevel world; // Paper
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) {
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world);
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) {
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world);
+ this.world = (net.minecraft.server.level.ServerLevel)world; // Paper
this.distanceTracker = new PoiManager.DistanceTracker();
}
@ -2992,17 +2986,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
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(chunkPos, true);
+ }); // Paper - delay this task since we're executing off-main
}
Registry<Biome> iregistry = world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
@@ -0,0 +0,0 @@ public class ChunkSerializer {
LevelChunkSection chunksection = new LevelChunkSection(b0, datapaletteblock, datapaletteblock1);
LevelChunkSection chunksection = new LevelChunkSection(b0, datapaletteblock, (PalettedContainer) object); // CraftBukkit - read/write
achunksection[k] = chunksection;
+ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main
@ -3010,23 +2994,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }); // Paper - delay this task since we're executing off-main
}
if (flag) {
if (nbttagcompound1.contains("BlockLight", 7)) {
boolean flag3 = nbttagcompound1.contains("BlockLight", 7);
@@ -0,0 +0,0 @@ public class ChunkSerializer {
if (flag3 || flag4) {
if (!flag2) {
+ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main
lightengine.retainData(chunkPos, true);
+ }); // Paper - delay this task since we're executing off-main
flag2 = true;
}
if (flag3) {
- 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(nbttagcompound1.getByteArray("BlockLight"));
+ DataLayer blockLight = new DataLayer(nbttagcompound1.getByteArray("BlockLight").clone());
+ tasksToExecuteOnMain.add(() -> {
+ lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkcoordintpair1, b0), blockLight, true);
+ lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), blockLight, true);
+ });
+ // Paper end - delay this task since we're executing off-main
}
if (flag1 && nbttagcompound1.contains("SkyLight", 7)) {
if (flag4) {
- 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(nbttagcompound1.getByteArray("SkyLight"));
+ DataLayer skyLight = new DataLayer(nbttagcompound1.getByteArray("SkyLight").clone());
+ tasksToExecuteOnMain.add(() -> {
+ lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkcoordintpair1, b0), skyLight, true);
+ lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), skyLight, true);
+ });
+ // Paper end - delay this task since we're executing off-mai
}
@ -3036,13 +3030,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) {
- return new ImposterProtoChunk((LevelChunk) object, false);
+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object, false), tasksToExecuteOnMain); // Paper - Async chunk loading
- return new ImposterProtoChunk((LevelChunk) object1, false);
+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false), tasksToExecuteOnMain); // Paper - Async chunk loading
} else {
ProtoChunk protochunk1 = (ProtoChunk) object;
ProtoChunk protochunk1 = (ProtoChunk) object1;
@@ -0,0 +0,0 @@ public class ChunkSerializer {
protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object).getMinBuildHeight()));
protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight()));
}
- return protochunk1;
@ -3111,7 +3105,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
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 {
}
// CraftBukkit end
public static CompoundTag write(ServerLevel world, ChunkAccess chunk) {
+ // Paper start
@ -3198,9 +3192,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper - nuke IO worker
protected final DataFixer fixerUpper;
@Nullable
- private LegacyStructureDataHandler legacyStructureHandler;
private volatile LegacyStructureDataHandler legacyStructureHandler;
+ // Paper start - async chunk loading
+ private volatile LegacyStructureDataHandler legacyStructureHandler;
+ private final Object persistentDataLock = new Object(); // Paper
+ public final RegionFileStorage regionFileCache;
+ // Paper end - async chunk loading
@ -3214,8 +3207,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - async chunk io
}
public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) {
- return this.worker.isOldChunkAround(chunkPos, checkRadius);
+ return true; // Paper - (for now, old unoptimised behavior) TODO implement later? the chunk status that blender uses SHOULD already have this radius loaded, no need to go back for it...
}
// CraftBukkit start
private boolean check(ServerChunkCache cps, int x, int z) throws IOException {
private boolean check(ServerChunkCache cps, int x, int z) {
ChunkPos pos = new ChunkPos(x, z);
if (cps != null) {
- com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");
@ -3225,19 +3223,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return true;
}
}
- CompoundTag nbt = this.read(pos);
+ // Paper start - prioritize
+ CompoundTag nbt = cps == null ? read(pos) :
+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.loadChunkData((ServerLevel)cps.getLevel(), x, z,
+ com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHER_PRIORITY, false, true).chunkData;
+ // Paper end
if (nbt != null) {
CompoundTag level = nbt.getCompound("Level");
if (level.getBoolean("TerrainPopulated")) {
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
public CompoundTag upgradeChunkTag(ResourceKey<LevelStem> resourcekey, Supplier<DimensionDataStorage> supplier, CompoundTag nbttagcompound, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) throws IOException {
public CompoundTag upgradeChunkTag(ResourceKey<LevelStem> resourcekey, Supplier<DimensionDataStorage> supplier, CompoundTag nbttagcompound, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) {
// CraftBukkit end
+ nbttagcompound = nbttagcompound.copy(); // Paper - defensive copy, another thread might modify this
int i = ChunkStorage.getVersion(nbttagcompound);
@ -3248,23 +3236,40 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, i, 1493);
if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) {
+ synchronized (this.persistentDataLock) { // Paper - Async chunk loading
if (this.legacyStructureHandler == null) {
this.legacyStructureHandler = LegacyStructureDataHandler.getLegacyStructureHandler(resourcekey, (DimensionDataStorage) supplier.get());
}
LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier);
nbttagcompound = this.legacyStructureHandler.updateFromLegacy(nbttagcompound);
nbttagcompound = persistentstructurelegacy.updateFromLegacy(nbttagcompound);
+ } // Paper - Async chunk loading
}
}
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
LegacyStructureDataHandler persistentstructurelegacy = this.legacyStructureHandler;
@Nullable
public CompoundTag read(ChunkPos chunkPos) throws IOException {
- return this.worker.load(chunkPos);
+ return this.regionFileCache.read(chunkPos); // Paper - async chunk io
if (persistentstructurelegacy == null) {
- synchronized (this) {
+ synchronized (this.persistentDataLock) { // Paper - async chunk loading
persistentstructurelegacy = this.legacyStructureHandler;
if (persistentstructurelegacy == null) {
this.legacyStructureHandler = persistentstructurelegacy = LegacyStructureDataHandler.getLegacyStructureHandler(resourcekey, (DimensionDataStorage) supplier.get());
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
}
public CompletableFuture<Optional<CompoundTag>> read(ChunkPos chunkPos) {
- return this.worker.loadAsync(chunkPos);
+ // Paper start - async chunk io
+ try {
+ return CompletableFuture.completedFuture(Optional.ofNullable(this.readSync(chunkPos)));
+ } catch (Throwable thr) {
+ return CompletableFuture.failedFuture(thr);
+ }
+ }
+ @Nullable
+ public CompoundTag readSync(ChunkPos chunkPos) throws IOException {
+ return this.regionFileCache.read(chunkPos);
}
+ // Paper end - async chunk io
- public void write(ChunkPos chunkPos, CompoundTag nbt) {
- this.worker.store(chunkPos, nbt);
+ // Paper start - async chunk io
@ -3475,12 +3480,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
protected final LevelHeightAccessor levelHeightAccessor;
public SectionStorage(Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) {
+ super(path, dsync);
public SectionStorage(Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) {
+ super(path, dsync); // Paper - remove mojang I/O thread
this.codec = codecFactory;
this.factory = factory;
this.fixerUpper = dataFixer;
this.type = dataFixTypes;
this.registryAccess = dynamicRegistryManager;
this.levelHeightAccessor = world;
- this.worker = new IOWorker(path, dsync, path.getFileName().toString());
+ // Paper - remove mojang I/O thread
@ -3490,34 +3496,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -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
+ this.loadInData(chunkPos, this.tryRead(chunkPos));
private CompletableFuture<Optional<CompoundTag>> tryRead(ChunkPos pos) {
- return this.worker.loadAsync(pos).exceptionally((throwable) -> {
- if (throwable instanceof IOException iOException) {
- LOGGER.error("Error reading chunk {} data from disk", pos, iOException);
- return Optional.empty();
- } else {
- throw new CompletionException(throwable);
- }
- });
+ // Paper start - async chunk io
+ try {
+ return CompletableFuture.completedFuture(Optional.ofNullable(this.read(pos)));
+ } catch (Throwable thr) {
+ return CompletableFuture.failedFuture(thr);
+ }
+ // Paper end - async chunk io
+ }
+
+ // Paper start - async chunk io
+ public void loadInData(ChunkPos chunkPos, CompoundTag compound) {
+ this.readColumn(chunkPos, NbtOps.INSTANCE, compound);
+ // Paper end - expose function to load in data
}
+ // Paper end - aync chnnk i
@Nullable
private CompoundTag tryRead(ChunkPos pos) {
try {
- return this.worker.load(pos);
+ return this.read(pos); // Paper - nuke IOWorker
} catch (IOException var3) {
LOGGER.error("Error reading chunk {} data from disk", pos, var3);
return null;
private <T> void readColumn(ChunkPos pos, DynamicOps<T> ops, @Nullable T data) {
if (data == null) {
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
Dynamic<Tag> dynamic = this.writeColumn(chunkPos, NbtOps.INSTANCE);
Dynamic<Tag> dynamic = this.writeColumn(pos, registryOps);
Tag tag = dynamic.getValue();
if (tag instanceof CompoundTag) {
- this.worker.store(chunkPos, (CompoundTag)tag);
+ try { this.write(chunkPos, (CompoundTag)tag); } catch (IOException ioexception) { SectionStorage.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker
- this.worker.store(pos, (CompoundTag)tag);
+ try { this.write(pos, (CompoundTag)tag); } catch (IOException ioexception) { SectionStorage.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker
} else {
LOGGER.error("Expected compound tag, got {}", (Object)tag);
}
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
return new Dynamic<>(ops, ops.createMap(ImmutableMap.of(ops.createString("Sections"), ops.createMap(map), ops.createString("DataVersion"), ops.createInt(SharedConstants.getCurrentVersion().getWorldVersion()))));
}
+ // Paper start - internal get data function, copied from above
@ -3533,9 +3548,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return null;
+ }
+ // Paper end
private <T> Dynamic<T> writeColumn(ChunkPos chunkPos, DynamicOps<T> dynamicOps) {
Map<T, T> map = Maps.newHashMap();
+
private static long getKey(ChunkPos chunkPos, int y) {
return SectionPos.asLong(chunkPos.x, y, chunkPos.z);
}
@@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
@Override
@ -3604,14 +3620,6 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -0,0 +0,0 @@ import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.TicketType;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.entity.Entity;
@@ -0,0 +0,0 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
this.entity.setYHeadRot(yaw);
}

View file

@ -22,6 +22,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public int cookingProgress;
public int cookingTotalTime;
protected final ContainerData dataAccess;
public final Object2IntOpenHashMap<ResourceLocation> recipesUsed;
private final RecipeManager.CachedCheck<Container, ? extends AbstractCookingRecipe> quickCheck;
+ public final RecipeType<? extends AbstractCookingRecipe> recipeType; // Paper
protected AbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, RecipeType<? extends AbstractCookingRecipe> recipeType) {
super(blockEntityType, pos, state);
@@ -0,0 +0,0 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
};
this.recipesUsed = new Object2IntOpenHashMap();
this.quickCheck = RecipeManager.createCheck((RecipeType<AbstractCookingRecipe>) recipeType); // CraftBukkit - decompile error // Eclipse fail
+ this.recipeType = recipeType; // Paper
}
public static Map<Item, Integer> getFuel() {
@@ -0,0 +0,0 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
this.recipesUsed.put(new ResourceLocation(s), nbttagcompound1.getInt(s));
}
@ -58,8 +72,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- if (blockEntity.cookingProgress == blockEntity.cookingTotalTime) {
+ if (blockEntity.cookingProgress >= blockEntity.cookingTotalTime) { // Paper - cook speed multiplier API
blockEntity.cookingProgress = 0;
- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity);
+ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier);
- blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity);
+ blockEntity.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(world, blockEntity.recipeType, blockEntity, blockEntity.cookSpeedMultiplier); // Paper
if (AbstractFurnaceBlockEntity.burn(blockEntity.level, blockEntity.worldPosition, irecipe, blockEntity.items, i)) { // CraftBukkit
blockEntity.setRecipeUsed(irecipe);
}
@ -67,12 +81,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
}
- private static int getTotalCookTime(Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, Container inventory) {
- return (world != null) ? (Integer) world.getRecipeManager().getRecipeFor((RecipeType<AbstractCookingRecipe>) recipeType, inventory, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : 200; // CraftBukkit - SPIGOT-4302 // Eclipse fail
+ // Paper begin - Expose this function so CraftFurnace can correctly scale the total cooking time to a new multiplier
+ public static int getTotalCookTime(@Nullable Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, Container inventory, final double cookSpeedMultiplier) {
- private static int getTotalCookTime(Level world, AbstractFurnaceBlockEntity furnace) {
- return (world != null) ? (Integer) furnace.quickCheck.getRecipeFor(furnace, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : 200; // CraftBukkit - SPIGOT-4302
+ // Paper start
+ public static int getTotalCookTime(Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, AbstractFurnaceBlockEntity furnace, double cookSpeedMultiplier) {
+ /* Scale the recipe's cooking time to the current cookSpeedMultiplier */
+ int cookTime = (world != null ? world.getRecipeManager() : net.minecraft.server.MinecraftServer.getServer().getRecipeManager()).getRecipeFor(recipeType, inventory, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(AbstractCookingRecipe::getCookingTime).orElse(200); // CraftBukkit - SPIGOT-4302 // Eclipse fail
+ int cookTime = world == null ? furnace.quickCheck.getRecipeFor(furnace, world).map(AbstractCookingRecipe::getCookingTime).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, furnace, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(AbstractCookingRecipe::getCookingTime).orElse(200));
+ return (int) Math.ceil (cookTime / cookSpeedMultiplier);
}
+ // Paper end
@ -83,8 +97,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
}
if (slot == 0 && !flag) {
- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this);
+ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this, this.cookSpeedMultiplier);
- this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this);
+ this.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.level, this.recipeType, this, this.cookSpeedMultiplier); // Paper
this.cookingProgress = 0;
this.setChanged();
}

View file

@ -101,12 +101,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.playHurtSound(source);
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (!this.isRemoved() && !this.dead) {
Entity entity = source.getEntity();
Entity entity = damageSource.getEntity();
LivingEntity entityliving = this.getKillCredit();
-
+ /* // Paper - move down to make death event cancellable - this is the awardKillScore below
if (this.deathScore >= 0 && entityliving != null) {
entityliving.awardKillScore(this, this.deathScore, source);
entityliving.awardKillScore(this, this.deathScore, damageSource);
}
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
if (!this.level.isClientSide && this.hasCustomName()) {
@ -118,17 +118,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- this.getCombatTracker().recheckStatus();
+ // Paper - moved into if below
if (this.level instanceof ServerLevel) {
if (entity != null) {
- entity.killed((ServerLevel) this.level, this);
+ // Paper - move below into if for onKill
}
- this.dropAllDeathLoot(source);
- if (entity == null || entity.wasKilled((ServerLevel) this.level, this)) {
+ // Paper - move below into if for onKill
+
+ // Paper start
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(source);
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource);
+ if (deathEvent == null || !deathEvent.isCancelled()) {
+ if (this.deathScore >= 0 && entityliving != null) {
+ entityliving.awardKillScore(this, this.deathScore, source);
+ entityliving.awardKillScore(this, this.deathScore, damageSource);
+ }
+ // Paper start - clear equipment if event is not cancelled
+ if (this instanceof Mob) {
@ -149,18 +146,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ this.getCombatTracker().recheckStatus();
+ if (entity != null) {
+ entity.killed((ServerLevel) this.level, this);
+ entity.wasKilled((ServerLevel) this.level, this);
+ }
this.gameEvent(GameEvent.ENTITY_DIE);
- this.dropAllDeathLoot(damageSource);
- this.createWitherRose(entityliving);
+ } else {
+ this.dead = false;
+ this.setHealth((float) deathEvent.getReviveHealth());
+ }
}
-
- this.level.broadcastEntityEvent(this, (byte) 3);
+ // Paper end
this.createWitherRose(entityliving);
+ this.createWitherRose(entityliving);
}
+ if (this.dead) { // Paper
this.level.broadcastEntityEvent(this, (byte) 3);
+ this.level.broadcastEntityEvent(this, (byte) 3);
this.setPose(Pose.DYING);
+ } // Paper
}
@ -305,8 +307,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event // Paper - make cancellable
+ if (event.isCancelled()) return; // Paper - make cancellable
this.remove(Entity.RemovalReason.KILLED);
this.gameEvent(GameEvent.ENTITY_DIE);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java

View file

@ -10,7 +10,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
StructureFeatureManager structuremanager = world.structureFeatureManager();
StructureManager structuremanager = world.structureManager();
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
int i = pos.getY();
- BlockState iblockdata = chunk.getBlockState(pos);