1
0
Fork 0

NBTChunkSerializer: Cleaned up interface.

Removed dependency on cChunkDataCallback.
Moved all the serializing code into a worker class.
Changed the serialization into a single-call action.
This commit is contained in:
Mattes D 2019-09-24 14:20:50 +02:00
parent d1c95742dd
commit 66e73a2d68
9 changed files with 1119 additions and 1170 deletions

View File

@ -444,12 +444,18 @@ void cChunkMap::ChunkLighted(
bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) bool cChunkMap::GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback)
{ {
if (!a_Callback.Coords(a_Coords.m_ChunkX, a_Coords.m_ChunkZ))
{
// The callback doesn't want the data
return false;
}
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_Coords);
if ((Chunk == nullptr) || !Chunk->IsValid()) if ((Chunk == nullptr) || !Chunk->IsValid())
{ {
// The chunk is not present
return false; return false;
} }
Chunk->GetAllData(a_Callback); Chunk->GetAllData(a_Callback);

View File

@ -108,7 +108,9 @@ public:
const cChunkDef::BlockNibbles & a_SkyLight const cChunkDef::BlockNibbles & a_SkyLight
); );
bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); /** Calls the callback with the chunk's data, if available (with ChunkCS locked).
Returns true if the chunk was reported successfully, false if not (chunk not present or callback failed). */
bool GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback);
/** Copies the chunk's blocktypes into a_Blocks; returns true if successful */ /** Copies the chunk's blocktypes into a_Blocks; returns true if successful */
bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks); bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks);
@ -439,7 +441,7 @@ private:
typedef std::list<cChunkStay *> cChunkStays; typedef std::list<cChunkStay *> cChunkStays;
cCriticalSection m_CSChunks; mutable cCriticalSection m_CSChunks;
/** A map of chunk coordinates to chunk pointers /** A map of chunk coordinates to chunk pointers
Uses a map (as opposed to unordered_map) because sorted maps are apparently faster */ Uses a map (as opposed to unordered_map) because sorted maps are apparently faster */
@ -468,7 +470,7 @@ private:
// Deprecated in favor of the vector version // Deprecated in favor of the vector version
cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ) cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ)
{ {
return GetChunkNoGen(cChunkCoords(a_ChunkX, a_ChunkZ)); return GetChunkNoGen({a_ChunkX, a_ChunkZ});
} }
/** Constructs a chunk, returning it. Doesn't load, doesn't generate */ /** Constructs a chunk, returning it. Doesn't load, doesn't generate */

View File

@ -241,7 +241,7 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, std::unordered_set<cCli
} }
// Query and prepare chunk data: // Query and prepare chunk data:
if (!m_World.GetChunkData(a_ChunkX, a_ChunkZ, *this)) if (!m_World.GetChunkData({a_ChunkX, a_ChunkZ}, *this))
{ {
return; return;
} }

View File

@ -336,7 +336,7 @@ void cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
for (int x = 0; x < 3; x++) for (int x = 0; x < 3; x++)
{ {
Reader.m_ReadingChunkX = x; Reader.m_ReadingChunkX = x;
VERIFY(m_World.GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader)); VERIFY(m_World.GetChunkData({a_ChunkX + x - 1, a_ChunkZ + z - 1}, Reader));
} // for z } // for z
} // for x } // for x

View File

@ -2636,9 +2636,9 @@ void cWorld::ChunkLighted(
bool cWorld::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) bool cWorld::GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback) const
{ {
return m_ChunkMap->GetChunkData(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->GetChunkData(a_Coords, a_Callback);
} }

View File

@ -234,7 +234,9 @@ public:
const cChunkDef::BlockNibbles & a_SkyLight const cChunkDef::BlockNibbles & a_SkyLight
); );
bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); /** Calls the callback with the chunk's data, if available (with ChunkCS locked).
Returns true if the chunk was reported successfully, false if not (chunk not present or callback failed). */
bool GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback) const;
/** Gets the chunk's blocks, only the block types */ /** Gets the chunk's blocks, only the block types */
bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);

