--- a/net/minecraft/server/level/WorldGenRegion.java +++ b/net/minecraft/server/level/WorldGenRegion.java @@ -167,7 +167,27 @@ int k = this.center.getPos().getChessboardDistance(chunkX, chunkZ); return k < this.generatingStep.directDependencies().size(); + } + + // Paper start - if loaded util + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(int x, int z) { + return this.getChunk(x, z, ChunkStatus.FULL, false); + } + + @Override + public final BlockState getBlockStateIfLoaded(BlockPos blockposition) { + ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4); + return chunk == null ? null : chunk.getBlockState(blockposition); + } + + @Override + public final FluidState getFluidIfLoaded(BlockPos blockposition) { + ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4); + return chunk == null ? null : chunk.getFluidState(blockposition); } + // Paper end @Override public BlockState getBlockState(BlockPos pos) { @@ -217,7 +237,8 @@ if (iblockdata.isAir()) { return false; } else { - if (drop) { + if (drop) LOGGER.warn("Potential async entity add during worldgen", new Throwable()); // Paper - Fix async entity add due to fungus trees; log when this happens + if (false) { // CraftBukkit - SPIGOT-6833: Do not drop during world generation BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; Block.dropResources(iblockdata, this.level, pos, tileentity, breakingEntity, ItemStack.EMPTY); @@ -264,6 +285,7 @@ } } + private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls @Override public boolean ensureCanWrite(BlockPos pos) { int i = SectionPos.blockToSectionCoord(pos.getX()); @@ -283,7 +305,15 @@ return true; } else { + // Paper start - Buffer OOB setBlock calls + if (!hasSetFarWarned) { Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); + hasSetFarWarned = true; + if (this.getServer() != null && this.getServer().isDebugging()) { + io.papermc.paper.util.TraceUtil.dumpTraceForThread("far setBlock call"); + } + } + // Paper end - Buffer OOB setBlock calls return false; } } @@ -294,7 +324,7 @@ 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); @@ -310,6 +340,17 @@ 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()); @@ -336,6 +377,13 @@ @Override public boolean addFreshEntity(Entity entity) { + // CraftBukkit start + return this.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + @Override + public boolean addFreshEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { + // CraftBukkit end int i = SectionPos.blockToSectionCoord(entity.getBlockX()); int j = SectionPos.blockToSectionCoord(entity.getBlockZ());