/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.server.level; import com.mojang.logging.LogUtils; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; import java.util.function.Supplier; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.SectionPos; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.util.StaticCache2D; import net.minecraft.util.Util; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.attribute.EnvironmentAttributeReader; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.status.ChunkType; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.ticks.LevelTickAccess; import net.minecraft.world.ticks.WorldGenTickAccess; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class WorldGenRegion implements WorldGenLevel { private static final Logger LOGGER = LogUtils.getLogger(); private final StaticCache2D cache; private final ChunkAccess center; private final ServerLevel level; private final long seed; private final LevelData levelData; private final RandomSource random; private final DimensionType dimensionType; private final WorldGenTickAccess blockTicks = new WorldGenTickAccess(pos -> this.getChunk((BlockPos)pos).getBlockTicks()); private final WorldGenTickAccess fluidTicks = new WorldGenTickAccess(pos -> this.getChunk((BlockPos)pos).getFluidTicks()); private final BiomeManager biomeManager; private final ChunkStep generatingStep; private @Nullable Supplier currentlyGenerating; private final AtomicLong subTickCount = new AtomicLong(); private static final Identifier WORLDGEN_REGION_RANDOM = Identifier.withDefaultNamespace("worldgen_region_random"); public WorldGenRegion(ServerLevel level, StaticCache2D cache, ChunkStep generatingStep, ChunkAccess center) { this.generatingStep = generatingStep; this.cache = cache; this.center = center; this.level = level; this.seed = level.getSeed(); this.levelData = level.getLevelData(); this.random = level.getChunkSource().randomState().getOrCreateRandomFactory(WORLDGEN_REGION_RANDOM).at(this.center.getPos().getWorldPosition()); this.dimensionType = level.dimensionType(); this.biomeManager = new BiomeManager(this, BiomeManager.obfuscateSeed(this.seed)); } public boolean isOldChunkAround(ChunkPos pos, int range) { return this.level.getChunkSource().chunkMap.isOldChunkAround(pos, range); } public ChunkPos getCenter() { return this.center.getPos(); } @Override public void setCurrentlyGenerating(@Nullable Supplier currentlyGenerating) { this.currentlyGenerating = currentlyGenerating; } @Override public ChunkAccess getChunk(int chunkX, int chunkZ) { return this.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY); } @Override public @Nullable ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus targetStatus, boolean loadOrGenerate) { GenerationChunkHolder chunkHolder; ChunkStatus maxAllowedStatus; int distance = this.center.getPos().getChessboardDistance(chunkX, chunkZ); ChunkStatus chunkStatus = maxAllowedStatus = distance >= this.generatingStep.directDependencies().size() ? null : this.generatingStep.directDependencies().get(distance); if (maxAllowedStatus != null) { ChunkAccess chunk; chunkHolder = this.cache.get(chunkX, chunkZ); if (targetStatus.isOrBefore(maxAllowedStatus) && (chunk = chunkHolder.getChunkIfPresentUnchecked(maxAllowedStatus)) != null) { return chunk; } } else { chunkHolder = null; } CrashReport report = CrashReport.forThrowable(new IllegalStateException("Requested chunk unavailable during world generation"), "Exception generating new chunk"); CrashReportCategory category = report.addCategory("Chunk request details"); category.setDetail("Requested chunk", String.format(Locale.ROOT, "%d, %d", chunkX, chunkZ)); category.setDetail("Generating status", () -> this.generatingStep.targetStatus().getName()); category.setDetail("Requested status", targetStatus::getName); category.setDetail("Actual status", () -> chunkHolder == null ? "[out of cache bounds]" : chunkHolder.getPersistedStatus().getName()); category.setDetail("Maximum allowed status", () -> maxAllowedStatus == null ? "null" : maxAllowedStatus.getName()); category.setDetail("Dependencies", this.generatingStep.directDependencies()::toString); category.setDetail("Requested distance", distance); category.setDetail("Generating chunk", this.center.getPos()::toString); throw new ReportedException(report); } @Override public boolean hasChunk(int chunkX, int chunkZ) { int distance = this.center.getPos().getChessboardDistance(chunkX, chunkZ); return distance < this.generatingStep.directDependencies().size(); } @Override public BlockState getBlockState(BlockPos pos) { return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos); } @Override public FluidState getFluidState(BlockPos pos) { return this.getChunk(pos).getFluidState(pos); } @Override public @Nullable Player getNearestPlayer(double x, double y, double z, double maxDist, @Nullable Predicate predicate) { return null; } @Override public int getSkyDarken() { return 0; } @Override public BiomeManager getBiomeManager() { return this.biomeManager; } @Override public Holder getUncachedNoiseBiome(int quartX, int quartY, int quartZ) { return this.level.getUncachedNoiseBiome(quartX, quartY, quartZ); } @Override public float getShade(Direction direction, boolean shade) { return 1.0f; } @Override public LevelLightEngine getLightEngine() { return this.level.getLightEngine(); } @Override public boolean destroyBlock(BlockPos pos, boolean dropResources, @Nullable Entity breaker, int updateLimit) { BlockState blockState = this.getBlockState(pos); if (blockState.isAir()) { return false; } if (dropResources) { BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; Block.dropResources(blockState, this.level, pos, blockEntity, breaker, ItemStack.EMPTY); } return this.setBlock(pos, Blocks.AIR.defaultBlockState(), 3, updateLimit); } @Override public @Nullable BlockEntity getBlockEntity(BlockPos pos) { ChunkAccess chunk = this.getChunk(pos); BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { return blockEntity; } CompoundTag tag = chunk.getBlockEntityNbt(pos); BlockState state = chunk.getBlockState(pos); if (tag != null) { if ("DUMMY".equals(tag.getStringOr("id", ""))) { if (!state.hasBlockEntity()) { return null; } blockEntity = ((EntityBlock)((Object)state.getBlock())).newBlockEntity(pos, state); } else { blockEntity = BlockEntity.loadStatic(pos, state, tag, this.level.registryAccess()); } if (blockEntity != null) { chunk.setBlockEntity(blockEntity); return blockEntity; } } if (state.hasBlockEntity()) { LOGGER.warn("Tried to access a block entity before it was created. {}", (Object)pos); } return null; } @Override public boolean ensureCanWrite(BlockPos pos) { LevelHeightAccessor levelHeightAccessor; int chunkX = SectionPos.blockToSectionCoord(pos.getX()); int chunkZ = SectionPos.blockToSectionCoord(pos.getZ()); ChunkPos centerPos = this.getCenter(); int distanceX = Math.abs(centerPos.x - chunkX); int distanceZ = Math.abs(centerPos.z - chunkZ); if (distanceX > this.generatingStep.blockStateWriteRadius() || distanceZ > this.generatingStep.blockStateWriteRadius()) { Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + chunkX + ", " + chunkZ + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (String)(this.currentlyGenerating == null ? "" : ", currently generating: " + this.currentlyGenerating.get())); return false; } return !this.center.isUpgrading() || !(levelHeightAccessor = this.center.getHeightAccessorForGeneration()).isOutsideBuildHeight(pos.getY()); } @Override public boolean setBlock(BlockPos pos, BlockState blockState, int updateFlags, int updateLimit) { if (!this.ensureCanWrite(pos)) { return false; } ChunkAccess chunk = this.getChunk(pos); BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); if (oldState != null) { this.level.updatePOIOnBlockStateChange(pos, oldState, blockState); } if (blockState.hasBlockEntity()) { if (chunk.getPersistedStatus().getChunkType() == ChunkType.LEVELCHUNK) { BlockEntity blockEntity = ((EntityBlock)((Object)blockState.getBlock())).newBlockEntity(pos, blockState); if (blockEntity != null) { chunk.setBlockEntity(blockEntity); } else { chunk.removeBlockEntity(pos); } } else { CompoundTag tag = new CompoundTag(); tag.putInt("x", pos.getX()); tag.putInt("y", pos.getY()); tag.putInt("z", pos.getZ()); tag.putString("id", "DUMMY"); chunk.setBlockEntityNbt(tag); } } else if (oldState != null && oldState.hasBlockEntity()) { chunk.removeBlockEntity(pos); } if (blockState.hasPostProcess(this, pos) && (updateFlags & 0x10) == 0) { this.markPosForPostprocessing(pos); } return true; } private void markPosForPostprocessing(BlockPos blockPos) { this.getChunk(blockPos).markPosForPostprocessing(blockPos); } @Override public boolean addFreshEntity(Entity entity) { int xc = SectionPos.blockToSectionCoord(entity.getBlockX()); int zc = SectionPos.blockToSectionCoord(entity.getBlockZ()); this.getChunk(xc, zc).addEntity(entity); return true; } @Override public boolean removeBlock(BlockPos pos, boolean movedByPiston) { return this.setBlock(pos, Blocks.AIR.defaultBlockState(), 3); } @Override public WorldBorder getWorldBorder() { return this.level.getWorldBorder(); } @Override public boolean isClientSide() { return false; } @Override @Deprecated public ServerLevel getLevel() { return this.level; } @Override public RegistryAccess registryAccess() { return this.level.registryAccess(); } @Override public FeatureFlagSet enabledFeatures() { return this.level.enabledFeatures(); } @Override public LevelData getLevelData() { return this.levelData; } @Override public DifficultyInstance getCurrentDifficultyAt(BlockPos pos) { if (!this.hasChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()))) { throw new RuntimeException("We are asking a region for a chunk out of bound"); } return new DifficultyInstance(this.level.getDifficulty(), this.level.getDayTime(), 0L, this.level.getMoonBrightness(pos)); } @Override public @Nullable MinecraftServer getServer() { return this.level.getServer(); } @Override public ChunkSource getChunkSource() { return this.level.getChunkSource(); } @Override public long getSeed() { return this.seed; } @Override public LevelTickAccess getBlockTicks() { return this.blockTicks; } @Override public LevelTickAccess getFluidTicks() { return this.fluidTicks; } @Override public int getSeaLevel() { return this.level.getSeaLevel(); } @Override public RandomSource getRandom() { return this.random; } @Override public int getHeight(Heightmap.Types type, int x, int z) { return this.getChunk(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z)).getHeight(type, x & 0xF, z & 0xF) + 1; } @Override public void playSound(@Nullable Entity except, BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch) { } @Override public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) { } @Override public void levelEvent(@Nullable Entity source, int type, BlockPos pos, int data) { } @Override public void gameEvent(Holder gameEvent, Vec3 position, GameEvent.Context context) { } @Override public DimensionType dimensionType() { return this.dimensionType; } @Override public boolean isStateAtPosition(BlockPos pos, Predicate predicate) { return predicate.test(this.getBlockState(pos)); } @Override public boolean isFluidAtPosition(BlockPos pos, Predicate predicate) { return predicate.test(this.getFluidState(pos)); } @Override public List getEntities(EntityTypeTest type, AABB bb, Predicate selector) { return Collections.emptyList(); } @Override public List getEntities(@Nullable Entity except, AABB bb, @Nullable Predicate selector) { return Collections.emptyList(); } public List players() { return Collections.emptyList(); } @Override public int getMinY() { return this.level.getMinY(); } @Override public int getHeight() { return this.level.getHeight(); } @Override public long nextSubTickCount() { return this.subTickCount.getAndIncrement(); } @Override public EnvironmentAttributeReader environmentAttributes() { return EnvironmentAttributeReader.EMPTY; } }