mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-21 18:15:54 +01:00
8c5b837e05
Firstly, the old methods all routed to the CompletableFuture method. However, the CF method could not guarantee that if the caller was off-main that the future would be "completed" on-main. Since the callback methods used the CF one, this meant that the callback methods did not guarantee that the callbacks were to be called on the main thread. Now, all methods route to getChunkAtAsync(x, z, gen, urgent, cb) so that the methods with the callback are guaranteed to invoke the callback on the main thread. The CF behavior remains unchanged; it may still appear to complete on main if invoked off-main. Secondly, remove the scheduleOnMain invocation in the async chunk completion. This unnecessarily delays the callback by 1 tick. Thirdly, add getChunksAtAsync(minX, minZ, maxX, maxZ, ...) which will load chunks within an area. This method is provided as a helper as keeping all chunks loaded within an area can be complicated to implement for plugins (due to the lacking ticket API), and is already implemented internally anyways. Fourthly, remove the ticket addition that occured with getChunkAt and getChunkAtAsync. The ticket addition may delay the unloading of the chunk unnecessarily. It also fixes a very rare timing bug where the future/callback would be completed after the chunk unloads.
60 lines
4.2 KiB
Diff
60 lines
4.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Pierpaolo Coletta <p.coletta@glyart.com>
|
|
Date: Sat, 30 Mar 2024 21:06:10 +0100
|
|
Subject: [PATCH] Fix creation of invalid block entity during world generation
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
index 2e72e92762877b28dd908711671e1dfb933de9b0..b7d29389a357f142237cecd75f8ca91cf1eb6b5b 100644
|
|
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
|
@@ -324,7 +324,7 @@ public class WorldGenRegion implements WorldGenLevel {
|
|
return false;
|
|
} else {
|
|
ChunkAccess ichunkaccess = this.getChunk(pos);
|
|
- BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false);
|
|
+ BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); final BlockState previousBlockState = iblockdata1; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper
|
|
|
|
if (iblockdata1 != null) {
|
|
this.level.onBlockStateChange(pos, iblockdata1, state);
|
|
@@ -340,6 +340,17 @@ public class WorldGenRegion implements WorldGenLevel {
|
|
ichunkaccess.removeBlockEntity(pos);
|
|
}
|
|
} else {
|
|
+ // Paper start - Clear block entity before setting up a DUMMY block entity
|
|
+ // The concept of removing a block entity when the block itself changes is generally lifted
|
|
+ // from LevelChunk#setBlockState.
|
|
+ // It is however to note that this may only run if the block actually changes.
|
|
+ // Otherwise a chest block entity generated by a structure template that is later "updated" to
|
|
+ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750)
|
|
+ // This logic is *also* found in LevelChunk#setBlockState.
|
|
+ if (previousBlockState != null && !java.util.Objects.equals(previousBlockState.getBlock(), state.getBlock())) {
|
|
+ ichunkaccess.removeBlockEntity(pos);
|
|
+ }
|
|
+ // Paper end - Clear block entity before setting up a DUMMY block entity
|
|
CompoundTag nbttagcompound = new CompoundTag();
|
|
|
|
nbttagcompound.putInt("x", pos.getX());
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
index d4bd4cbc5c4773659662a6d7a09b21a99463c1fb..7a794bb0587ce55b067c67dd17ab5be6a4773030 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
@@ -991,9 +991,14 @@ public class LevelChunk extends ChunkAccess {
|
|
if (this.blockEntity.getType().isValid(iblockdata)) {
|
|
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity);
|
|
this.loggedInvalidBlockState = false;
|
|
- } else if (!this.loggedInvalidBlockState) {
|
|
- this.loggedInvalidBlockState = true;
|
|
- LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
|
+ // Paper start - Remove the Block Entity if it's invalid
|
|
+ } else {
|
|
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
|
+ if (!this.loggedInvalidBlockState) {
|
|
+ this.loggedInvalidBlockState = true;
|
|
+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
|
+ }
|
|
+ // Paper end - Remove the Block Entity if it's invalid
|
|
}
|
|
|
|
gameprofilerfiller.pop();
|