466 lines
16 KiB
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();
|
|
}
|
|
}
|