338 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.level.chunk;
 | |
| 
 | |
| import com.google.common.collect.Lists;
 | |
| import com.mojang.logging.LogUtils;
 | |
| 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.util.ProblemReporter;
 | |
| 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.level.storage.TagValueOutput;
 | |
| import net.minecraft.world.ticks.LevelChunkTicks;
 | |
| import net.minecraft.world.ticks.ProtoChunkTicks;
 | |
| import net.minecraft.world.ticks.TickContainerAccess;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| public class ProtoChunk extends ChunkAccess {
 | |
| 	private static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	@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()) {
 | |
| 			try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(entity.problemPath(), LOGGER)) {
 | |
| 				TagValueOutput tagValueOutput = TagValueOutput.createWithContext(scopedCollector, entity.registryAccess());
 | |
| 				entity.save(tagValueOutput);
 | |
| 				this.addEntity(tagValueOutput.buildResult());
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@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);
 | |
| 	}
 | |
| }
 |