--- a/net/minecraft/server/level/WorldGenRegion.java +++ b/net/minecraft/server/level/WorldGenRegion.java @@ -151,6 +_,26 @@ return chessboardDistance < 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) { return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos); @@ -198,7 +_,8 @@ if (blockState.isAir()) { return false; } else { - if (dropBlock) { + if (dropBlock) 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 blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; Block.dropResources(blockState, this.level, pos, blockEntity, entity, ItemStack.EMPTY); } @@ -242,6 +_,7 @@ } } + private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls @Override public boolean ensureCanWrite(BlockPos pos) { int sectionPosX = SectionPos.blockToSectionCoord(pos.getX()); @@ -259,6 +_,8 @@ return true; } else { + // Paper start - Buffer OOB setBlock calls + if (!hasSetFarWarned) { Util.logAndPauseIfInIde( "Detected setBlock in a far chunk [" + sectionPosX @@ -270,6 +_,12 @@ + this.generatingStep.targetStatus() + (this.currentlyGenerating == null ? "" : ", currently generating: " + 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; } } @@ -280,7 +_,7 @@ return false; } else { ChunkAccess chunk = this.getChunk(pos); - BlockState blockState = chunk.setBlockState(pos, state, false); + BlockState blockState = chunk.setBlockState(pos, state, false); final BlockState previousBlockState = blockState; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper if (blockState != null) { this.level.onBlockStateChange(pos, blockState, state); } @@ -294,6 +_,17 @@ chunk.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())) { + chunk.removeBlockEntity(pos); + } + // Paper end - Clear block entity before setting up a DUMMY block entity CompoundTag compoundTag = new CompoundTag(); compoundTag.putInt("x", pos.getX()); compoundTag.putInt("y", pos.getY()); @@ -319,6 +_,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 sectionPosX = SectionPos.blockToSectionCoord(entity.getBlockX()); int sectionPosZ = SectionPos.blockToSectionCoord(entity.getBlockZ()); this.getChunk(sectionPosX, sectionPosZ).addEntity(entity);