File diff suppressed because it is too large Load Diff

View File

@ -1,139 +1,27 @@
// NBTChunkSerializer.h // NBTChunkSerializer.h
// Declares the cNBTChunkSerializer class that is used for saving individual chunks into NBT format used by Anvil
#pragma once #pragma once
#include "../ChunkDataCallback.h"
// fwd: // fwd:
class cFastNBTWriter; class cFastNBTWriter;
class cEntity; class cWorld;
class cBlockEntity;
class cBoat;
class cBeaconEntity;
class cBedEntity;
class cBrewingstandEntity;
class cChestEntity;
class cCommandBlockEntity;
class cDispenserEntity;
class cDropperEntity;
class cEnderCrystal;
class cFurnaceEntity;
class cHopperEntity;
class cJukeboxEntity;
class cNoteEntity;
class cSignEntity;
class cMobHeadEntity;
class cMobSpawnerEntity;
class cFlowerPotEntity;
class cFallingBlock;
class cMinecart;
class cMinecartWithChest;
class cMonster;
class cPickup;
class cItemGrid;
class cProjectileEntity;
class cTNTEntity;
class cExpOrb;
class cHangingEntity;
class cItemFrame;
class cLeashKnot;
class cPainting;
class cNBTChunkSerializer : /** Saves the chunk data into a NBT format, used by the Anvil storage.
public cChunkDataCopyCollector The Writer is expected to be set up so that the serializer can write the chunk's top level "Level" NBT tag immediately.
Provides a single static entry point that does all the work, through a hidden worker class in the CPP file. */
class NBTChunkSerializer
{ {
public: public:
cChunkDef::BiomeMap m_Biomes;
unsigned char m_VanillaBiomes[cChunkDef::Width * cChunkDef::Width];
int m_VanillaHeightMap[cChunkDef::Width * cChunkDef::Width];
bool m_BiomesAreValid;
cNBTChunkSerializer(cFastNBTWriter & a_Writer);
/** Close NBT tags that we've opened */
void Finish(void);
bool IsLightValid(void) const { return m_IsLightValid; }
protected:
/* From cChunkDataCopyCollector we inherit:
- cChunkData m_Data */
cFastNBTWriter & m_Writer;
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
bool m_HasHadEntity; // True if any Entity has already been received and processed
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
bool m_IsLightValid; // True if the chunk lighting is valid
/** Writes an item into the writer, if slot >= 0, adds the Slot tag. The compound is named as requested. */
void AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName = "");
/** Writes an item grid into the writer; begins the stored slot numbers with a_BeginSlotNum. Note that it doesn't begin nor end the list tag */
void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0);
// Block entities:
void AddBasicTileEntity (cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddBeaconEntity (cBeaconEntity * a_Entity);
void AddBedEntity (cBedEntity * a_Entity);
void AddBrewingstandEntity(cBrewingstandEntity * a_Brewingstand);
void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType);
void AddDispenserEntity (cDispenserEntity * a_Entity);
void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity (cFurnaceEntity * a_Furnace);
void AddHopperEntity (cHopperEntity * a_Entity);
void AddJukeboxEntity (cJukeboxEntity * a_Jukebox);
void AddMobSpawnerEntity (cMobSpawnerEntity * a_MobSpawner);
void AddNoteEntity (cNoteEntity * a_Note);
void AddSignEntity (cSignEntity * a_Sign);
void AddMobHeadEntity (cMobHeadEntity * a_MobHead);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
void AddFlowerPotEntity (cFlowerPotEntity * a_FlowerPot);
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
void AddBoatEntity (cBoat * a_Boat);
void AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal);
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
void AddHangingEntity (cHangingEntity * a_Hanging);
void AddTNTEntity (cTNTEntity * a_TNT);
void AddExpOrbEntity (cExpOrb * a_ExpOrb);
void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddLeashKnotEntity (cLeashKnot * a_LeashKnot);
void AddPaintingEntity (cPainting * a_Painting);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides:
virtual void LightIsValid(bool a_IsLightValid) override;
virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
} ; // class cNBTChunkSerializer
/** Serializes the chunk into the specified writer.
Returns true on success, false on failure (chunk not present etc.) */
static bool serialize(const cWorld & aWorld, cChunkCoords aCoords, cFastNBTWriter & aWriter);
};

