From 868cd94ee9a5a0638c014a4cc42224f01ff234c8 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 5 Mar 2021 13:03:55 +0000 Subject: Prepare ChunkData for BlockState storage (#5105) * Rename ChunkData Creatable test * Add missing Y-check in RedstoneWireHandler * Remove ChunkDef.h dependency in Scoreboard * Prepare ChunkData for BlockState storage + Split chunk block, meta, block & sky light storage + Load the height map from disk - Reduce duplicated code in ChunkData - Remove saving MCSBiomes, there aren't any - Remove the allocation pool, ref #4315, #3864 * fixed build * fixed test * fixed the debug compile Co-authored-by: 12xx12 <44411062+12xx12@users.noreply.github.com> --- src/WorldStorage/WSSAnvil.cpp | 188 ++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 88 deletions(-) (limited to 'src/WorldStorage/WSSAnvil.cpp') diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 78320d636..e2a9b1539 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -353,16 +353,7 @@ Compression::Result cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk) bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT, const ContiguousByteBufferView a_RawChunkData) { - // The data arrays, in MCA-native y / z / x ordering (will be reordered for the final chunk data) - cChunkDef::BlockTypes BlockTypes; - cChunkDef::BlockNibbles MetaData; - cChunkDef::BlockNibbles BlockLight; - cChunkDef::BlockNibbles SkyLight; - - memset(BlockTypes, 0, sizeof(BlockTypes)); - memset(MetaData, 0, sizeof(MetaData)); - memset(SkyLight, 0xff, sizeof(SkyLight)); // By default, data not present in the NBT means air, which means full skylight - memset(BlockLight, 0x00, sizeof(BlockLight)); + struct SetChunkData Data(a_Chunk); // Load the blockdata, blocklight and skylight: int Level = a_NBT.FindChildByName(0, "Level"); @@ -371,12 +362,14 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing NBT tag: Level", a_RawChunkData); return false; } + int Sections = a_NBT.FindChildByName(Level, "Sections"); if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List)) { ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing NBT tag: Sections", a_RawChunkData); return false; } + eTagType SectionsType = a_NBT.GetChildrenType(Sections); if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End)) { @@ -385,39 +378,56 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child)) { - int y = 0; - int SectionY = a_NBT.FindChildByName(Child, "Y"); - if ((SectionY < 0) || (a_NBT.GetType(SectionY) != TAG_Byte)) + const int SectionYTag = a_NBT.FindChildByName(Child, "Y"); + if ((SectionYTag < 0) || (a_NBT.GetType(SectionYTag) != TAG_Byte)) { - continue; + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT tag missing or has wrong: Y", a_RawChunkData); + return false; } - y = a_NBT.GetByte(SectionY); - if ((y < 0) || (y > 15)) + + const int Y = a_NBT.GetByte(SectionYTag); + if ((Y < 0) || (Y > static_cast(cChunkDef::NumSections - 1))) { - continue; + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT tag exceeds chunk bounds: Y", a_RawChunkData); + return false; + } + + const auto + BlockData = GetSectionData(a_NBT, Child, "Blocks", ChunkBlockData::SectionBlockCount), + MetaData = GetSectionData(a_NBT, Child, "Data", ChunkBlockData::SectionMetaCount), + BlockLightData = GetSectionData(a_NBT, Child, "BlockLight", ChunkLightData::SectionLightCount), + SkyLightData = GetSectionData(a_NBT, Child, "SkyLight", ChunkLightData::SectionLightCount); + if ((BlockData != nullptr) && (MetaData != nullptr) && (SkyLightData != nullptr) && (BlockLightData != nullptr)) + { + Data.BlockData.SetSection(*reinterpret_cast(BlockData), *reinterpret_cast(MetaData), static_cast(Y)); + Data.LightData.SetSection(*reinterpret_cast(BlockLightData), *reinterpret_cast(SkyLightData), static_cast(Y)); + } + else + { + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk block/light data", a_RawChunkData); + return false; } - CopyNBTData(a_NBT, Child, "Blocks", reinterpret_cast(&(BlockTypes[y * 4096])), 4096); - CopyNBTData(a_NBT, Child, "Data", reinterpret_cast(&(MetaData[y * 2048])), 2048); - CopyNBTData(a_NBT, Child, "SkyLight", reinterpret_cast(&(SkyLight[y * 2048])), 2048); - CopyNBTData(a_NBT, Child, "BlockLight", reinterpret_cast(&(BlockLight[y * 2048])), 2048); } // for itr - LevelSections[] - // Load the biomes from NBT, if present and valid. First try MCS-style, then Vanilla-style: - cChunkDef::BiomeMap BiomeMap; - cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "MCSBiomes")); - if (Biomes == nullptr) + // Load the biomes from NBT, if present and valid: + if (!LoadBiomeMapFromNBT(Data.BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes"))) + { + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk biome data", a_RawChunkData); + return false; + } + + // Height map too: + if (!LoadHeightMapFromNBT(Data.HeightMap, a_NBT, a_NBT.FindChildByName(Level, "HeightMap"))) { - // MCS-style biomes not available, load vanilla-style: - Biomes = LoadVanillaBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")); + ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk height data", a_RawChunkData); + return false; } // Load the entities from NBT: - cEntityList Entities; - cBlockEntities BlockEntities; - LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities")); - LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"), BlockTypes, MetaData); + LoadEntitiesFromNBT (Data.Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities")); + LoadBlockEntitiesFromNBT(Data.BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"), Data.BlockData); - bool IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0); + Data.IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0); /* // Uncomment this block for really cool stuff :) @@ -455,16 +465,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } // for y //*/ - auto SetChunkData = std::make_unique( - a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, - BlockTypes, MetaData, - IsLightValid ? BlockLight : nullptr, - IsLightValid ? SkyLight : nullptr, - nullptr, Biomes, - std::move(Entities), std::move(BlockEntities), - false - ); - m_World->QueueSetChunkData(std::move(SetChunkData)); + m_World->QueueSetChunkData(std::move(Data)); return true; } @@ -472,69 +473,66 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT -void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length) +bool cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap & a_BiomeMap, const cParsedNBT & a_NBT, const int a_TagIdx) { - int Child = a_NBT.FindChildByName(a_Tag, a_ChildName); - if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length)) + if ( + (a_TagIdx < 0) || + (a_NBT.GetType(a_TagIdx) != TAG_ByteArray) || + (a_NBT.GetDataLength(a_TagIdx) != std::size(a_BiomeMap)) + ) { - memcpy(a_Destination, a_NBT.GetData(Child), a_Length); + return false; } -} - - - - -cChunkDef::BiomeMap * cWSSAnvil::LoadVanillaBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx) -{ - if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_ByteArray)) - { - return nullptr; - } - if (a_NBT.GetDataLength(a_TagIdx) != 16 * 16) + const auto * const BiomeData = a_NBT.GetData(a_TagIdx); + for (size_t i = 0; i < ARRAYCOUNT(a_BiomeMap); i++) { - // The biomes stored don't match in size - return nullptr; - } - const unsigned char * VanillaBiomeData = reinterpret_cast(a_NBT.GetData(a_TagIdx)); - for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++) - { - if ((VanillaBiomeData)[i] == 0xff) + if (BiomeData[i] > std::byte(EMCSBiome::biMaxVariantBiome)) { - // Unassigned biomes - return nullptr; + // Unassigned biomes: + return false; } - (*a_BiomeMap)[i] = static_cast(VanillaBiomeData[i]); + + a_BiomeMap[i] = static_cast(BiomeData[i]); } - return a_BiomeMap; + + return true; } -cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx) +bool cWSSAnvil::LoadHeightMapFromNBT(cChunkDef::HeightMap & a_HeightMap, const cParsedNBT & a_NBT, const int a_TagIdx) { - if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_IntArray)) + if ( + (a_TagIdx < 0) || + (a_NBT.GetType(a_TagIdx) != TAG_IntArray) || + (a_NBT.GetDataLength(a_TagIdx) != (4 * std::size(a_HeightMap))) + ) { - return nullptr; - } - if (a_NBT.GetDataLength(a_TagIdx) != sizeof(*a_BiomeMap)) - { - // The biomes stored don't match in size - return nullptr; + return false; } - const auto * BiomeData = a_NBT.GetData(a_TagIdx); - for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++) + + const auto * const HeightData = a_NBT.GetData(a_TagIdx); + for (int RelZ = 0; RelZ < cChunkDef::Width; RelZ++) { - (*a_BiomeMap)[i] = static_cast(GetBEInt(&BiomeData[i * 4])); - if ((*a_BiomeMap)[i] == 0xff) + for (int RelX = 0; RelX < cChunkDef::Width; RelX++) { - // Unassigned biomes - return nullptr; + const int Index = 4 * (RelX + RelZ * cChunkDef::Width); + const int Height = GetBEInt(HeightData + Index); + + if (Height > std::numeric_limits::max()) + { + // Invalid data: + return false; + } + + cChunkDef::SetHeight(a_HeightMap, RelX, RelZ, static_cast(Height)); } } - return a_BiomeMap; + + return true; } @@ -575,7 +573,7 @@ void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entities, const cParsedNBT & -void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntities & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas) +void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntities & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, const ChunkBlockData & a_BlockData) { if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List)) { @@ -596,11 +594,11 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntities & a_BlockEntities, const LOGWARNING("Bad block entity, missing the coords. Will be ignored."); continue; } - auto relPos = cChunkDef::AbsoluteToRelative(absPos); + const auto relPos = cChunkDef::AbsoluteToRelative(absPos); // Load the proper BlockEntity type based on the block type: - BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, relPos); - NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, relPos); + const auto BlockType = a_BlockData.GetBlock(relPos); + const auto BlockMeta = a_BlockData.GetMeta(relPos); OwnedBlockEntity Entity; try @@ -3990,6 +3988,20 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, ContiguousB +const std::byte * cWSSAnvil::GetSectionData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, size_t a_Length) +{ + int Child = a_NBT.FindChildByName(a_Tag, a_ChildName); + if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length)) + { + return a_NBT.GetData(Child); + } + return nullptr; +} + + + + + bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const ContiguousByteBufferView a_Data) { if (!OpenFile(false)) -- cgit v1.2.3