Code/net/minecraft/world/level/chunk/storage/SerializableChunkData.java

613 lines
30 KiB
Java
Raw Permalink Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.level.chunk.storage;
import com.google.common.collect.Maps;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import it.unimi.dsi.fastutil.shorts.ShortList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import net.minecraft.Optionull;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.NbtException;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.ShortTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
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.CarvingMask;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkType;
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.Structure;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.ticks.LevelChunkTicks;
import net.minecraft.world.ticks.ProtoChunkTicks;
import net.minecraft.world.ticks.SavedTick;
import org.slf4j.Logger;
public record SerializableChunkData(
Registry<Biome> biomeRegistry,
ChunkPos chunkPos,
int minSectionY,
long lastUpdateTime,
long inhabitedTime,
ChunkStatus chunkStatus,
@Nullable BlendingData.Packed blendingData,
@Nullable BelowZeroRetrogen belowZeroRetrogen,
UpgradeData upgradeData,
@Nullable long[] carvingMask,
Map<Heightmap.Types, long[]> heightmaps,
ChunkAccess.PackedTicks packedTicks,
ShortList[] postProcessingSections,
boolean lightCorrect,
List<SerializableChunkData.SectionData> sectionData,
List<CompoundTag> entities,
List<CompoundTag> blockEntities,
CompoundTag structureData
) {
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()
);
private static final Codec<List<SavedTick<Block>>> BLOCK_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.BLOCK.byNameCodec()).listOf();
private static final Codec<List<SavedTick<Fluid>>> FLUID_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.FLUID.byNameCodec()).listOf();
private static final Logger LOGGER = LogUtils.getLogger();
private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG = "block_ticks";
private static final String FLUID_TICKS_TAG = "fluid_ticks";
public static final String X_POS_TAG = "xPos";
public static final String Z_POS_TAG = "zPos";
public static final String HEIGHTMAPS_TAG = "Heightmaps";
public static final String IS_LIGHT_ON_TAG = "isLightOn";
public static final String SECTIONS_TAG = "sections";
public static final String BLOCK_LIGHT_TAG = "BlockLight";
public static final String SKY_LIGHT_TAG = "SkyLight";
@Nullable
public static SerializableChunkData parse(LevelHeightAccessor p_366637_, RegistryAccess p_364474_, CompoundTag p_368975_) {
if (p_368975_.getString("Status").isEmpty()) {
return null;
} else {
ChunkPos chunkpos = new ChunkPos(p_368975_.getIntOr("xPos", 0), p_368975_.getIntOr("zPos", 0));
long i = p_368975_.getLongOr("LastUpdate", 0L);
long j = p_368975_.getLongOr("InhabitedTime", 0L);
ChunkStatus chunkstatus = p_368975_.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
UpgradeData upgradedata = p_368975_.getCompound("UpgradeData").map(p_391014_ -> new UpgradeData(p_391014_, p_366637_)).orElse(UpgradeData.EMPTY);
boolean flag = p_368975_.getBooleanOr("isLightOn", false);
BlendingData.Packed blendingdata$packed = p_368975_.read("blending_data", BlendingData.Packed.CODEC).orElse(null);
BelowZeroRetrogen belowzeroretrogen = p_368975_.read("below_zero_retrogen", BelowZeroRetrogen.CODEC).orElse(null);
long[] along = p_368975_.getLongArray("carving_mask").orElse(null);
Map<Heightmap.Types, long[]> map = new EnumMap<>(Heightmap.Types.class);
p_368975_.getCompound("Heightmaps").ifPresent(p_391017_ -> {
for (Heightmap.Types heightmap$types : chunkstatus.heightmapsAfter()) {
p_391017_.getLongArray(heightmap$types.getSerializationKey()).ifPresent(p_391011_ -> map.put(heightmap$types, p_391011_));
}
});
List<SavedTick<Block>> list = SavedTick.filterTickListForChunk(p_368975_.read("block_ticks", BLOCK_TICKS_CODEC).orElse(List.of()), chunkpos);
List<SavedTick<Fluid>> list1 = SavedTick.filterTickListForChunk(p_368975_.read("fluid_ticks", FLUID_TICKS_CODEC).orElse(List.of()), chunkpos);
ChunkAccess.PackedTicks chunkaccess$packedticks = new ChunkAccess.PackedTicks(list, list1);
ListTag listtag = p_368975_.getListOrEmpty("PostProcessing");
ShortList[] ashortlist = new ShortList[listtag.size()];
for (int k = 0; k < listtag.size(); k++) {
ListTag listtag1 = listtag.getListOrEmpty(k);
ShortList shortlist = new ShortArrayList(listtag1.size());
for (int l = 0; l < listtag1.size(); l++) {
shortlist.add(listtag1.getShortOr(l, (short)0));
}
ashortlist[k] = shortlist;
}
List<CompoundTag> list3 = p_368975_.getList("entities").stream().flatMap(ListTag::compoundStream).toList();
List<CompoundTag> list4 = p_368975_.getList("block_entities").stream().flatMap(ListTag::compoundStream).toList();
CompoundTag compoundtag1 = p_368975_.getCompoundOrEmpty("structures");
ListTag listtag2 = p_368975_.getListOrEmpty("sections");
List<SerializableChunkData.SectionData> list2 = new ArrayList<>(listtag2.size());
Registry<Biome> registry = p_364474_.lookupOrThrow(Registries.BIOME);
Codec<PalettedContainerRO<Holder<Biome>>> codec = makeBiomeCodec(registry);
for (int i1 = 0; i1 < listtag2.size(); i1++) {
Optional<CompoundTag> optional = listtag2.getCompound(i1);
if (!optional.isEmpty()) {
CompoundTag compoundtag = optional.get();
int j1 = compoundtag.getByteOr("Y", (byte)0);
LevelChunkSection levelchunksection;
if (j1 >= p_366637_.getMinSectionY() && j1 <= p_366637_.getMaxSectionY()) {
PalettedContainer<BlockState> palettedcontainer = compoundtag.getCompound("block_states")
.map(
p_391024_ -> BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, p_391024_)
.promotePartial(p_362514_ -> logErrors(chunkpos, j1, p_362514_))
.getOrThrow(SerializableChunkData.ChunkReadException::new)
)
.orElseGet(() -> new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES));
PalettedContainerRO<Holder<Biome>> palettedcontainerro = compoundtag.getCompound("biomes")
.map(
p_391021_ -> codec.parse(NbtOps.INSTANCE, p_391021_)
.promotePartial(p_362842_ -> logErrors(chunkpos, j1, p_362842_))
.getOrThrow(SerializableChunkData.ChunkReadException::new)
)
.orElseGet(
() -> new PalettedContainer<>(registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES)
);
levelchunksection = new LevelChunkSection(palettedcontainer, palettedcontainerro);
} else {
levelchunksection = null;
}
DataLayer datalayer = compoundtag.getByteArray("BlockLight").map(DataLayer::new).orElse(null);
DataLayer datalayer1 = compoundtag.getByteArray("SkyLight").map(DataLayer::new).orElse(null);
list2.add(new SerializableChunkData.SectionData(j1, levelchunksection, datalayer, datalayer1));
}
}
return new SerializableChunkData(
registry,
chunkpos,
p_366637_.getMinSectionY(),
i,
j,
chunkstatus,
blendingdata$packed,
belowzeroretrogen,
upgradedata,
along,
map,
chunkaccess$packedticks,
ashortlist,
flag,
list2,
list3,
list4,
compoundtag1
);
}
}
public ProtoChunk read(ServerLevel p_368634_, PoiManager p_362734_, RegionStorageInfo p_366907_, ChunkPos p_363624_) {
if (!Objects.equals(p_363624_, this.chunkPos)) {
LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", p_363624_, p_363624_, this.chunkPos);
p_368634_.getServer().reportMisplacedChunk(this.chunkPos, p_363624_, p_366907_);
}
int i = p_368634_.getSectionsCount();
LevelChunkSection[] alevelchunksection = new LevelChunkSection[i];
boolean flag = p_368634_.dimensionType().hasSkyLight();
ChunkSource chunksource = p_368634_.getChunkSource();
LevelLightEngine levellightengine = chunksource.getLightEngine();
Registry<Biome> registry = p_368634_.registryAccess().lookupOrThrow(Registries.BIOME);
boolean flag1 = false;
for (SerializableChunkData.SectionData serializablechunkdata$sectiondata : this.sectionData) {
SectionPos sectionpos = SectionPos.of(p_363624_, serializablechunkdata$sectiondata.y);
if (serializablechunkdata$sectiondata.chunkSection != null) {
alevelchunksection[p_368634_.getSectionIndexFromSectionY(serializablechunkdata$sectiondata.y)] = serializablechunkdata$sectiondata.chunkSection;
p_362734_.checkConsistencyWithBlocks(sectionpos, serializablechunkdata$sectiondata.chunkSection);
}
boolean flag2 = serializablechunkdata$sectiondata.blockLight != null;
boolean flag3 = flag && serializablechunkdata$sectiondata.skyLight != null;
if (flag2 || flag3) {
if (!flag1) {
levellightengine.retainData(p_363624_, true);
flag1 = true;
}
if (flag2) {
levellightengine.queueSectionData(LightLayer.BLOCK, sectionpos, serializablechunkdata$sectiondata.blockLight);
}
if (flag3) {
levellightengine.queueSectionData(LightLayer.SKY, sectionpos, serializablechunkdata$sectiondata.skyLight);
}
}
}
ChunkType chunktype = this.chunkStatus.getChunkType();
ChunkAccess chunkaccess;
if (chunktype == ChunkType.LEVELCHUNK) {
LevelChunkTicks<Block> levelchunkticks = new LevelChunkTicks<>(this.packedTicks.blocks());
LevelChunkTicks<Fluid> levelchunkticks1 = new LevelChunkTicks<>(this.packedTicks.fluids());
chunkaccess = new LevelChunk(
p_368634_.getLevel(),
p_363624_,
this.upgradeData,
levelchunkticks,
levelchunkticks1,
this.inhabitedTime,
alevelchunksection,
postLoadChunk(p_368634_, this.entities, this.blockEntities),
BlendingData.unpack(this.blendingData)
);
} else {
ProtoChunkTicks<Block> protochunkticks = ProtoChunkTicks.load(this.packedTicks.blocks());
ProtoChunkTicks<Fluid> protochunkticks1 = ProtoChunkTicks.load(this.packedTicks.fluids());
ProtoChunk protochunk1 = new ProtoChunk(
p_363624_, this.upgradeData, alevelchunksection, protochunkticks, protochunkticks1, p_368634_, registry, BlendingData.unpack(this.blendingData)
);
chunkaccess = protochunk1;
protochunk1.setInhabitedTime(this.inhabitedTime);
if (this.belowZeroRetrogen != null) {
protochunk1.setBelowZeroRetrogen(this.belowZeroRetrogen);
}
protochunk1.setPersistedStatus(this.chunkStatus);
if (this.chunkStatus.isOrAfter(ChunkStatus.INITIALIZE_LIGHT)) {
protochunk1.setLightEngine(levellightengine);
}
}
chunkaccess.setLightCorrect(this.lightCorrect);
EnumSet<Heightmap.Types> enumset = EnumSet.noneOf(Heightmap.Types.class);
for (Heightmap.Types heightmap$types : chunkaccess.getPersistedStatus().heightmapsAfter()) {
long[] along = this.heightmaps.get(heightmap$types);
if (along != null) {
chunkaccess.setHeightmap(heightmap$types, along);
} else {
enumset.add(heightmap$types);
}
}
Heightmap.primeHeightmaps(chunkaccess, enumset);
chunkaccess.setAllStarts(unpackStructureStart(StructurePieceSerializationContext.fromLevel(p_368634_), this.structureData, p_368634_.getSeed()));
chunkaccess.setAllReferences(unpackStructureReferences(p_368634_.registryAccess(), p_363624_, this.structureData));
for (int j = 0; j < this.postProcessingSections.length; j++) {
chunkaccess.addPackedPostProcess(this.postProcessingSections[j], j);
}
if (chunktype == ChunkType.LEVELCHUNK) {
return new ImposterProtoChunk((LevelChunk)chunkaccess, false);
} else {
ProtoChunk protochunk = (ProtoChunk)chunkaccess;
for (CompoundTag compoundtag : this.entities) {
protochunk.addEntity(compoundtag);
}
for (CompoundTag compoundtag1 : this.blockEntities) {
protochunk.setBlockEntityNbt(compoundtag1);
}
if (this.carvingMask != null) {
protochunk.setCarvingMask(new CarvingMask(this.carvingMask, chunkaccess.getMinY()));
}
return protochunk;
}
}
private static void logErrors(ChunkPos p_362005_, int p_366847_, String p_369695_) {
LOGGER.error("Recoverable errors when loading section [{}, {}, {}]: {}", p_362005_.x, p_366847_, p_362005_.z, p_369695_);
}
private static Codec<PalettedContainerRO<Holder<Biome>>> makeBiomeCodec(Registry<Biome> p_368397_) {
return PalettedContainer.codecRO(
p_368397_.asHolderIdMap(), p_368397_.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, p_368397_.getOrThrow(Biomes.PLAINS)
);
}
public static SerializableChunkData copyOf(ServerLevel p_369088_, ChunkAccess p_363062_) {
if (!p_363062_.canBeSerialized()) {
throw new IllegalArgumentException("Chunk can't be serialized: " + p_363062_);
} else {
ChunkPos chunkpos = p_363062_.getPos();
List<SerializableChunkData.SectionData> list = new ArrayList<>();
LevelChunkSection[] alevelchunksection = p_363062_.getSections();
LevelLightEngine levellightengine = p_369088_.getChunkSource().getLightEngine();
for (int i = levellightengine.getMinLightSection(); i < levellightengine.getMaxLightSection(); i++) {
int j = p_363062_.getSectionIndexFromSectionY(i);
boolean flag = j >= 0 && j < alevelchunksection.length;
DataLayer datalayer = levellightengine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(chunkpos, i));
DataLayer datalayer1 = levellightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkpos, i));
DataLayer datalayer2 = datalayer != null && !datalayer.isEmpty() ? datalayer.copy() : null;
DataLayer datalayer3 = datalayer1 != null && !datalayer1.isEmpty() ? datalayer1.copy() : null;
if (flag || datalayer2 != null || datalayer3 != null) {
LevelChunkSection levelchunksection = flag ? alevelchunksection[j].copy() : null;
list.add(new SerializableChunkData.SectionData(i, levelchunksection, datalayer2, datalayer3));
}
}
List<CompoundTag> list1 = new ArrayList<>(p_363062_.getBlockEntitiesPos().size());
for (BlockPos blockpos : p_363062_.getBlockEntitiesPos()) {
CompoundTag compoundtag = p_363062_.getBlockEntityNbtForSaving(blockpos, p_369088_.registryAccess());
if (compoundtag != null) {
list1.add(compoundtag);
}
}
List<CompoundTag> list2 = new ArrayList<>();
long[] along = null;
if (p_363062_.getPersistedStatus().getChunkType() == ChunkType.PROTOCHUNK) {
ProtoChunk protochunk = (ProtoChunk)p_363062_;
list2.addAll(protochunk.getEntities());
CarvingMask carvingmask = protochunk.getCarvingMask();
if (carvingmask != null) {
along = carvingmask.toArray();
}
}
Map<Heightmap.Types, long[]> map = new EnumMap<>(Heightmap.Types.class);
for (Entry<Heightmap.Types, Heightmap> entry : p_363062_.getHeightmaps()) {
if (p_363062_.getPersistedStatus().heightmapsAfter().contains(entry.getKey())) {
long[] along1 = entry.getValue().getRawData();
map.put(entry.getKey(), (long[])along1.clone());
}
}
ChunkAccess.PackedTicks chunkaccess$packedticks = p_363062_.getTicksForSerialization(p_369088_.getGameTime());
ShortList[] ashortlist = Arrays.stream(p_363062_.getPostProcessing())
.map(p_366782_ -> p_366782_ != null ? new ShortArrayList(p_366782_) : null)
.toArray(ShortList[]::new);
CompoundTag compoundtag1 = packStructureData(StructurePieceSerializationContext.fromLevel(p_369088_), chunkpos, p_363062_.getAllStarts(), p_363062_.getAllReferences());
return new SerializableChunkData(
p_369088_.registryAccess().lookupOrThrow(Registries.BIOME),
chunkpos,
p_363062_.getMinSectionY(),
p_369088_.getGameTime(),
p_363062_.getInhabitedTime(),
p_363062_.getPersistedStatus(),
Optionull.map(p_363062_.getBlendingData(), BlendingData::pack),
p_363062_.getBelowZeroRetrogen(),
p_363062_.getUpgradeData().copy(),
along,
map,
chunkaccess$packedticks,
ashortlist,
p_363062_.isLightCorrect(),
list,
list2,
list1,
compoundtag1
);
}
}
public CompoundTag write() {
CompoundTag compoundtag = NbtUtils.addCurrentDataVersion(new CompoundTag());
compoundtag.putInt("xPos", this.chunkPos.x);
compoundtag.putInt("yPos", this.minSectionY);
compoundtag.putInt("zPos", this.chunkPos.z);
compoundtag.putLong("LastUpdate", this.lastUpdateTime);
compoundtag.putLong("InhabitedTime", this.inhabitedTime);
compoundtag.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
compoundtag.storeNullable("blending_data", BlendingData.Packed.CODEC, this.blendingData);
compoundtag.storeNullable("below_zero_retrogen", BelowZeroRetrogen.CODEC, this.belowZeroRetrogen);
if (!this.upgradeData.isEmpty()) {
compoundtag.put("UpgradeData", this.upgradeData.write());
}
ListTag listtag = new ListTag();
Codec<PalettedContainerRO<Holder<Biome>>> codec = makeBiomeCodec(this.biomeRegistry);
for (SerializableChunkData.SectionData serializablechunkdata$sectiondata : this.sectionData) {
CompoundTag compoundtag1 = new CompoundTag();
LevelChunkSection levelchunksection = serializablechunkdata$sectiondata.chunkSection;
if (levelchunksection != null) {
compoundtag1.store("block_states", BLOCK_STATE_CODEC, levelchunksection.getStates());
compoundtag1.store("biomes", codec, levelchunksection.getBiomes());
}
if (serializablechunkdata$sectiondata.blockLight != null) {
compoundtag1.putByteArray("BlockLight", serializablechunkdata$sectiondata.blockLight.getData());
}
if (serializablechunkdata$sectiondata.skyLight != null) {
compoundtag1.putByteArray("SkyLight", serializablechunkdata$sectiondata.skyLight.getData());
}
if (!compoundtag1.isEmpty()) {
compoundtag1.putByte("Y", (byte)serializablechunkdata$sectiondata.y);
listtag.add(compoundtag1);
}
}
compoundtag.put("sections", listtag);
if (this.lightCorrect) {
compoundtag.putBoolean("isLightOn", true);
}
ListTag listtag1 = new ListTag();
listtag1.addAll(this.blockEntities);
compoundtag.put("block_entities", listtag1);
if (this.chunkStatus.getChunkType() == ChunkType.PROTOCHUNK) {
ListTag listtag2 = new ListTag();
listtag2.addAll(this.entities);
compoundtag.put("entities", listtag2);
if (this.carvingMask != null) {
compoundtag.putLongArray("carving_mask", this.carvingMask);
}
}
saveTicks(compoundtag, this.packedTicks);
compoundtag.put("PostProcessing", packOffsets(this.postProcessingSections));
CompoundTag compoundtag2 = new CompoundTag();
this.heightmaps.forEach((p_369025_, p_369618_) -> compoundtag2.put(p_369025_.getSerializationKey(), new LongArrayTag(p_369618_)));
compoundtag.put("Heightmaps", compoundtag2);
compoundtag.put("structures", this.structureData);
return compoundtag;
}
private static void saveTicks(CompoundTag p_366243_, ChunkAccess.PackedTicks p_367613_) {
p_366243_.store("block_ticks", BLOCK_TICKS_CODEC, p_367613_.blocks());
p_366243_.store("fluid_ticks", FLUID_TICKS_CODEC, p_367613_.fluids());
}
public static ChunkStatus getChunkStatusFromTag(@Nullable CompoundTag p_392104_) {
return p_392104_ != null ? p_392104_.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY) : ChunkStatus.EMPTY;
}
@Nullable
private static LevelChunk.PostLoadProcessor postLoadChunk(ServerLevel p_367726_, List<CompoundTag> p_368624_, List<CompoundTag> p_369871_) {
return p_368624_.isEmpty() && p_369871_.isEmpty() ? null : p_361871_ -> {
if (!p_368624_.isEmpty()) {
p_367726_.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(p_368624_, p_367726_, EntitySpawnReason.LOAD));
}
for (CompoundTag compoundtag : p_369871_) {
boolean flag = compoundtag.getBooleanOr("keepPacked", false);
if (flag) {
p_361871_.setBlockEntityNbt(compoundtag);
} else {
BlockPos blockpos = BlockEntity.getPosFromTag(p_361871_.getPos(), compoundtag);
BlockEntity blockentity = BlockEntity.loadStatic(blockpos, p_361871_.getBlockState(blockpos), compoundtag, p_367726_.registryAccess());
if (blockentity != null) {
p_361871_.setBlockEntity(blockentity);
}
}
}
};
}
private static CompoundTag packStructureData(
StructurePieceSerializationContext p_365342_, ChunkPos p_366115_, Map<Structure, StructureStart> p_361842_, Map<Structure, LongSet> p_369653_
) {
CompoundTag compoundtag = new CompoundTag();
CompoundTag compoundtag1 = new CompoundTag();
Registry<Structure> registry = p_365342_.registryAccess().lookupOrThrow(Registries.STRUCTURE);
for (Entry<Structure, StructureStart> entry : p_361842_.entrySet()) {
ResourceLocation resourcelocation = registry.getKey(entry.getKey());
compoundtag1.put(resourcelocation.toString(), entry.getValue().createTag(p_365342_, p_366115_));
}
compoundtag.put("starts", compoundtag1);
CompoundTag compoundtag2 = new CompoundTag();
for (Entry<Structure, LongSet> entry1 : p_369653_.entrySet()) {
if (!entry1.getValue().isEmpty()) {
ResourceLocation resourcelocation1 = registry.getKey(entry1.getKey());
compoundtag2.putLongArray(resourcelocation1.toString(), entry1.getValue().toLongArray());
}
}
compoundtag.put("References", compoundtag2);
return compoundtag;
}
private static Map<Structure, StructureStart> unpackStructureStart(StructurePieceSerializationContext p_368168_, CompoundTag p_361005_, long p_364111_) {
Map<Structure, StructureStart> map = Maps.newHashMap();
Registry<Structure> registry = p_368168_.registryAccess().lookupOrThrow(Registries.STRUCTURE);
CompoundTag compoundtag = p_361005_.getCompoundOrEmpty("starts");
for (String s : compoundtag.keySet()) {
ResourceLocation resourcelocation = ResourceLocation.tryParse(s);
Structure structure = registry.getValue(resourcelocation);
if (structure == null) {
LOGGER.error("Unknown structure start: {}", resourcelocation);
} else {
StructureStart structurestart = StructureStart.loadStaticStart(p_368168_, compoundtag.getCompoundOrEmpty(s), p_364111_);
if (structurestart != null) {
map.put(structure, structurestart);
}
}
}
return map;
}
private static Map<Structure, LongSet> unpackStructureReferences(RegistryAccess p_360899_, ChunkPos p_366437_, CompoundTag p_368599_) {
Map<Structure, LongSet> map = Maps.newHashMap();
Registry<Structure> registry = p_360899_.lookupOrThrow(Registries.STRUCTURE);
CompoundTag compoundtag = p_368599_.getCompoundOrEmpty("References");
compoundtag.forEach((p_391028_, p_391029_) -> {
ResourceLocation resourcelocation = ResourceLocation.tryParse(p_391028_);
Structure structure = registry.getValue(resourcelocation);
if (structure == null) {
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", resourcelocation, p_366437_);
} else {
Optional<long[]> optional = p_391029_.asLongArray();
if (!optional.isEmpty()) {
map.put(structure, new LongOpenHashSet(Arrays.stream(optional.get()).filter(p_365743_ -> {
ChunkPos chunkpos = new ChunkPos(p_365743_);
if (chunkpos.getChessboardDistance(p_366437_) > 8) {
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", resourcelocation, chunkpos, p_366437_);
return false;
} else {
return true;
}
}).toArray()));
}
}
});
return map;
}
private static ListTag packOffsets(ShortList[] p_365024_) {
ListTag listtag = new ListTag();
for (ShortList shortlist : p_365024_) {
ListTag listtag1 = new ListTag();
if (shortlist != null) {
for (int i = 0; i < shortlist.size(); i++) {
listtag1.add(ShortTag.valueOf(shortlist.getShort(i)));
}
}
listtag.add(listtag1);
}
return listtag;
}
public static class ChunkReadException extends NbtException {
public ChunkReadException(String p_364016_) {
super(p_364016_);
}
}
public record SectionData(int y, @Nullable LevelChunkSection chunkSection, @Nullable DataLayer blockLight, @Nullable DataLayer skyLight) {
}
}