786 lines
30 KiB
Java
786 lines
30 KiB
Java
package net.minecraft.world.level.chunk;
|
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import net.minecraft.core.Registry;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.level.ChunkTickList;
|
|
import it.unimi.dsi.fastutil.shorts.ShortListIterator;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
|
import java.util.stream.StreamSupport;
|
|
import java.util.stream.Stream;
|
|
import java.util.Collections;
|
|
import net.minecraft.network.FriendlyByteBuf;
|
|
import net.minecraft.world.entity.boss.EnderDragonPart;
|
|
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
|
import java.util.function.Predicate;
|
|
import java.util.List;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.block.EntityBlock;
|
|
import net.minecraft.world.level.material.Fluids;
|
|
import net.minecraft.world.level.material.FluidState;
|
|
import net.minecraft.ReportedException;
|
|
import net.minecraft.CrashReportCategory;
|
|
import net.minecraft.CrashReport;
|
|
import net.minecraft.world.level.levelgen.DebugLevelSource;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.LevelType;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import java.util.Collection;
|
|
import com.google.common.collect.Sets;
|
|
import java.util.Set;
|
|
import java.util.Iterator;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import com.google.common.collect.Maps;
|
|
import net.minecraft.world.level.EmptyTickList;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import java.util.function.Consumer;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.server.level.ChunkHolder;
|
|
import java.util.function.Supplier;
|
|
import net.minecraft.world.level.material.Fluid;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.TickList;
|
|
import it.unimi.dsi.fastutil.shorts.ShortList;
|
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.util.ClassInstanceMultiMap;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.levelgen.Heightmap;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.core.BlockPos;
|
|
import java.util.Map;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
public class LevelChunk implements ChunkAccess {
|
|
private static final Logger LOGGER;
|
|
public static final LevelChunkSection EMPTY_SECTION;
|
|
private final LevelChunkSection[] sections;
|
|
private ChunkBiomeContainer biomes;
|
|
private final Map<BlockPos, CompoundTag> pendingBlockEntities;
|
|
private boolean loaded;
|
|
private final Level level;
|
|
private final Map<Heightmap.Types, Heightmap> heightmaps;
|
|
private final UpgradeData upgradeData;
|
|
private final Map<BlockPos, BlockEntity> blockEntities;
|
|
private final ClassInstanceMultiMap<Entity>[] entitySections;
|
|
private final Map<String, StructureStart> structureStarts;
|
|
private final Map<String, LongSet> structuresRefences;
|
|
private final ShortList[] postProcessing;
|
|
private TickList<Block> blockTicks;
|
|
private TickList<Fluid> liquidTicks;
|
|
private boolean lastSaveHadEntities;
|
|
private long lastSaveTime;
|
|
private volatile boolean unsaved;
|
|
private long inhabitedTime;
|
|
@Nullable
|
|
private Supplier<ChunkHolder.FullChunkStatus> fullStatus;
|
|
@Nullable
|
|
private Consumer<LevelChunk> postLoad;
|
|
private final ChunkPos chunkPos;
|
|
private volatile boolean isLightCorrect;
|
|
|
|
public LevelChunk(final Level bjt, final ChunkPos bje, final ChunkBiomeContainer bzw) {
|
|
this(bjt, bje, bzw, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, null, null);
|
|
}
|
|
|
|
public LevelChunk(final Level bjt, final ChunkPos bje, final ChunkBiomeContainer bzw, final UpgradeData cas, final TickList<Block> bki5, final TickList<Fluid> bki6, final long long7, @Nullable final LevelChunkSection[] arr, @Nullable final Consumer<LevelChunk> consumer) {
|
|
this.sections = new LevelChunkSection[16];
|
|
this.pendingBlockEntities = Maps.newHashMap();
|
|
this.heightmaps = Maps.newEnumMap(Heightmap.Types.class);
|
|
this.blockEntities = Maps.newHashMap();
|
|
this.structureStarts = Maps.newHashMap();
|
|
this.structuresRefences = Maps.newHashMap();
|
|
this.postProcessing = new ShortList[16];
|
|
this.entitySections = new ClassInstanceMultiMap[16];
|
|
this.level = bjt;
|
|
this.chunkPos = bje;
|
|
this.upgradeData = cas;
|
|
for (final Heightmap.Types a15 : Heightmap.Types.values()) {
|
|
if (ChunkStatus.FULL.heightmapsAfter().contains(a15)) {
|
|
this.heightmaps.put(a15, new Heightmap(this, a15));
|
|
}
|
|
}
|
|
for (int integer12 = 0; integer12 < this.entitySections.length; ++integer12) {
|
|
this.entitySections[integer12] = new ClassInstanceMultiMap<Entity>(Entity.class);
|
|
}
|
|
this.biomes = bzw;
|
|
this.blockTicks = bki5;
|
|
this.liquidTicks = bki6;
|
|
this.inhabitedTime = long7;
|
|
this.postLoad = consumer;
|
|
if (arr != null) {
|
|
if (this.sections.length == arr.length) {
|
|
System.arraycopy(arr, 0, this.sections, 0, this.sections.length);
|
|
}
|
|
else {
|
|
LevelChunk.LOGGER.warn("Could not set level chunk sections, array length is {} instead of {}", arr.length, this.sections.length);
|
|
}
|
|
}
|
|
}
|
|
|
|
public LevelChunk(final Level bjt, final ProtoChunk caq) {
|
|
this(bjt, caq.getPos(), caq.getBiomes(), caq.getUpgradeData(), caq.getBlockTicks(), caq.getLiquidTicks(), caq.getInhabitedTime(), caq.getSections(), null);
|
|
for (final CompoundTag jt5 : caq.getEntities()) {
|
|
EntityType.loadEntityRecursive(jt5, bjt, akn -> {
|
|
this.addEntity(akn);
|
|
return akn;
|
|
});
|
|
}
|
|
for (final BlockEntity bwi5 : caq.getBlockEntities().values()) {
|
|
this.addBlockEntity(bwi5);
|
|
}
|
|
this.pendingBlockEntities.putAll(caq.getBlockEntityNbts());
|
|
for (int integer4 = 0; integer4 < caq.getPostProcessing().length; ++integer4) {
|
|
this.postProcessing[integer4] = caq.getPostProcessing()[integer4];
|
|
}
|
|
this.setAllStarts(caq.getAllStarts());
|
|
this.setAllReferences(caq.getAllReferences());
|
|
for (final Map.Entry<Heightmap.Types, Heightmap> entry5 : caq.getHeightmaps()) {
|
|
if (ChunkStatus.FULL.heightmapsAfter().contains(entry5.getKey())) {
|
|
this.getOrCreateHeightmapUnprimed(entry5.getKey()).setRawData(entry5.getValue().getRawData());
|
|
}
|
|
}
|
|
this.setLightCorrect(caq.isLightCorrect());
|
|
this.unsaved = true;
|
|
}
|
|
|
|
@Override
|
|
public Heightmap getOrCreateHeightmapUnprimed(final Heightmap.Types a) {
|
|
return this.heightmaps.computeIfAbsent(a, a -> new Heightmap(this, a));
|
|
}
|
|
|
|
@Override
|
|
public Set<BlockPos> getBlockEntitiesPos() {
|
|
final Set<BlockPos> set2 = Sets.newHashSet(this.pendingBlockEntities.keySet());
|
|
set2.addAll(this.blockEntities.keySet());
|
|
return set2;
|
|
}
|
|
|
|
@Override
|
|
public LevelChunkSection[] getSections() {
|
|
return this.sections;
|
|
}
|
|
|
|
@Override
|
|
public BlockState getBlockState(final BlockPos fk) {
|
|
final int integer3 = fk.getX();
|
|
final int integer4 = fk.getY();
|
|
final int integer5 = fk.getZ();
|
|
if (this.level.getGeneratorType() == LevelType.DEBUG_ALL_BLOCK_STATES) {
|
|
BlockState byg6 = null;
|
|
if (integer4 == 60) {
|
|
byg6 = Blocks.BARRIER.defaultBlockState();
|
|
}
|
|
if (integer4 == 70) {
|
|
byg6 = DebugLevelSource.getBlockStateFor(integer3, integer5);
|
|
}
|
|
return (byg6 == null) ? Blocks.AIR.defaultBlockState() : byg6;
|
|
}
|
|
try {
|
|
if (integer4 >= 0 && integer4 >> 4 < this.sections.length) {
|
|
final LevelChunkSection caj6 = this.sections[integer4 >> 4];
|
|
if (!LevelChunkSection.isEmpty(caj6)) {
|
|
return caj6.getBlockState(integer3 & 0xF, integer4 & 0xF, integer5 & 0xF);
|
|
}
|
|
}
|
|
return Blocks.AIR.defaultBlockState();
|
|
}
|
|
catch (Throwable throwable6) {
|
|
final CrashReport h7 = CrashReport.forThrowable(throwable6, "Getting block state");
|
|
final CrashReportCategory i8 = h7.addCategory("Block being got");
|
|
i8.setDetail("Location", () -> CrashReportCategory.formatLocation(integer3, integer4, integer5));
|
|
throw new ReportedException(h7);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public FluidState getFluidState(final BlockPos fk) {
|
|
return this.getFluidState(fk.getX(), fk.getY(), fk.getZ());
|
|
}
|
|
|
|
public FluidState getFluidState(final int integer1, final int integer2, final int integer3) {
|
|
try {
|
|
if (integer2 >= 0 && integer2 >> 4 < this.sections.length) {
|
|
final LevelChunkSection caj5 = this.sections[integer2 >> 4];
|
|
if (!LevelChunkSection.isEmpty(caj5)) {
|
|
return caj5.getFluidState(integer1 & 0xF, integer2 & 0xF, integer3 & 0xF);
|
|
}
|
|
}
|
|
return Fluids.EMPTY.defaultFluidState();
|
|
}
|
|
catch (Throwable throwable5) {
|
|
final CrashReport h6 = CrashReport.forThrowable(throwable5, "Getting fluid state");
|
|
final CrashReportCategory i7 = h6.addCategory("Block being got");
|
|
i7.setDetail("Location", () -> CrashReportCategory.formatLocation(integer1, integer2, integer3));
|
|
throw new ReportedException(h6);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public BlockState setBlockState(final BlockPos fk, final BlockState byg, final boolean boolean3) {
|
|
final int integer5 = fk.getX() & 0xF;
|
|
final int integer6 = fk.getY();
|
|
final int integer7 = fk.getZ() & 0xF;
|
|
LevelChunkSection caj8 = this.sections[integer6 >> 4];
|
|
if (caj8 == LevelChunk.EMPTY_SECTION) {
|
|
if (byg.isAir()) {
|
|
return null;
|
|
}
|
|
caj8 = new LevelChunkSection(integer6 >> 4 << 4);
|
|
this.sections[integer6 >> 4] = caj8;
|
|
}
|
|
final boolean boolean4 = caj8.isEmpty();
|
|
final BlockState byg2 = caj8.setBlockState(integer5, integer6 & 0xF, integer7, byg);
|
|
if (byg2 == byg) {
|
|
return null;
|
|
}
|
|
final Block bpe11 = byg.getBlock();
|
|
final Block bpe12 = byg2.getBlock();
|
|
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(integer5, integer6, integer7, byg);
|
|
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(integer5, integer6, integer7, byg);
|
|
this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(integer5, integer6, integer7, byg);
|
|
this.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(integer5, integer6, integer7, byg);
|
|
final boolean boolean5 = caj8.isEmpty();
|
|
if (boolean4 != boolean5) {
|
|
this.level.getChunkSource().getLightEngine().updateSectionStatus(fk, boolean5);
|
|
}
|
|
if (!this.level.isClientSide) {
|
|
byg2.onRemove(this.level, fk, byg, boolean3);
|
|
}
|
|
else if (bpe12 != bpe11 && bpe12 instanceof EntityBlock) {
|
|
this.level.removeBlockEntity(fk);
|
|
}
|
|
if (caj8.getBlockState(integer5, integer6 & 0xF, integer7).getBlock() != bpe11) {
|
|
return null;
|
|
}
|
|
if (bpe12 instanceof EntityBlock) {
|
|
final BlockEntity bwi14 = this.getBlockEntity(fk, EntityCreationType.CHECK);
|
|
if (bwi14 != null) {
|
|
bwi14.clearCache();
|
|
}
|
|
}
|
|
if (!this.level.isClientSide) {
|
|
byg.onPlace(this.level, fk, byg2, boolean3);
|
|
}
|
|
if (bpe11 instanceof EntityBlock) {
|
|
BlockEntity bwi14 = this.getBlockEntity(fk, EntityCreationType.CHECK);
|
|
if (bwi14 == null) {
|
|
bwi14 = ((EntityBlock)bpe11).newBlockEntity(this.level);
|
|
this.level.setBlockEntity(fk, bwi14);
|
|
}
|
|
else {
|
|
bwi14.clearCache();
|
|
}
|
|
}
|
|
this.unsaved = true;
|
|
return byg2;
|
|
}
|
|
|
|
@Nullable
|
|
public LevelLightEngine getLightEngine() {
|
|
return this.level.getChunkSource().getLightEngine();
|
|
}
|
|
|
|
@Override
|
|
public void addEntity(final Entity akn) {
|
|
this.lastSaveHadEntities = true;
|
|
final int integer3 = Mth.floor(akn.getX() / 16.0);
|
|
final int integer4 = Mth.floor(akn.getZ() / 16.0);
|
|
if (integer3 != this.chunkPos.x || integer4 != this.chunkPos.z) {
|
|
LevelChunk.LOGGER.warn("Wrong location! ({}, {}) should be ({}, {}), {}", integer3, integer4, this.chunkPos.x, this.chunkPos.z, akn);
|
|
akn.removed = true;
|
|
}
|
|
int integer5 = Mth.floor(akn.getY() / 16.0);
|
|
if (integer5 < 0) {
|
|
integer5 = 0;
|
|
}
|
|
if (integer5 >= this.entitySections.length) {
|
|
integer5 = this.entitySections.length - 1;
|
|
}
|
|
akn.inChunk = true;
|
|
akn.xChunk = this.chunkPos.x;
|
|
akn.yChunk = integer5;
|
|
akn.zChunk = this.chunkPos.z;
|
|
this.entitySections[integer5].add(akn);
|
|
}
|
|
|
|
@Override
|
|
public void setHeightmap(final Heightmap.Types a, final long[] arr) {
|
|
this.heightmaps.get(a).setRawData(arr);
|
|
}
|
|
|
|
public void removeEntity(final Entity akn) {
|
|
this.removeEntity(akn, akn.yChunk);
|
|
}
|
|
|
|
public void removeEntity(final Entity akn, int integer) {
|
|
if (integer < 0) {
|
|
integer = 0;
|
|
}
|
|
if (integer >= this.entitySections.length) {
|
|
integer = this.entitySections.length - 1;
|
|
}
|
|
this.entitySections[integer].remove(akn);
|
|
}
|
|
|
|
@Override
|
|
public int getHeight(final Heightmap.Types a, final int integer2, final int integer3) {
|
|
return this.heightmaps.get(a).getFirstAvailable(integer2 & 0xF, integer3 & 0xF) - 1;
|
|
}
|
|
|
|
@Nullable
|
|
private BlockEntity createBlockEntity(final BlockPos fk) {
|
|
final BlockState byg3 = this.getBlockState(fk);
|
|
final Block bpe4 = byg3.getBlock();
|
|
if (!bpe4.isEntityBlock()) {
|
|
return null;
|
|
}
|
|
return ((EntityBlock)bpe4).newBlockEntity(this.level);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public BlockEntity getBlockEntity(final BlockPos fk) {
|
|
return this.getBlockEntity(fk, EntityCreationType.CHECK);
|
|
}
|
|
|
|
@Nullable
|
|
public BlockEntity getBlockEntity(final BlockPos fk, final EntityCreationType a) {
|
|
BlockEntity bwi4 = this.blockEntities.get(fk);
|
|
if (bwi4 == null) {
|
|
final CompoundTag jt5 = this.pendingBlockEntities.remove(fk);
|
|
if (jt5 != null) {
|
|
final BlockEntity bwi5 = this.promotePendingBlockEntity(fk, jt5);
|
|
if (bwi5 != null) {
|
|
return bwi5;
|
|
}
|
|
}
|
|
}
|
|
if (bwi4 == null) {
|
|
if (a == EntityCreationType.IMMEDIATE) {
|
|
bwi4 = this.createBlockEntity(fk);
|
|
this.level.setBlockEntity(fk, bwi4);
|
|
}
|
|
}
|
|
else if (bwi4.isRemoved()) {
|
|
this.blockEntities.remove(fk);
|
|
return null;
|
|
}
|
|
return bwi4;
|
|
}
|
|
|
|
public void addBlockEntity(final BlockEntity bwi) {
|
|
this.setBlockEntity(bwi.getBlockPos(), bwi);
|
|
if (this.loaded || this.level.isClientSide()) {
|
|
this.level.setBlockEntity(bwi.getBlockPos(), bwi);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setBlockEntity(final BlockPos fk, final BlockEntity bwi) {
|
|
if (!(this.getBlockState(fk).getBlock() instanceof EntityBlock)) {
|
|
return;
|
|
}
|
|
bwi.setLevelAndPosition(this.level, fk);
|
|
bwi.clearRemoved();
|
|
final BlockEntity bwi2 = this.blockEntities.put(fk.immutable(), bwi);
|
|
if (bwi2 != null && bwi2 != bwi) {
|
|
bwi2.setRemoved();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setBlockEntityNbt(final CompoundTag jt) {
|
|
this.pendingBlockEntities.put(new BlockPos(jt.getInt("x"), jt.getInt("y"), jt.getInt("z")), jt);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public CompoundTag getBlockEntityNbtForSaving(final BlockPos fk) {
|
|
final BlockEntity bwi3 = this.getBlockEntity(fk);
|
|
if (bwi3 != null && !bwi3.isRemoved()) {
|
|
final CompoundTag jt4 = bwi3.save(new CompoundTag());
|
|
jt4.putBoolean("keepPacked", false);
|
|
return jt4;
|
|
}
|
|
CompoundTag jt4 = this.pendingBlockEntities.get(fk);
|
|
if (jt4 != null) {
|
|
jt4 = jt4.copy();
|
|
jt4.putBoolean("keepPacked", true);
|
|
}
|
|
return jt4;
|
|
}
|
|
|
|
@Override
|
|
public void removeBlockEntity(final BlockPos fk) {
|
|
if (this.loaded || this.level.isClientSide()) {
|
|
final BlockEntity bwi3 = this.blockEntities.remove(fk);
|
|
if (bwi3 != null) {
|
|
bwi3.setRemoved();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void runPostLoad() {
|
|
if (this.postLoad != null) {
|
|
this.postLoad.accept(this);
|
|
this.postLoad = null;
|
|
}
|
|
}
|
|
|
|
public void markUnsaved() {
|
|
this.unsaved = true;
|
|
}
|
|
|
|
public void getEntities(@Nullable final Entity akn, final AABB cvc, final List<Entity> list, @Nullable final Predicate<? super Entity> predicate) {
|
|
int integer6 = Mth.floor((cvc.minY - 2.0) / 16.0);
|
|
int integer7 = Mth.floor((cvc.maxY + 2.0) / 16.0);
|
|
integer6 = Mth.clamp(integer6, 0, this.entitySections.length - 1);
|
|
integer7 = Mth.clamp(integer7, 0, this.entitySections.length - 1);
|
|
for (int integer8 = integer6; integer8 <= integer7; ++integer8) {
|
|
if (!this.entitySections[integer8].isEmpty()) {
|
|
for (final Entity akn2 : this.entitySections[integer8]) {
|
|
if (akn2.getBoundingBox().intersects(cvc) && akn2 != akn) {
|
|
if (predicate == null || predicate.test(akn2)) {
|
|
list.add(akn2);
|
|
}
|
|
if (!(akn2 instanceof EnderDragon)) {
|
|
continue;
|
|
}
|
|
for (final EnderDragonPart aun14 : ((EnderDragon)akn2).getSubEntities()) {
|
|
if (aun14 != akn && aun14.getBoundingBox().intersects(cvc) && (predicate == null || predicate.test(aun14))) {
|
|
list.add(aun14);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public <T extends Entity> void getEntities(@Nullable final EntityType<?> akr, final AABB cvc, final List<? super T> list, final Predicate<? super T> predicate) {
|
|
int integer6 = Mth.floor((cvc.minY - 2.0) / 16.0);
|
|
int integer7 = Mth.floor((cvc.maxY + 2.0) / 16.0);
|
|
integer6 = Mth.clamp(integer6, 0, this.entitySections.length - 1);
|
|
integer7 = Mth.clamp(integer7, 0, this.entitySections.length - 1);
|
|
for (int integer8 = integer6; integer8 <= integer7; ++integer8) {
|
|
for (final Entity akn10 : this.entitySections[integer8].<Entity>find(Entity.class)) {
|
|
if (akr != null && akn10.getType() != akr) {
|
|
continue;
|
|
}
|
|
final T akn11 = (T)akn10;
|
|
if (!akn10.getBoundingBox().intersects(cvc) || !predicate.test(akn11)) {
|
|
continue;
|
|
}
|
|
list.add(akn11);
|
|
}
|
|
}
|
|
}
|
|
|
|
public <T extends Entity> void getEntitiesOfClass(final Class<? extends T> class1, final AABB cvc, final List<T> list, @Nullable final Predicate<? super T> predicate) {
|
|
int integer6 = Mth.floor((cvc.minY - 2.0) / 16.0);
|
|
int integer7 = Mth.floor((cvc.maxY + 2.0) / 16.0);
|
|
integer6 = Mth.clamp(integer6, 0, this.entitySections.length - 1);
|
|
integer7 = Mth.clamp(integer7, 0, this.entitySections.length - 1);
|
|
for (int integer8 = integer6; integer8 <= integer7; ++integer8) {
|
|
for (final T akn10 : this.entitySections[integer8].find(class1)) {
|
|
if (akn10.getBoundingBox().intersects(cvc) && (predicate == null || predicate.test(akn10))) {
|
|
list.add(akn10);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public ChunkPos getPos() {
|
|
return this.chunkPos;
|
|
}
|
|
|
|
public void replaceWithPacketData(@Nullable final ChunkBiomeContainer bzw, final FriendlyByteBuf kv, final CompoundTag jt, final int integer) {
|
|
final boolean boolean6 = bzw != null;
|
|
final Predicate<BlockPos> predicate7 = boolean6 ? (fk -> true) : (fk -> (integer & 1 << (fk.getY() >> 4)) != 0x0);
|
|
Sets.newHashSet(this.blockEntities.keySet()).stream().filter(predicate7).forEach(this.level::removeBlockEntity);
|
|
for (int integer2 = 0; integer2 < this.sections.length; ++integer2) {
|
|
LevelChunkSection caj9 = this.sections[integer2];
|
|
if ((integer & 1 << integer2) == 0x0) {
|
|
if (boolean6 && caj9 != LevelChunk.EMPTY_SECTION) {
|
|
this.sections[integer2] = LevelChunk.EMPTY_SECTION;
|
|
}
|
|
}
|
|
else {
|
|
if (caj9 == LevelChunk.EMPTY_SECTION) {
|
|
caj9 = new LevelChunkSection(integer2 << 4);
|
|
this.sections[integer2] = caj9;
|
|
}
|
|
caj9.read(kv);
|
|
}
|
|
}
|
|
if (bzw != null) {
|
|
this.biomes = bzw;
|
|
}
|
|
for (final Heightmap.Types a11 : Heightmap.Types.values()) {
|
|
final String string12 = a11.getSerializationKey();
|
|
if (jt.contains(string12, 12)) {
|
|
this.setHeightmap(a11, jt.getLongArray(string12));
|
|
}
|
|
}
|
|
for (final BlockEntity bwi9 : this.blockEntities.values()) {
|
|
bwi9.clearCache();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ChunkBiomeContainer getBiomes() {
|
|
return this.biomes;
|
|
}
|
|
|
|
public void setLoaded(final boolean boolean1) {
|
|
this.loaded = boolean1;
|
|
}
|
|
|
|
public Level getLevel() {
|
|
return this.level;
|
|
}
|
|
|
|
@Override
|
|
public Collection<Map.Entry<Heightmap.Types, Heightmap>> getHeightmaps() {
|
|
return Collections.unmodifiableSet(this.heightmaps.entrySet());
|
|
}
|
|
|
|
public Map<BlockPos, BlockEntity> getBlockEntities() {
|
|
return this.blockEntities;
|
|
}
|
|
|
|
public ClassInstanceMultiMap<Entity>[] getEntitySections() {
|
|
return this.entitySections;
|
|
}
|
|
|
|
@Override
|
|
public CompoundTag getBlockEntityNbt(final BlockPos fk) {
|
|
return this.pendingBlockEntities.get(fk);
|
|
}
|
|
|
|
@Override
|
|
public Stream<BlockPos> getLights() {
|
|
return StreamSupport.<BlockPos>stream(BlockPos.betweenClosed(this.chunkPos.getMinBlockX(), 0, this.chunkPos.getMinBlockZ(), this.chunkPos.getMaxBlockX(), 255, this.chunkPos.getMaxBlockZ()).spliterator(), false).filter(fk -> this.getBlockState(fk).getLightEmission() != 0);
|
|
}
|
|
|
|
@Override
|
|
public TickList<Block> getBlockTicks() {
|
|
return this.blockTicks;
|
|
}
|
|
|
|
@Override
|
|
public TickList<Fluid> getLiquidTicks() {
|
|
return this.liquidTicks;
|
|
}
|
|
|
|
@Override
|
|
public void setUnsaved(final boolean boolean1) {
|
|
this.unsaved = boolean1;
|
|
}
|
|
|
|
@Override
|
|
public boolean isUnsaved() {
|
|
return this.unsaved || (this.lastSaveHadEntities && this.level.getGameTime() != this.lastSaveTime);
|
|
}
|
|
|
|
public void setLastSaveHadEntities(final boolean boolean1) {
|
|
this.lastSaveHadEntities = boolean1;
|
|
}
|
|
|
|
@Override
|
|
public void setLastSaveTime(final long long1) {
|
|
this.lastSaveTime = 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);
|
|
}
|
|
|
|
@Override
|
|
public Map<String, StructureStart> getAllStarts() {
|
|
return this.structureStarts;
|
|
}
|
|
|
|
@Override
|
|
public void setAllStarts(final Map<String, StructureStart> map) {
|
|
this.structureStarts.clear();
|
|
this.structureStarts.putAll(map);
|
|
}
|
|
|
|
@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);
|
|
}
|
|
|
|
@Override
|
|
public Map<String, LongSet> getAllReferences() {
|
|
return this.structuresRefences;
|
|
}
|
|
|
|
@Override
|
|
public void setAllReferences(final Map<String, LongSet> map) {
|
|
this.structuresRefences.clear();
|
|
this.structuresRefences.putAll(map);
|
|
}
|
|
|
|
@Override
|
|
public long getInhabitedTime() {
|
|
return this.inhabitedTime;
|
|
}
|
|
|
|
@Override
|
|
public void setInhabitedTime(final long long1) {
|
|
this.inhabitedTime = long1;
|
|
}
|
|
|
|
public void postProcessGeneration() {
|
|
final ChunkPos bje2 = this.getPos();
|
|
for (int integer3 = 0; integer3 < this.postProcessing.length; ++integer3) {
|
|
if (this.postProcessing[integer3] != null) {
|
|
for (final Short short5 : this.postProcessing[integer3]) {
|
|
final BlockPos fk6 = ProtoChunk.unpackOffsetCoordinates(short5, integer3, bje2);
|
|
final BlockState byg7 = this.getBlockState(fk6);
|
|
final BlockState byg8 = Block.updateFromNeighbourShapes(byg7, this.level, fk6);
|
|
this.level.setBlock(fk6, byg8, 20);
|
|
}
|
|
this.postProcessing[integer3].clear();
|
|
}
|
|
}
|
|
this.unpackTicks();
|
|
for (final BlockPos fk7 : Sets.<BlockPos>newHashSet(this.pendingBlockEntities.keySet())) {
|
|
this.getBlockEntity(fk7);
|
|
}
|
|
this.pendingBlockEntities.clear();
|
|
this.upgradeData.upgrade(this);
|
|
}
|
|
|
|
@Nullable
|
|
private BlockEntity promotePendingBlockEntity(final BlockPos fk, final CompoundTag jt) {
|
|
BlockEntity bwi4;
|
|
if ("DUMMY".equals(jt.getString("id"))) {
|
|
final Block bpe5 = this.getBlockState(fk).getBlock();
|
|
if (bpe5 instanceof EntityBlock) {
|
|
bwi4 = ((EntityBlock)bpe5).newBlockEntity(this.level);
|
|
}
|
|
else {
|
|
bwi4 = null;
|
|
LevelChunk.LOGGER.warn("Tried to load a DUMMY block entity @ {} but found not block entity block {} at location", fk, this.getBlockState(fk));
|
|
}
|
|
}
|
|
else {
|
|
bwi4 = BlockEntity.loadStatic(jt);
|
|
}
|
|
if (bwi4 != null) {
|
|
bwi4.setLevelAndPosition(this.level, fk);
|
|
this.addBlockEntity(bwi4);
|
|
}
|
|
else {
|
|
LevelChunk.LOGGER.warn("Tried to load a block entity for block {} but failed at location {}", this.getBlockState(fk), fk);
|
|
}
|
|
return bwi4;
|
|
}
|
|
|
|
@Override
|
|
public UpgradeData getUpgradeData() {
|
|
return this.upgradeData;
|
|
}
|
|
|
|
@Override
|
|
public ShortList[] getPostProcessing() {
|
|
return this.postProcessing;
|
|
}
|
|
|
|
public void unpackTicks() {
|
|
if (this.blockTicks instanceof ProtoTickList) {
|
|
((ProtoTickList)this.blockTicks).copyOut(this.level.getBlockTicks(), fk -> this.getBlockState(fk).getBlock());
|
|
this.blockTicks = EmptyTickList.empty();
|
|
}
|
|
else if (this.blockTicks instanceof ChunkTickList) {
|
|
this.level.getBlockTicks().addAll(((ChunkTickList)this.blockTicks).ticks());
|
|
this.blockTicks = EmptyTickList.empty();
|
|
}
|
|
if (this.liquidTicks instanceof ProtoTickList) {
|
|
((ProtoTickList)this.liquidTicks).copyOut(this.level.getLiquidTicks(), fk -> this.getFluidState(fk).getType());
|
|
this.liquidTicks = EmptyTickList.empty();
|
|
}
|
|
else if (this.liquidTicks instanceof ChunkTickList) {
|
|
this.level.getLiquidTicks().addAll(((ChunkTickList)this.liquidTicks).ticks());
|
|
this.liquidTicks = EmptyTickList.empty();
|
|
}
|
|
}
|
|
|
|
public void packTicks(final ServerLevel xd) {
|
|
if (this.blockTicks == EmptyTickList.empty()) {
|
|
this.blockTicks = new ChunkTickList<Block>(Registry.BLOCK::getKey, xd.getBlockTicks().fetchTicksInChunk(this.chunkPos, true, false));
|
|
this.setUnsaved(true);
|
|
}
|
|
if (this.liquidTicks == EmptyTickList.empty()) {
|
|
this.liquidTicks = new ChunkTickList<Fluid>(Registry.FLUID::getKey, xd.getLiquidTicks().fetchTicksInChunk(this.chunkPos, true, false));
|
|
this.setUnsaved(true);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ChunkStatus getStatus() {
|
|
return ChunkStatus.FULL;
|
|
}
|
|
|
|
public ChunkHolder.FullChunkStatus getFullStatus() {
|
|
if (this.fullStatus == null) {
|
|
return ChunkHolder.FullChunkStatus.BORDER;
|
|
}
|
|
return this.fullStatus.get();
|
|
}
|
|
|
|
public void setFullStatus(final Supplier<ChunkHolder.FullChunkStatus> supplier) {
|
|
this.fullStatus = supplier;
|
|
}
|
|
|
|
@Override
|
|
public boolean isLightCorrect() {
|
|
return this.isLightCorrect;
|
|
}
|
|
|
|
@Override
|
|
public void setLightCorrect(final boolean boolean1) {
|
|
this.isLightCorrect = boolean1;
|
|
this.setUnsaved(true);
|
|
}
|
|
|
|
static {
|
|
LOGGER = LogManager.getLogger();
|
|
EMPTY_SECTION = null;
|
|
}
|
|
|
|
public enum EntityCreationType {
|
|
IMMEDIATE,
|
|
QUEUED,
|
|
CHECK;
|
|
}
|
|
}
|