View File

@ -491,68 +491,11 @@ void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString &
bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer) bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer)
{ {
a_Writer.BeginCompound("Level"); if (!NBTChunkSerializer::serialize(*m_World, a_Chunk, a_Writer))
a_Writer.AddInt("xPos", a_Chunk.m_ChunkX);
a_Writer.AddInt("zPos", a_Chunk.m_ChunkZ);
cNBTChunkSerializer Serializer(a_Writer);
if (!m_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer))
{ {
LOGWARNING("Cannot get chunk [%d, %d] data for NBT saving", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); LOGWARNING("Failed to save chunk %s.", a_Chunk.ToString());
return false; return false;
} }
Serializer.Finish(); // Close NBT tags
// Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray):
if (Serializer.m_BiomesAreValid)
{
a_Writer.AddByteArray("Biomes", reinterpret_cast<const char *>(Serializer.m_VanillaBiomes), ARRAYCOUNT(Serializer.m_VanillaBiomes));
a_Writer.AddIntArray ("MCSBiomes", reinterpret_cast<const int *>(Serializer.m_Biomes), ARRAYCOUNT(Serializer.m_Biomes));
}
// Save heightmap (Vanilla require this):
a_Writer.AddIntArray("HeightMap", reinterpret_cast<const int *>(Serializer.m_VanillaHeightMap), ARRAYCOUNT(Serializer.m_VanillaHeightMap));
// Save blockdata:
a_Writer.BeginList("Sections", TAG_Compound);
for (size_t Y = 0; Y != cChunkData::NumSections; ++Y)
{
auto Section = Serializer.m_Data.GetSection(Y);
if (Section == nullptr)
{
continue;
}
a_Writer.BeginCompound("");
a_Writer.AddByteArray("Blocks", reinterpret_cast<const char *>(Section->m_BlockTypes), ARRAYCOUNT(Section->m_BlockTypes));
a_Writer.AddByteArray("Data", reinterpret_cast<const char *>(Section->m_BlockMetas), ARRAYCOUNT(Section->m_BlockMetas));
#ifdef DEBUG_SKYLIGHT
a_Writer.AddByteArray("BlockLight", reinterpret_cast<const char *>(Section->m_BlockSkyLight), ARRAYCOUNT(Section->m_BlockSkyLight));
#else
a_Writer.AddByteArray("BlockLight", reinterpret_cast<const char *>(Section->m_BlockLight), ARRAYCOUNT(Section->m_BlockLight));
#endif
a_Writer.AddByteArray("SkyLight", reinterpret_cast<const char *>(Section->m_BlockSkyLight), ARRAYCOUNT(Section->m_BlockSkyLight));
a_Writer.AddByte("Y", static_cast<unsigned char>(Y));
a_Writer.EndCompound();
}
a_Writer.EndList(); // "Sections"
// Store the information that the lighting is valid.
// For compatibility reason, the default is "invalid" (missing) - this means older data is re-lighted upon loading.
if (Serializer.IsLightValid())
{
a_Writer.AddByte("MCSIsLightValid", 1);
}
// Save the world age to the chunk data. Required by vanilla and mcedit.
a_Writer.AddLong("LastUpdate", m_World->GetWorldAge());
// Store the flag that the chunk has all the ores, trees, dungeons etc. MCS chunks are always complete.
a_Writer.AddByte("TerrainPopulated", 1);
a_Writer.EndCompound(); // "Level"
return true; return true;
} }