1
0

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:
madmaxoft@gmail.com 2012-03-07 22:09:55 +00:00
parent 4544d5d3b9
commit 7219e74c7c
4 changed files with 240 additions and 11 deletions

View File

@ -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 PrevIdx = 0;
size_t idx = iPath.find('\\'); size_t idx = iPath.find('\\');
cNBTTag * res = this; const cNBTTag * res = this;
while ((res != NULL) && (idx != AString::npos)) while ((res != NULL) && (idx != AString::npos))
{ {
res = res->FindChildByName(AString(iPath, PrevIdx, idx - PrevIdx)); 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) 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) 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; 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

View File

@ -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 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; } virtual cNBTTag * FindChildByName(const AString & a_Name) const {return NULL; }
cNBTTag * FindChildByPath(const AString & a_Path); const cNBTTag * FindChildByPath(const AString & a_Path) const;
} ; } ;
typedef cNBTTag cNBTTree; typedef cNBTTag cNBTTree;
@ -118,7 +118,7 @@ public:
cNBTTag * GetChildByIdx (size_t a_Index); cNBTTag * GetChildByIdx (size_t a_Index);
const cNBTTags & GetChildren (void) const {return m_Children; } const cNBTTags & GetChildren (void) const {return m_Children; }
size_t GetChildrenCount(void) const {return m_Children.size(); } 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 int SetChildrenType(eTagType a_Type); // Only valid when list empty
eTagType GetChildrenType(void) const {return m_ChildrenType; } eTagType GetChildrenType(void) const {return m_ChildrenType; }
@ -142,7 +142,7 @@ public:
cNBTTag * GetChildByIdx (size_t a_Index); cNBTTag * GetChildByIdx (size_t a_Index);
const cNBTTags & GetChildren (void) const {return m_Children; } const cNBTTags & GetChildren (void) const {return m_Children; }
size_t GetChildrenCount(void) const {return m_Children.size(); } 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

View File

@ -9,6 +9,8 @@
#include "zlib.h" #include "zlib.h"
#include "NBT.h" #include "NBT.h"
#include "BlockID.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; cEntityList Entities;
cBlockEntityList BlockEntities; 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: // 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]; 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: // cWSSAnvil::cMCAFile:

View File

@ -26,6 +26,8 @@ enum
// fwd: "NBT.h" // fwd: "NBT.h"
class cNBTTag; class cNBTTag;
class cNBTList;
class cNBTCompound;
@ -81,6 +83,17 @@ protected:
/// Loads the chunk from NBT data (no locking needed) /// Loads the chunk from NBT data (no locking needed)
bool LoadChunkFromNBT(const cChunkCoords & a_Chunk, cNBTTag & a_NBT); 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 /// 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); cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk);