minecraft-src/net/minecraft/world/level/chunk/ProtoChunk.java
2025-07-04 03:45:38 +03:00

331 lines
10 KiB
Java

package net.minecraft.world.level.chunk;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.shorts.ShortList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.levelgen.BelowZeroRetrogen;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.lighting.LightEngine;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.ticks.LevelChunkTicks;
import net.minecraft.world.ticks.ProtoChunkTicks;
import net.minecraft.world.ticks.TickContainerAccess;
import org.jetbrains.annotations.Nullable;
public class ProtoChunk extends ChunkAccess {
@Nullable
private volatile LevelLightEngine lightEngine;
private volatile ChunkStatus status = ChunkStatus.EMPTY;
private final List<CompoundTag> entities = Lists.<CompoundTag>newArrayList();
@Nullable
private CarvingMask carvingMask;
@Nullable
private BelowZeroRetrogen belowZeroRetrogen;
private final ProtoChunkTicks<Block> blockTicks;
private final ProtoChunkTicks<Fluid> fluidTicks;
public ProtoChunk(
ChunkPos chunkPos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor, Registry<Biome> biomeRegistry, @Nullable BlendingData blendingData
) {
this(chunkPos, upgradeData, null, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomeRegistry, blendingData);
}
public ProtoChunk(
ChunkPos chunkPos,
UpgradeData upgradeData,
@Nullable LevelChunkSection[] sections,
ProtoChunkTicks<Block> blockTicks,
ProtoChunkTicks<Fluid> liquidTicks,
LevelHeightAccessor levelHeightAccessor,
Registry<Biome> biomeRegistry,
@Nullable BlendingData blendingData
) {
super(chunkPos, upgradeData, levelHeightAccessor, biomeRegistry, 0L, sections, blendingData);
this.blockTicks = blockTicks;
this.fluidTicks = liquidTicks;
}
@Override
public TickContainerAccess<Block> getBlockTicks() {
return this.blockTicks;
}
@Override
public TickContainerAccess<Fluid> getFluidTicks() {
return this.fluidTicks;
}
@Override
public ChunkAccess.PackedTicks getTicksForSerialization(long gametime) {
return new ChunkAccess.PackedTicks(this.blockTicks.pack(gametime), this.fluidTicks.pack(gametime));
}
@Override
public BlockState getBlockState(BlockPos pos) {
int i = pos.getY();
if (this.isOutsideBuildHeight(i)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
LevelChunkSection levelChunkSection = this.getSection(this.getSectionIndex(i));
return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(pos.getX() & 15, i & 15, pos.getZ() & 15);
}
}
@Override
public FluidState getFluidState(BlockPos pos) {
int i = pos.getY();
if (this.isOutsideBuildHeight(i)) {
return Fluids.EMPTY.defaultFluidState();
} else {
LevelChunkSection levelChunkSection = this.getSection(this.getSectionIndex(i));
return levelChunkSection.hasOnlyAir() ? Fluids.EMPTY.defaultFluidState() : levelChunkSection.getFluidState(pos.getX() & 15, i & 15, pos.getZ() & 15);
}
}
@Nullable
@Override
public BlockState setBlockState(BlockPos pos, BlockState state, int flags) {
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
if (this.isOutsideBuildHeight(j)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
int l = this.getSectionIndex(j);
LevelChunkSection levelChunkSection = this.getSection(l);
boolean bl = levelChunkSection.hasOnlyAir();
if (bl && state.is(Blocks.AIR)) {
return state;
} else {
int m = SectionPos.sectionRelative(i);
int n = SectionPos.sectionRelative(j);
int o = SectionPos.sectionRelative(k);
BlockState blockState = levelChunkSection.setBlockState(m, n, o, state);
if (this.status.isOrAfter(ChunkStatus.INITIALIZE_LIGHT)) {
boolean bl2 = levelChunkSection.hasOnlyAir();
if (bl2 != bl) {
this.lightEngine.updateSectionStatus(pos, bl2);
}
if (LightEngine.hasDifferentLightProperties(blockState, state)) {
this.skyLightSources.update(this, m, j, o);
this.lightEngine.checkBlock(pos);
}
}
EnumSet<Heightmap.Types> enumSet = this.getPersistedStatus().heightmapsAfter();
EnumSet<Heightmap.Types> enumSet2 = null;
for (Heightmap.Types types : enumSet) {
Heightmap heightmap = (Heightmap)this.heightmaps.get(types);
if (heightmap == null) {
if (enumSet2 == null) {
enumSet2 = EnumSet.noneOf(Heightmap.Types.class);
}
enumSet2.add(types);
}
}
if (enumSet2 != null) {
Heightmap.primeHeightmaps(this, enumSet2);
}
for (Heightmap.Types typesx : enumSet) {
((Heightmap)this.heightmaps.get(typesx)).update(m, j, o, state);
}
return blockState;
}
}
}
@Override
public void setBlockEntity(BlockEntity blockEntity) {
this.pendingBlockEntities.remove(blockEntity.getBlockPos());
this.blockEntities.put(blockEntity.getBlockPos(), blockEntity);
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
return (BlockEntity)this.blockEntities.get(pos);
}
public Map<BlockPos, BlockEntity> getBlockEntities() {
return this.blockEntities;
}
public void addEntity(CompoundTag tag) {
this.entities.add(tag);
}
@Override
public void addEntity(Entity entity) {
if (!entity.isPassenger()) {
CompoundTag compoundTag = new CompoundTag();
entity.save(compoundTag);
this.addEntity(compoundTag);
}
}
@Override
public void setStartForStructure(Structure structure, StructureStart structureStart) {
BelowZeroRetrogen belowZeroRetrogen = this.getBelowZeroRetrogen();
if (belowZeroRetrogen != null && structureStart.isValid()) {
BoundingBox boundingBox = structureStart.getBoundingBox();
LevelHeightAccessor levelHeightAccessor = this.getHeightAccessorForGeneration();
if (boundingBox.minY() < levelHeightAccessor.getMinY() || boundingBox.maxY() > levelHeightAccessor.getMaxY()) {
return;
}
}
super.setStartForStructure(structure, structureStart);
}
public List<CompoundTag> getEntities() {
return this.entities;
}
@Override
public ChunkStatus getPersistedStatus() {
return this.status;
}
public void setPersistedStatus(ChunkStatus status) {
this.status = status;
if (this.belowZeroRetrogen != null && status.isOrAfter(this.belowZeroRetrogen.targetStatus())) {
this.setBelowZeroRetrogen(null);
}
this.markUnsaved();
}
@Override
public Holder<Biome> getNoiseBiome(int i, int j, int k) {
if (this.getHighestGeneratedStatus().isOrAfter(ChunkStatus.BIOMES)) {
return super.getNoiseBiome(i, j, k);
} else {
throw new IllegalStateException("Asking for biomes before we have biomes");
}
}
public static short packOffsetCoordinates(BlockPos pos) {
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
int l = i & 15;
int m = j & 15;
int n = k & 15;
return (short)(l | m << 4 | n << 8);
}
public static BlockPos unpackOffsetCoordinates(short packedPos, int yOffset, ChunkPos chunkPos) {
int i = SectionPos.sectionToBlockCoord(chunkPos.x, packedPos & 15);
int j = SectionPos.sectionToBlockCoord(yOffset, packedPos >>> 4 & 15);
int k = SectionPos.sectionToBlockCoord(chunkPos.z, packedPos >>> 8 & 15);
return new BlockPos(i, j, k);
}
@Override
public void markPosForPostprocessing(BlockPos pos) {
if (!this.isOutsideBuildHeight(pos)) {
ChunkAccess.getOrCreateOffsetList(this.postProcessing, this.getSectionIndex(pos.getY())).add(packOffsetCoordinates(pos));
}
}
@Override
public void addPackedPostProcess(ShortList offsets, int index) {
ChunkAccess.getOrCreateOffsetList(this.postProcessing, index).addAll(offsets);
}
public Map<BlockPos, CompoundTag> getBlockEntityNbts() {
return Collections.unmodifiableMap(this.pendingBlockEntities);
}
@Nullable
@Override
public CompoundTag getBlockEntityNbtForSaving(BlockPos pos, HolderLookup.Provider registries) {
BlockEntity blockEntity = this.getBlockEntity(pos);
return blockEntity != null ? blockEntity.saveWithFullMetadata(registries) : (CompoundTag)this.pendingBlockEntities.get(pos);
}
@Override
public void removeBlockEntity(BlockPos pos) {
this.blockEntities.remove(pos);
this.pendingBlockEntities.remove(pos);
}
@Nullable
public CarvingMask getCarvingMask() {
return this.carvingMask;
}
public CarvingMask getOrCreateCarvingMask() {
if (this.carvingMask == null) {
this.carvingMask = new CarvingMask(this.getHeight(), this.getMinY());
}
return this.carvingMask;
}
public void setCarvingMask(CarvingMask carvingMask) {
this.carvingMask = carvingMask;
}
public void setLightEngine(LevelLightEngine lightEngine) {
this.lightEngine = lightEngine;
}
public void setBelowZeroRetrogen(@Nullable BelowZeroRetrogen belowZeroRetrogen) {
this.belowZeroRetrogen = belowZeroRetrogen;
}
@Nullable
@Override
public BelowZeroRetrogen getBelowZeroRetrogen() {
return this.belowZeroRetrogen;
}
private static <T> LevelChunkTicks<T> unpackTicks(ProtoChunkTicks<T> ticks) {
return new LevelChunkTicks<>(ticks.scheduledTicks());
}
public LevelChunkTicks<Block> unpackBlockTicks() {
return unpackTicks(this.blockTicks);
}
public LevelChunkTicks<Fluid> unpackFluidTicks() {
return unpackTicks(this.fluidTicks);
}
@Override
public LevelHeightAccessor getHeightAccessorForGeneration() {
return (LevelHeightAccessor)(this.isUpgrading() ? BelowZeroRetrogen.UPGRADE_HEIGHT_ACCESSOR : this);
}
}