Anvil format: loading chests' contents.
git-svn-id: http://mc-server.googlecode.com/svn/trunk@385 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
4544d5d3b9
commit
7219e74c7c
@ -88,11 +88,11 @@ cNBTTag * cNBTTag::CreateTag(cNBTTag * a_Parent, eTagType a_Type, const AString
|
||||
|
||||
|
||||
|
||||
cNBTTag * cNBTTag::FindChildByPath(const AString & iPath)
|
||||
const cNBTTag * cNBTTag::FindChildByPath(const AString & iPath) const
|
||||
{
|
||||
size_t PrevIdx = 0;
|
||||
size_t idx = iPath.find('\\');
|
||||
cNBTTag * res = this;
|
||||
const cNBTTag * res = this;
|
||||
while ((res != NULL) && (idx != AString::npos))
|
||||
{
|
||||
res = res->FindChildByName(AString(iPath, PrevIdx, idx - PrevIdx));
|
||||
@ -191,9 +191,9 @@ cNBTTag * cNBTList::GetChildByIdx(size_t iIndex)
|
||||
|
||||
|
||||
|
||||
cNBTTag * cNBTList::FindChildByName(const AString & a_Name)
|
||||
cNBTTag * cNBTList::FindChildByName(const AString & a_Name) const
|
||||
{
|
||||
for (cNBTTags::iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
||||
for (cNBTTags::const_iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetName() == a_Name)
|
||||
{
|
||||
@ -260,9 +260,9 @@ cNBTTag * cNBTCompound::GetChildByIdx(size_t iIndex)
|
||||
|
||||
|
||||
|
||||
cNBTTag * cNBTCompound::FindChildByName(const AString & a_Name)
|
||||
cNBTTag * cNBTCompound::FindChildByName(const AString & a_Name) const
|
||||
{
|
||||
for (cNBTTags::iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
||||
for (cNBTTags::const_iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetName() == a_Name)
|
||||
{
|
||||
@ -580,6 +580,7 @@ int cNBTParser::ReadTag(const char ** a_Data, int * a_Length, cNBTTag::eTagType
|
||||
return ERROR_PRIVATE_NBTPARSER_BADTYPE;
|
||||
}
|
||||
|
||||
#undef CASE_SIMPLE_TAG
|
||||
|
||||
|
||||
|
||||
@ -618,3 +619,85 @@ cNBTTree * cNBTParser::Parse(const char * a_Data, int a_Length)
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Dumping the NBT tree (debug-only)
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#define CASE_SIMPLE_TAG(TYPE,FMT) \
|
||||
case cNBTTag::TAG_##TYPE: \
|
||||
{ \
|
||||
AString out; \
|
||||
Printf(out, "%sTAG_" TEXT(#TYPE) TEXT("(\"%hs\"): %") TEXT(FMT) TEXT("\n"), Indent.c_str(), a_Tree->GetName().c_str(), ((cNBT##TYPE *)a_Tree)->m_Value); \
|
||||
OutputDebugString(out.c_str()); \
|
||||
break; \
|
||||
}
|
||||
|
||||
void DumpTree(const cNBTTree * a_Tree, int a_Level)
|
||||
{
|
||||
AString Indent(a_Level, TEXT(' '));
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
switch (a_Tree->GetType())
|
||||
{
|
||||
CASE_SIMPLE_TAG(Byte, "d")
|
||||
CASE_SIMPLE_TAG(Short, "d")
|
||||
CASE_SIMPLE_TAG(Int, "d")
|
||||
CASE_SIMPLE_TAG(Long, "I64d")
|
||||
CASE_SIMPLE_TAG(Float, "f")
|
||||
CASE_SIMPLE_TAG(Double, "f")
|
||||
|
||||
case cNBTTag::TAG_ByteArray:
|
||||
{
|
||||
AString out;
|
||||
Printf(out, "%sTAG_ByteArray(\"%hs\"): %d bytes\n", Indent.c_str(), a_Tree->GetName().c_str(), ((cNBTByteArray *)a_Tree)->m_Value.size());
|
||||
OutputDebugString(out.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case cNBTTag::TAG_String:
|
||||
{
|
||||
AString out;
|
||||
Printf(out, "%sTAG_String(\"%hs\"): %d bytes: \"%hs\"\n", Indent.c_str(), a_Tree->GetName().c_str(), ((cNBTString *)a_Tree)->m_Value.size(), ((cNBTString *)a_Tree)->m_Value.c_str());
|
||||
OutputDebugString(out.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case cNBTTag::TAG_List:
|
||||
{
|
||||
const cNBTTags & Children = ((cNBTList *)a_Tree)->GetChildren();
|
||||
AString out;
|
||||
Printf(out, "%sTAG_List(\"%hs\"): %d items of type %d\n%s{\n", Indent.c_str(), a_Tree->GetName().c_str(), Children.size(), ((cNBTList *)a_Tree)->GetChildrenType(), Indent.c_str());
|
||||
OutputDebugString(out.c_str());
|
||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
||||
{
|
||||
DumpTree(*itr, a_Level + 1);
|
||||
} // for itr - Children[]
|
||||
Printf(out, "%s}\n", Indent.c_str());
|
||||
OutputDebugString(out.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case cNBTTag::TAG_Compound:
|
||||
{
|
||||
const cNBTTags & Children = ((cNBTCompound *)a_Tree)->GetChildren();
|
||||
AString out;
|
||||
Printf(out, "%sTAG_Compound(\"%hs\"): %d items\n%s{\n", Indent.c_str(), a_Tree->GetName().c_str(), Children.size(), Indent.c_str());
|
||||
OutputDebugString(out.c_str());
|
||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
||||
{
|
||||
DumpTree(*itr, a_Level + 1);
|
||||
} // for itr - Children[]
|
||||
Printf(out, "%s}\n", Indent.c_str());
|
||||
OutputDebugString(out.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CASE_SIMPLE_TAG
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
|
||||
|
||||
|
19
source/NBT.h
19
source/NBT.h
@ -62,8 +62,8 @@ public:
|
||||
|
||||
static cNBTTag * CreateTag(cNBTTag * a_Parent, eTagType a_Type, const AString & a_Name); // Creates a new instance of a tag specified by iType, uses the correct class
|
||||
|
||||
virtual cNBTTag * FindChildByName(const AString & a_Name) {return NULL; }
|
||||
cNBTTag * FindChildByPath(const AString & a_Path);
|
||||
virtual cNBTTag * FindChildByName(const AString & a_Name) const {return NULL; }
|
||||
const cNBTTag * FindChildByPath(const AString & a_Path) const;
|
||||
} ;
|
||||
|
||||
typedef cNBTTag cNBTTree;
|
||||
@ -118,7 +118,7 @@ public:
|
||||
cNBTTag * GetChildByIdx (size_t a_Index);
|
||||
const cNBTTags & GetChildren (void) const {return m_Children; }
|
||||
size_t GetChildrenCount(void) const {return m_Children.size(); }
|
||||
virtual cNBTTag * FindChildByName (const AString & a_Name) override;
|
||||
virtual cNBTTag * FindChildByName (const AString & a_Name) const override;
|
||||
|
||||
int SetChildrenType(eTagType a_Type); // Only valid when list empty
|
||||
eTagType GetChildrenType(void) const {return m_ChildrenType; }
|
||||
@ -142,7 +142,7 @@ public:
|
||||
cNBTTag * GetChildByIdx (size_t a_Index);
|
||||
const cNBTTags & GetChildren (void) const {return m_Children; }
|
||||
size_t GetChildrenCount(void) const {return m_Children.size(); }
|
||||
virtual cNBTTag * FindChildByName (const AString & a_Name) override;
|
||||
virtual cNBTTag * FindChildByName (const AString & a_Name) const override;
|
||||
} ;
|
||||
|
||||
|
||||
@ -199,3 +199,14 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Dumping the tree (DEBUG-only)
|
||||
|
||||
#ifdef _DEBUG
|
||||
void DumpTree(const cNBTTree * a_Tree, int a_Level = 0);
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "zlib.h"
|
||||
#include "NBT.h"
|
||||
#include "BlockID.h"
|
||||
#include "cChestEntity.h"
|
||||
#include "cItem.h"
|
||||
|
||||
|
||||
|
||||
@ -219,7 +221,9 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, cNBTTag & a_NBT)
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
|
||||
// TODO: Load the entities from NBT
|
||||
// Load the entities from NBT:
|
||||
LoadEntitiesFromNBT (Entities, (cNBTList *)(a_NBT.FindChildByPath("Level\\Entities")));
|
||||
LoadBlockEntitiesFromNBT(BlockEntities, (cNBTList *)(a_NBT.FindChildByPath("Level\\TileEntities")));
|
||||
|
||||
// Reorder the chunk data - walk the MCA-formatted data sequentially and copy it into the right place in the ChunkData:
|
||||
char ChunkData[cChunk::c_BlockDataSize];
|
||||
@ -260,6 +264,124 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, cNBTTag & a_NBT)
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entitites, const cNBTList * a_NBT)
|
||||
{
|
||||
// TODO: Load the entities
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, const cNBTList * a_NBT)
|
||||
{
|
||||
if ((a_NBT == NULL) || (a_NBT->GetType() != cNBTTag::TAG_List))
|
||||
{
|
||||
return;
|
||||
}
|
||||
const cNBTTags & Tags = a_NBT->GetChildren();
|
||||
|
||||
for (cNBTTags::const_iterator itr = Tags.begin(); itr != Tags.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetType() != cNBTTag::TAG_Compound)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cNBTString * sID = (cNBTString *)((*itr)->FindChildByName("id"));
|
||||
if (sID == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sID->m_Value == "Chest")
|
||||
{
|
||||
LoadChestFromNBT(a_BlockEntities, (cNBTCompound *)(*itr));
|
||||
}
|
||||
// TODO: Other block entities
|
||||
} // for itr - Tags[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cNBTCompound * a_NBT)
|
||||
{
|
||||
ASSERT(a_NBT != NULL);
|
||||
ASSERT(a_NBT->GetType() == cNBTTag::TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, x, y, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
cNBTList * Items = (cNBTList *)(a_NBT->FindChildByName("Items"));
|
||||
if ((Items == NULL) || (Items->GetType() != cNBTTag::TAG_List))
|
||||
{
|
||||
return; // Make it an empty chest
|
||||
}
|
||||
std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World));
|
||||
const cNBTTags & ItemDefs = Items->GetChildren();
|
||||
for (cNBTTags::const_iterator itr = ItemDefs.begin(); itr != ItemDefs.end(); ++itr)
|
||||
{
|
||||
cNBTByte * Slot = (cNBTByte *)((*itr)->FindChildByName("Slot"));
|
||||
if ((Slot == NULL) || (Slot->GetType() != cNBTTag::TAG_Byte))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cItem Item;
|
||||
cNBTShort * ID = (cNBTShort *)((*itr)->FindChildByName("id"));
|
||||
if ((ID == NULL) || (ID->GetType() != cNBTTag::TAG_Short))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Item.m_ItemID = (ENUM_ITEM_ID)(ID->m_Value);
|
||||
cNBTShort * Damage = (cNBTShort *)((*itr)->FindChildByName("Damage"));
|
||||
if ((Damage == NULL) || (Damage->GetType() != cNBTTag::TAG_Short))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Item.m_ItemHealth = Damage->m_Value;
|
||||
cNBTByte * Count = (cNBTByte *)((*itr)->FindChildByName("Count"));
|
||||
if ((Count == NULL) || (Count->GetType() != cNBTTag::TAG_Byte))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Item.m_ItemCount = Count->m_Value;
|
||||
Chest->SetSlot(Slot->m_Value, Item);
|
||||
} // for itr - ItemDefs[]
|
||||
a_BlockEntities.push_back(Chest.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::GetBlockEntityNBTPos(const cNBTCompound * a_NBT, int & a_X, int & a_Y, int & a_Z)
|
||||
{
|
||||
cNBTInt * x = (cNBTInt *)(a_NBT->FindChildByName("x"));
|
||||
if ((x == NULL) || (x->GetType() != cNBTTag::TAG_Int))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
cNBTInt * y = (cNBTInt *)(a_NBT->FindChildByName("y"));
|
||||
if ((y == NULL) || (y->GetType() != cNBTTag::TAG_Int))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
cNBTInt * z = (cNBTInt *)(a_NBT->FindChildByName("z"));
|
||||
if ((z == NULL) || (z->GetType() != cNBTTag::TAG_Int))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_X = x->m_Value;
|
||||
a_Y = y->m_Value;
|
||||
a_Z = z->m_Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWSSAnvil::cMCAFile:
|
||||
|
||||
|
@ -26,6 +26,8 @@ enum
|
||||
|
||||
// fwd: "NBT.h"
|
||||
class cNBTTag;
|
||||
class cNBTList;
|
||||
class cNBTCompound;
|
||||
|
||||
|
||||
|
||||
@ -81,6 +83,17 @@ protected:
|
||||
/// Loads the chunk from NBT data (no locking needed)
|
||||
bool LoadChunkFromNBT(const cChunkCoords & a_Chunk, cNBTTag & a_NBT);
|
||||
|
||||
/// Loads the chunk's entities from NBT data (a_NBT is the Level\\Entities list tag; may be NULL)
|
||||
void LoadEntitiesFromNBT(cEntityList & a_Entitites, const cNBTList * a_NBT);
|
||||
|
||||
/// Loads the chunk's BlockEntities from NBT data (a_NBT is the Level\\TileEntities list tag; may be NULL)
|
||||
void LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntitites, const cNBTList * a_NBT);
|
||||
|
||||
void LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cNBTCompound * a_NBT);
|
||||
|
||||
/// Helper function for extracting the X, Y, and Z int subtags of a NBT compound; returns true if successful
|
||||
bool GetBlockEntityNBTPos(const cNBTCompound * a_NBT, int & a_X, int & a_Y, int & a_Z);
|
||||
|
||||
/// Gets the correct MCA file either from cache or from disk, manages the m_MCAFiles cache; assumes m_CS is locked
|
||||
cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user