Code/net/minecraft/server/level/WorldGenRegion.java

472 lines
17 KiB
Java
Raw Permalink Normal View History

2025-07-01 06:20:03 +00:00
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 javax.annotation.Nullable;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.Util;
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.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StaticCache2D;
import net.minecraft.world.DifficultyInstance;
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.slf4j.Logger;
public class WorldGenRegion implements WorldGenLevel {
private static final Logger LOGGER = LogUtils.getLogger();
private final StaticCache2D<GenerationChunkHolder> 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<Block> blockTicks = new WorldGenTickAccess<>(p_390154_ -> this.getChunk(p_390154_).getBlockTicks());
private final WorldGenTickAccess<Fluid> fluidTicks = new WorldGenTickAccess<>(p_390153_ -> this.getChunk(p_390153_).getFluidTicks());
private final BiomeManager biomeManager;
private final ChunkStep generatingStep;
@Nullable
private Supplier<String> currentlyGenerating;
private final AtomicLong subTickCount = new AtomicLong();
private static final ResourceLocation WORLDGEN_REGION_RANDOM = ResourceLocation.withDefaultNamespace("worldgen_region_random");
public WorldGenRegion(ServerLevel p_143484_, StaticCache2D<GenerationChunkHolder> p_345015_, ChunkStep p_344631_, ChunkAccess p_342729_) {
this.generatingStep = p_344631_;
this.cache = p_345015_;
this.center = p_342729_;
this.level = p_143484_;
this.seed = p_143484_.getSeed();
this.levelData = p_143484_.getLevelData();
this.random = p_143484_.getChunkSource().randomState().getOrCreateRandomFactory(WORLDGEN_REGION_RANDOM).at(this.center.getPos().getWorldPosition());
this.dimensionType = p_143484_.dimensionType();
this.biomeManager = new BiomeManager(this, BiomeManager.obfuscateSeed(this.seed));
}
public boolean isOldChunkAround(ChunkPos p_215160_, int p_215161_) {
return this.level.getChunkSource().chunkMap.isOldChunkAround(p_215160_, p_215161_);
}
public ChunkPos getCenter() {
return this.center.getPos();
}
@Override
public void setCurrentlyGenerating(@Nullable Supplier<String> p_143498_) {
this.currentlyGenerating = p_143498_;
}
@Override
public ChunkAccess getChunk(int p_9507_, int p_9508_) {
return this.getChunk(p_9507_, p_9508_, ChunkStatus.EMPTY);
}
@Nullable
@Override
public ChunkAccess getChunk(int p_9514_, int p_9515_, ChunkStatus p_332757_, boolean p_9517_) {
int i = this.center.getPos().getChessboardDistance(p_9514_, p_9515_);
ChunkStatus chunkstatus = i >= this.generatingStep.directDependencies().size() ? null : this.generatingStep.directDependencies().get(i);
GenerationChunkHolder generationchunkholder;
if (chunkstatus != null) {
generationchunkholder = this.cache.get(p_9514_, p_9515_);
if (p_332757_.isOrBefore(chunkstatus)) {
ChunkAccess chunkaccess = generationchunkholder.getChunkIfPresentUnchecked(chunkstatus);
if (chunkaccess != null) {
return chunkaccess;
}
}
} else {
generationchunkholder = null;
}
CrashReport crashreport = CrashReport.forThrowable(
new IllegalStateException("Requested chunk unavailable during world generation"), "Exception generating new chunk"
);
CrashReportCategory crashreportcategory = crashreport.addCategory("Chunk request details");
crashreportcategory.setDetail("Requested chunk", String.format(Locale.ROOT, "%d, %d", p_9514_, p_9515_));
crashreportcategory.setDetail("Generating status", () -> this.generatingStep.targetStatus().getName());
crashreportcategory.setDetail("Requested status", p_332757_::getName);
crashreportcategory.setDetail(
"Actual status", () -> generationchunkholder == null ? "[out of cache bounds]" : generationchunkholder.getPersistedStatus().getName()
);
crashreportcategory.setDetail("Maximum allowed status", () -> chunkstatus == null ? "null" : chunkstatus.getName());
crashreportcategory.setDetail("Dependencies", this.generatingStep.directDependencies()::toString);
crashreportcategory.setDetail("Requested distance", i);
crashreportcategory.setDetail("Generating chunk", this.center.getPos()::toString);
throw new ReportedException(crashreport);
}
@Override
public boolean hasChunk(int p_9574_, int p_9575_) {
int i = this.center.getPos().getChessboardDistance(p_9574_, p_9575_);
return i < this.generatingStep.directDependencies().size();
}
@Override
public BlockState getBlockState(BlockPos p_9587_) {
return this.getChunk(SectionPos.blockToSectionCoord(p_9587_.getX()), SectionPos.blockToSectionCoord(p_9587_.getZ())).getBlockState(p_9587_);
}
@Override
public FluidState getFluidState(BlockPos p_9577_) {
return this.getChunk(p_9577_).getFluidState(p_9577_);
}
@Nullable
@Override
public Player getNearestPlayer(double p_9501_, double p_9502_, double p_9503_, double p_9504_, Predicate<Entity> p_9505_) {
return null;
}
@Override
public int getSkyDarken() {
return 0;
}
@Override
public BiomeManager getBiomeManager() {
return this.biomeManager;
}
@Override
public Holder<Biome> getUncachedNoiseBiome(int p_203787_, int p_203788_, int p_203789_) {
return this.level.getUncachedNoiseBiome(p_203787_, p_203788_, p_203789_);
}
@Override
public float getShade(Direction p_9555_, boolean p_9556_) {
return 1.0F;
}
@Override
public LevelLightEngine getLightEngine() {
return this.level.getLightEngine();
}
@Override
public boolean destroyBlock(BlockPos p_9550_, boolean p_9551_, @Nullable Entity p_9552_, int p_9553_) {
BlockState blockstate = this.getBlockState(p_9550_);
if (blockstate.isAir()) {
return false;
} else {
if (p_9551_) {
BlockEntity blockentity = blockstate.hasBlockEntity() ? this.getBlockEntity(p_9550_) : null;
Block.dropResources(blockstate, this.level, p_9550_, blockentity, p_9552_, ItemStack.EMPTY);
}
return this.setBlock(p_9550_, Blocks.AIR.defaultBlockState(), 3, p_9553_);
}
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos p_9582_) {
ChunkAccess chunkaccess = this.getChunk(p_9582_);
BlockEntity blockentity = chunkaccess.getBlockEntity(p_9582_);
if (blockentity != null) {
return blockentity;
} else {
CompoundTag compoundtag = chunkaccess.getBlockEntityNbt(p_9582_);
BlockState blockstate = chunkaccess.getBlockState(p_9582_);
if (compoundtag != null) {
if ("DUMMY".equals(compoundtag.getStringOr("id", ""))) {
if (!blockstate.hasBlockEntity()) {
return null;
}
blockentity = ((EntityBlock)blockstate.getBlock()).newBlockEntity(p_9582_, blockstate);
} else {
blockentity = BlockEntity.loadStatic(p_9582_, blockstate, compoundtag, this.level.registryAccess());
}
if (blockentity != null) {
chunkaccess.setBlockEntity(blockentity);
return blockentity;
}
}
if (blockstate.hasBlockEntity()) {
LOGGER.warn("Tried to access a block entity before it was created. {}", p_9582_);
}
return null;
}
}
@Override
public boolean ensureCanWrite(BlockPos p_181031_) {
int i = SectionPos.blockToSectionCoord(p_181031_.getX());
int j = SectionPos.blockToSectionCoord(p_181031_.getZ());
ChunkPos chunkpos = this.getCenter();
int k = Math.abs(chunkpos.x - i);
int l = Math.abs(chunkpos.z - j);
if (k <= this.generatingStep.blockStateWriteRadius() && l <= this.generatingStep.blockStateWriteRadius()) {
if (this.center.isUpgrading()) {
LevelHeightAccessor levelheightaccessor = this.center.getHeightAccessorForGeneration();
if (levelheightaccessor.isOutsideBuildHeight(p_181031_.getY())) {
return false;
}
}
return true;
} else {
Util.logAndPauseIfInIde(
"Detected setBlock in a far chunk ["
+ i
+ ", "
+ j
+ "], pos: "
+ p_181031_
+ ", status: "
+ this.generatingStep.targetStatus()
+ (this.currentlyGenerating == null ? "" : ", currently generating: " + this.currentlyGenerating.get())
);
return false;
}
}
@Override
public boolean setBlock(BlockPos p_9539_, BlockState p_9540_, int p_9541_, int p_9542_) {
if (!this.ensureCanWrite(p_9539_)) {
return false;
} else {
ChunkAccess chunkaccess = this.getChunk(p_9539_);
BlockState blockstate = chunkaccess.setBlockState(p_9539_, p_9540_, p_9541_);
if (blockstate != null) {
this.level.updatePOIOnBlockStateChange(p_9539_, blockstate, p_9540_);
}
if (p_9540_.hasBlockEntity()) {
if (chunkaccess.getPersistedStatus().getChunkType() == ChunkType.LEVELCHUNK) {
BlockEntity blockentity = ((EntityBlock)p_9540_.getBlock()).newBlockEntity(p_9539_, p_9540_);
if (blockentity != null) {
chunkaccess.setBlockEntity(blockentity);
} else {
chunkaccess.removeBlockEntity(p_9539_);
}
} else {
CompoundTag compoundtag = new CompoundTag();
compoundtag.putInt("x", p_9539_.getX());
compoundtag.putInt("y", p_9539_.getY());
compoundtag.putInt("z", p_9539_.getZ());
compoundtag.putString("id", "DUMMY");
chunkaccess.setBlockEntityNbt(compoundtag);
}
} else if (blockstate != null && blockstate.hasBlockEntity()) {
chunkaccess.removeBlockEntity(p_9539_);
}
if (p_9540_.hasPostProcess(this, p_9539_) && (p_9541_ & 16) == 0) {
this.markPosForPostprocessing(p_9539_);
}
return true;
}
}
private void markPosForPostprocessing(BlockPos p_9592_) {
this.getChunk(p_9592_).markPosForPostprocessing(p_9592_);
}
@Override
public boolean addFreshEntity(Entity p_9580_) {
int i = SectionPos.blockToSectionCoord(p_9580_.getBlockX());
int j = SectionPos.blockToSectionCoord(p_9580_.getBlockZ());
this.getChunk(i, j).addEntity(p_9580_);
return true;
}
@Override
public boolean removeBlock(BlockPos p_9547_, boolean p_9548_) {
return this.setBlock(p_9547_, Blocks.AIR.defaultBlockState(), 3);
}
@Override
public WorldBorder getWorldBorder() {
return this.level.getWorldBorder();
}
@Override
public boolean isClientSide() {
return false;
}
@Deprecated
@Override
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 p_9585_) {
if (!this.hasChunk(SectionPos.blockToSectionCoord(p_9585_.getX()), SectionPos.blockToSectionCoord(p_9585_.getZ()))) {
throw new RuntimeException("We are asking a region for a chunk out of bound");
} else {
return new DifficultyInstance(this.level.getDifficulty(), this.level.getDayTime(), 0L, this.level.getMoonBrightness());
}
}
@Nullable
@Override
public MinecraftServer getServer() {
return this.level.getServer();
}
@Override
public ChunkSource getChunkSource() {
return this.level.getChunkSource();
}
@Override
public long getSeed() {
return this.seed;
}
@Override
public LevelTickAccess<Block> getBlockTicks() {
return this.blockTicks;
}
@Override
public LevelTickAccess<Fluid> 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 p_9535_, int p_9536_, int p_9537_) {
return this.getChunk(SectionPos.blockToSectionCoord(p_9536_), SectionPos.blockToSectionCoord(p_9537_)).getHeight(p_9535_, p_9536_ & 15, p_9537_ & 15) + 1;
}
@Override
public void playSound(@Nullable Entity p_397488_, BlockPos p_9529_, SoundEvent p_9530_, SoundSource p_9531_, float p_9532_, float p_9533_) {
}
@Override
public void addParticle(ParticleOptions p_9561_, double p_9562_, double p_9563_, double p_9564_, double p_9565_, double p_9566_, double p_9567_) {
}
@Override
public void levelEvent(@Nullable Entity p_396946_, int p_9524_, BlockPos p_9525_, int p_9526_) {
}
@Override
public void gameEvent(Holder<GameEvent> p_332620_, Vec3 p_215164_, GameEvent.Context p_215165_) {
}
@Override
public DimensionType dimensionType() {
return this.dimensionType;
}
@Override
public boolean isStateAtPosition(BlockPos p_9544_, Predicate<BlockState> p_9545_) {
return p_9545_.test(this.getBlockState(p_9544_));
}
@Override
public boolean isFluidAtPosition(BlockPos p_143500_, Predicate<FluidState> p_143501_) {
return p_143501_.test(this.getFluidState(p_143500_));
}
@Override
public <T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> p_143494_, AABB p_143495_, Predicate<? super T> p_143496_) {
return Collections.emptyList();
}
@Override
public List<Entity> getEntities(@Nullable Entity p_9519_, AABB p_9520_, @Nullable Predicate<? super Entity> p_9521_) {
return Collections.emptyList();
}
@Override
public List<Player> 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();
}
}