minecraft-source/src/net/minecraft/world/level/chunk/ProtoChunk.java

466 lines
16 KiB
Java

package net.minecraft.world.level.chunk;
import org.apache.logging.log4j.LogManager;
import net.minecraft.world.level.TickList;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import java.util.Collections;
import net.minecraft.world.entity.Entity;
import java.util.Collection;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.EnumSet;
import net.minecraft.world.level.BlockGetter;
import java.util.Iterator;
import java.util.stream.Stream;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraft.world.level.material.Fluids;
import java.util.BitSet;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.block.Block;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import it.unimi.dsi.fastutil.shorts.ShortList;
import java.util.List;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.levelgen.Heightmap;
import java.util.Map;
import net.minecraft.world.level.lighting.LevelLightEngine;
import javax.annotation.Nullable;
import net.minecraft.world.level.ChunkPos;
import org.apache.logging.log4j.Logger;
public class ProtoChunk implements ChunkAccess {
private static final Logger LOGGER;
private final ChunkPos chunkPos;
private volatile boolean isDirty;
@Nullable
private ChunkBiomeContainer biomes;
@Nullable
private volatile LevelLightEngine lightEngine;
private final Map<Heightmap.Types, Heightmap> heightmaps;
private volatile ChunkStatus status;
private final Map<BlockPos, BlockEntity> blockEntities;
private final Map<BlockPos, CompoundTag> blockEntityNbts;
private final LevelChunkSection[] sections;
private final List<CompoundTag> entities;
private final List<BlockPos> lights;
private final ShortList[] postProcessing;
private final Map<String, StructureStart> structureStarts;
private final Map<String, LongSet> structuresRefences;
private final UpgradeData upgradeData;
private final ProtoTickList<Block> blockTicks;
private final ProtoTickList<Fluid> liquidTicks;
private long inhabitedTime;
private final Map<GenerationStep.Carving, BitSet> carvingMasks;
private volatile boolean isLightCorrect;
public ProtoChunk(final ChunkPos bje, final UpgradeData cas) {
this(bje, cas, null, new ProtoTickList<Block>(bpe -> bpe == null || bpe.defaultBlockState().isAir(), bje), new ProtoTickList<Fluid>(cof -> cof == null || cof == Fluids.EMPTY, bje));
}
public ProtoChunk(final ChunkPos bje, final UpgradeData cas, @Nullable final LevelChunkSection[] arr, final ProtoTickList<Block> car4, final ProtoTickList<Fluid> car5) {
this.heightmaps = Maps.newEnumMap(Heightmap.Types.class);
this.status = ChunkStatus.EMPTY;
this.blockEntities = Maps.newHashMap();
this.blockEntityNbts = Maps.newHashMap();
this.sections = new LevelChunkSection[16];
this.entities = Lists.newArrayList();
this.lights = Lists.newArrayList();
this.postProcessing = new ShortList[16];
this.structureStarts = Maps.newHashMap();
this.structuresRefences = Maps.newHashMap();
this.carvingMasks = Maps.newHashMap();
this.chunkPos = bje;
this.upgradeData = cas;
this.blockTicks = car4;
this.liquidTicks = car5;
if (arr != null) {
if (this.sections.length == arr.length) {
System.arraycopy(arr, 0, this.sections, 0, this.sections.length);
}
else {
ProtoChunk.LOGGER.warn("Could not set level chunk sections, array length is {} instead of {}", arr.length, this.sections.length);
}
}
}
@Override
public BlockState getBlockState(final BlockPos fk) {
final int integer3 = fk.getY();
if (Level.isOutsideBuildHeight(integer3)) {
return Blocks.VOID_AIR.defaultBlockState();
}
final LevelChunkSection caj4 = this.getSections()[integer3 >> 4];
if (LevelChunkSection.isEmpty(caj4)) {
return Blocks.AIR.defaultBlockState();
}
return caj4.getBlockState(fk.getX() & 0xF, integer3 & 0xF, fk.getZ() & 0xF);
}
@Override
public FluidState getFluidState(final BlockPos fk) {
final int integer3 = fk.getY();
if (Level.isOutsideBuildHeight(integer3)) {
return Fluids.EMPTY.defaultFluidState();
}
final LevelChunkSection caj4 = this.getSections()[integer3 >> 4];
if (LevelChunkSection.isEmpty(caj4)) {
return Fluids.EMPTY.defaultFluidState();
}
return caj4.getFluidState(fk.getX() & 0xF, integer3 & 0xF, fk.getZ() & 0xF);
}
@Override
public Stream<BlockPos> getLights() {
return this.lights.stream();
}
public ShortList[] getPackedLights() {
final ShortList[] arr2 = new ShortList[16];
for (final BlockPos fk4 : this.lights) {
ChunkAccess.getOrCreateOffsetList(arr2, fk4.getY() >> 4).add(packOffsetCoordinates(fk4));
}
return arr2;
}
public void addLight(final short short1, final int integer) {
this.addLight(unpackOffsetCoordinates(short1, integer, this.chunkPos));
}
public void addLight(final BlockPos fk) {
this.lights.add(fk.immutable());
}
@Nullable
@Override
public BlockState setBlockState(final BlockPos fk, final BlockState byg, final boolean boolean3) {
final int integer5 = fk.getX();
final int integer6 = fk.getY();
final int integer7 = fk.getZ();
if (integer6 < 0 || integer6 >= 256) {
return Blocks.VOID_AIR.defaultBlockState();
}
if (this.sections[integer6 >> 4] == LevelChunk.EMPTY_SECTION && byg.getBlock() == Blocks.AIR) {
return byg;
}
if (byg.getLightEmission() > 0) {
this.lights.add(new BlockPos((integer5 & 0xF) + this.getPos().getMinBlockX(), integer6, (integer7 & 0xF) + this.getPos().getMinBlockZ()));
}
final LevelChunkSection caj8 = this.getOrCreateSection(integer6 >> 4);
final BlockState byg2 = caj8.setBlockState(integer5 & 0xF, integer6 & 0xF, integer7 & 0xF, byg);
if (this.status.isOrAfter(ChunkStatus.FEATURES) && byg != byg2 && (byg.getLightBlock(this, fk) != byg2.getLightBlock(this, fk) || byg.getLightEmission() != byg2.getLightEmission() || byg.useShapeForLightOcclusion() || byg2.useShapeForLightOcclusion())) {
final LevelLightEngine cnx10 = this.getLightEngine();
cnx10.checkBlock(fk);
}
final EnumSet<Heightmap.Types> enumSet10 = this.getStatus().heightmapsAfter();
EnumSet<Heightmap.Types> enumSet11 = null;
for (final Heightmap.Types a13 : enumSet10) {
final Heightmap cbs14 = this.heightmaps.get(a13);
if (cbs14 == null) {
if (enumSet11 == null) {
enumSet11 = EnumSet.<Heightmap.Types>noneOf(Heightmap.Types.class);
}
enumSet11.add(a13);
}
}
if (enumSet11 != null) {
Heightmap.primeHeightmaps(this, enumSet11);
}
for (final Heightmap.Types a13 : enumSet10) {
this.heightmaps.get(a13).update(integer5 & 0xF, integer6, integer7 & 0xF, byg);
}
return byg2;
}
public LevelChunkSection getOrCreateSection(final int integer) {
if (this.sections[integer] == LevelChunk.EMPTY_SECTION) {
this.sections[integer] = new LevelChunkSection(integer << 4);
}
return this.sections[integer];
}
@Override
public void setBlockEntity(final BlockPos fk, final BlockEntity bwi) {
bwi.setPosition(fk);
this.blockEntities.put(fk, bwi);
}
@Override
public Set<BlockPos> getBlockEntitiesPos() {
final Set<BlockPos> set2 = Sets.newHashSet(this.blockEntityNbts.keySet());
set2.addAll(this.blockEntities.keySet());
return set2;
}
@Nullable
@Override
public BlockEntity getBlockEntity(final BlockPos fk) {
return this.blockEntities.get(fk);
}
public Map<BlockPos, BlockEntity> getBlockEntities() {
return this.blockEntities;
}
public void addEntity(final CompoundTag jt) {
this.entities.add(jt);
}
@Override
public void addEntity(final Entity akn) {
final CompoundTag jt3 = new CompoundTag();
akn.save(jt3);
this.addEntity(jt3);
}
public List<CompoundTag> getEntities() {
return this.entities;
}
public void setBiomes(final ChunkBiomeContainer bzw) {
this.biomes = bzw;
}
@Nullable
@Override
public ChunkBiomeContainer getBiomes() {
return this.biomes;
}
@Override
public void setUnsaved(final boolean boolean1) {
this.isDirty = boolean1;
}
@Override
public boolean isUnsaved() {
return this.isDirty;
}
@Override
public ChunkStatus getStatus() {
return this.status;
}
public void setStatus(final ChunkStatus cab) {
this.status = cab;
this.setUnsaved(true);
}
@Override
public LevelChunkSection[] getSections() {
return this.sections;
}
@Nullable
public LevelLightEngine getLightEngine() {
return this.lightEngine;
}
@Override
public Collection<Map.Entry<Heightmap.Types, Heightmap>> getHeightmaps() {
return Collections.unmodifiableSet(this.heightmaps.entrySet());
}
@Override
public void setHeightmap(final Heightmap.Types a, final long[] arr) {
this.getOrCreateHeightmapUnprimed(a).setRawData(arr);
}
@Override
public Heightmap getOrCreateHeightmapUnprimed(final Heightmap.Types a) {
return this.heightmaps.computeIfAbsent(a, a -> new Heightmap(this, a));
}
@Override
public int getHeight(final Heightmap.Types a, final int integer2, final int integer3) {
Heightmap cbs5 = this.heightmaps.get(a);
if (cbs5 == null) {
Heightmap.primeHeightmaps(this, EnumSet.<Heightmap.Types>of(a));
cbs5 = this.heightmaps.get(a);
}
return cbs5.getFirstAvailable(integer2 & 0xF, integer3 & 0xF) - 1;
}
@Override
public ChunkPos getPos() {
return this.chunkPos;
}
@Override
public void setLastSaveTime(final long long1) {
}
@Nullable
@Override
public StructureStart getStartForFeature(final String string) {
return this.structureStarts.get(string);
}
@Override
public void setStartForFeature(final String string, final StructureStart cls) {
this.structureStarts.put(string, cls);
this.isDirty = true;
}
@Override
public Map<String, StructureStart> getAllStarts() {
return Collections.<String, StructureStart>unmodifiableMap(this.structureStarts);
}
@Override
public void setAllStarts(final Map<String, StructureStart> map) {
this.structureStarts.clear();
this.structureStarts.putAll(map);
this.isDirty = true;
}
@Override
public LongSet getReferencesForFeature(final String string) {
return this.structuresRefences.computeIfAbsent(string, string -> new LongOpenHashSet());
}
@Override
public void addReferenceForFeature(final String string, final long long2) {
this.structuresRefences.computeIfAbsent(string, string -> new LongOpenHashSet()).add(long2);
this.isDirty = true;
}
@Override
public Map<String, LongSet> getAllReferences() {
return Collections.<String, LongSet>unmodifiableMap(this.structuresRefences);
}
@Override
public void setAllReferences(final Map<String, LongSet> map) {
this.structuresRefences.clear();
this.structuresRefences.putAll(map);
this.isDirty = true;
}
public static short packOffsetCoordinates(final BlockPos fk) {
final int integer2 = fk.getX();
final int integer3 = fk.getY();
final int integer4 = fk.getZ();
final int integer5 = integer2 & 0xF;
final int integer6 = integer3 & 0xF;
final int integer7 = integer4 & 0xF;
return (short)(integer5 | integer6 << 4 | integer7 << 8);
}
public static BlockPos unpackOffsetCoordinates(final short short1, final int integer, final ChunkPos bje) {
final int integer2 = (short1 & 0xF) + (bje.x << 4);
final int integer3 = (short1 >>> 4 & 0xF) + (integer << 4);
final int integer4 = (short1 >>> 8 & 0xF) + (bje.z << 4);
return new BlockPos(integer2, integer3, integer4);
}
@Override
public void markPosForPostprocessing(final BlockPos fk) {
if (!Level.isOutsideBuildHeight(fk)) {
ChunkAccess.getOrCreateOffsetList(this.postProcessing, fk.getY() >> 4).add(packOffsetCoordinates(fk));
}
}
@Override
public ShortList[] getPostProcessing() {
return this.postProcessing;
}
@Override
public void addPackedPostProcess(final short short1, final int integer) {
ChunkAccess.getOrCreateOffsetList(this.postProcessing, integer).add(short1);
}
@Override
public ProtoTickList<Block> getBlockTicks() {
return this.blockTicks;
}
@Override
public ProtoTickList<Fluid> getLiquidTicks() {
return this.liquidTicks;
}
@Override
public UpgradeData getUpgradeData() {
return this.upgradeData;
}
@Override
public void setInhabitedTime(final long long1) {
this.inhabitedTime = long1;
}
@Override
public long getInhabitedTime() {
return this.inhabitedTime;
}
@Override
public void setBlockEntityNbt(final CompoundTag jt) {
this.blockEntityNbts.put(new BlockPos(jt.getInt("x"), jt.getInt("y"), jt.getInt("z")), jt);
}
public Map<BlockPos, CompoundTag> getBlockEntityNbts() {
return Collections.<BlockPos, CompoundTag>unmodifiableMap(this.blockEntityNbts);
}
@Override
public CompoundTag getBlockEntityNbt(final BlockPos fk) {
return this.blockEntityNbts.get(fk);
}
@Nullable
@Override
public CompoundTag getBlockEntityNbtForSaving(final BlockPos fk) {
final BlockEntity bwi3 = this.getBlockEntity(fk);
if (bwi3 != null) {
return bwi3.save(new CompoundTag());
}
return this.blockEntityNbts.get(fk);
}
@Override
public void removeBlockEntity(final BlockPos fk) {
this.blockEntities.remove(fk);
this.blockEntityNbts.remove(fk);
}
@Override
public BitSet getCarvingMask(final GenerationStep.Carving a) {
return this.carvingMasks.computeIfAbsent(a, a -> new BitSet(65536));
}
public void setCarvingMask(final GenerationStep.Carving a, final BitSet bitSet) {
this.carvingMasks.put(a, bitSet);
}
public void setLightEngine(final LevelLightEngine cnx) {
this.lightEngine = cnx;
}
@Override
public boolean isLightCorrect() {
return this.isLightCorrect;
}
@Override
public void setLightCorrect(final boolean boolean1) {
this.isLightCorrect = boolean1;
this.setUnsaved(true);
}
static {
LOGGER = LogManager.getLogger();
}
}