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:
parent
d1c95742dd
commit
66e73a2d68
@ -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);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_Coords);
|
||||
if ((Chunk == nullptr) || !Chunk->IsValid())
|
||||
{
|
||||
// The chunk is not present
|
||||
return false;
|
||||
}
|
||||
Chunk->GetAllData(a_Callback);
|
||||
|
@ -108,7 +108,9 @@ public:
|
||||
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 */
|
||||
bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks);
|
||||
@ -439,7 +441,7 @@ private:
|
||||
|
||||
typedef std::list<cChunkStay *> cChunkStays;
|
||||
|
||||
cCriticalSection m_CSChunks;
|
||||
mutable cCriticalSection m_CSChunks;
|
||||
|
||||
/** A map of chunk coordinates to chunk pointers
|
||||
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
|
||||
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 */
|
||||
|
@ -241,7 +241,7 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, std::unordered_set<cCli
|
||||
}
|
||||
|
||||
// Query and prepare chunk data:
|
||||
if (!m_World.GetChunkData(a_ChunkX, a_ChunkZ, *this))
|
||||
if (!m_World.GetChunkData({a_ChunkX, a_ChunkZ}, *this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ void cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
|
||||
for (int x = 0; x < 3; 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 x
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -234,7 +234,9 @@ public:
|
||||
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 */
|
||||
bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,139 +1,27 @@
|
||||
|
||||
// NBTChunkSerializer.h
|
||||
|
||||
// Declares the cNBTChunkSerializer class that is used for saving individual chunks into NBT format used by Anvil
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ChunkDataCallback.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cFastNBTWriter;
|
||||
class cEntity;
|
||||
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 cWorld;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cNBTChunkSerializer :
|
||||
public cChunkDataCopyCollector
|
||||
/** Saves the chunk data into a NBT format, used by the Anvil storage.
|
||||
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:
|
||||
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);
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
a_Writer.BeginCompound("Level");
|
||||
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))
|
||||
if (!NBTChunkSerializer::serialize(*m_World, a_Chunk, a_Writer))
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user