summaryrefslogtreecommitdiffstats
path: root/src/WorldStorage
diff options
context:
space:
mode:
Diffstat (limited to 'src/WorldStorage')
-rw-r--r--src/WorldStorage/FastNBT.h14
-rw-r--r--src/WorldStorage/MapSerializer.cpp276
-rw-r--r--src/WorldStorage/MapSerializer.h86
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp8
-rw-r--r--src/WorldStorage/WSSAnvil.cpp183
-rw-r--r--src/WorldStorage/WSSAnvil.h7
6 files changed, 572 insertions, 2 deletions
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index b84eda1a1..49f97c458 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -172,8 +172,18 @@ public:
inline float GetFloat(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Float);
- Int32 tmp = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
- return *((float *)&tmp);
+
+ // Cause a compile-time error if sizeof(float) != 4
+ // If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats
+ char Check1[5 - sizeof(float)]; // sizeof(float) <= 4
+ char Check2[sizeof(float) - 3]; // sizeof(float) >= 4
+ UNUSED(Check1);
+ UNUSED(Check2);
+
+ Int32 i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
+ float f;
+ memcpy(&f, &i, sizeof(f));
+ return f;
}
inline double GetDouble(int a_Tag) const
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
new file mode 100644
index 000000000..a4a0aab57
--- /dev/null
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -0,0 +1,276 @@
+
+// MapSerializer.cpp
+
+
+#include "Globals.h"
+#include "MapSerializer.h"
+#include "../StringCompression.h"
+#include "zlib/zlib.h"
+#include "FastNBT.h"
+
+#include "../Map.h"
+#include "../World.h"
+
+
+
+
+
+cMapSerializer::cMapSerializer(const AString& a_WorldName, cMap * a_Map)
+ : m_Map(a_Map)
+{
+ AString DataPath;
+ Printf(DataPath, "%s/data", a_WorldName.c_str());
+
+ Printf(m_Path, "%s/map_%i.dat", DataPath.c_str(), a_Map->GetID());
+
+ cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
+}
+
+
+
+
+
+bool cMapSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ AString Uncompressed;
+ int res = UncompressStringGZIP(Data.data(), Data.size(), Uncompressed);
+
+ if (res != Z_OK)
+ {
+ return false;
+ }
+
+ // Parse the NBT data:
+ cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
+ if (!NBT.IsValid())
+ {
+ // NBT Parsing failed
+ return false;
+ }
+
+ return LoadMapFromNBT(NBT);
+}
+
+
+
+
+
+bool cMapSerializer::Save(void)
+{
+ cFastNBTWriter Writer;
+
+ SaveMapToNBT(Writer);
+
+ Writer.Finish();
+
+ #ifdef _DEBUG
+ cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
+ ASSERT(TestParse.IsValid());
+ #endif // _DEBUG
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ AString Compressed;
+ int res = CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
+
+ if (res != Z_OK)
+ {
+ return false;
+ }
+
+ File.Write(Compressed.data(), Compressed.size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
+void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer)
+{
+ a_Writer.BeginCompound("data");
+
+ a_Writer.AddByte("scale", m_Map->GetScale());
+ a_Writer.AddByte("dimension", (int) m_Map->GetDimension());
+
+ a_Writer.AddShort("width", m_Map->GetWidth());
+ a_Writer.AddShort("height", m_Map->GetHeight());
+
+ a_Writer.AddInt("xCenter", m_Map->GetCenterX());
+ a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
+
+ const cMap::cColorList & Data = m_Map->GetData();
+ a_Writer.AddByteArray("colors", (char *) &Data[0], Data.size());
+
+ a_Writer.EndCompound();
+}
+
+
+
+
+
+bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
+{
+ int Data = a_NBT.FindChildByName(0, "data");
+ if (Data < 0)
+ {
+ return false;
+ }
+
+ int CurrLine = a_NBT.FindChildByName(Data, "scale");
+ if (CurrLine >= 0)
+ {
+ unsigned int Scale = a_NBT.GetByte(CurrLine);
+ m_Map->SetScale(Scale);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "dimension");
+ if (CurrLine >= 0)
+ {
+ eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
+
+ ASSERT(Dimension == m_Map->m_World->GetDimension());
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "width");
+ if (CurrLine >= 0)
+ {
+ unsigned int Width = a_NBT.GetShort(CurrLine);
+ m_Map->m_Width = Width;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "height");
+ if (CurrLine >= 0)
+ {
+ unsigned int Height = a_NBT.GetShort(CurrLine);
+ m_Map->m_Height = Height;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "xCenter");
+ if (CurrLine >= 0)
+ {
+ int CenterX = a_NBT.GetInt(CurrLine);
+ m_Map->m_CenterX = CenterX;
+ }
+
+ CurrLine = a_NBT.FindChildByName(Data, "zCenter");
+ if (CurrLine >= 0)
+ {
+ int CenterZ = a_NBT.GetInt(CurrLine);
+ m_Map->m_CenterZ = CenterZ;
+ }
+
+ unsigned int NumPixels = m_Map->GetNumPixels();
+ m_Map->m_Data.resize(NumPixels);
+
+ CurrLine = a_NBT.FindChildByName(Data, "colors");
+ if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
+ {
+ memcpy(&m_Map->m_Data[0], a_NBT.GetData(CurrLine), NumPixels);
+ }
+
+ return true;
+}
+
+
+
+
+
+cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
+{
+ AString DataPath;
+ Printf(DataPath, "%s/data", a_WorldName.c_str());
+
+ Printf(m_Path, "%s/idcounts.dat", DataPath.c_str());
+
+ cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
+}
+
+
+
+
+
+bool cIDCountSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ // NOTE: idcounts.dat is not compressed (raw format)
+
+ // Parse the NBT data:
+ cParsedNBT NBT(Data.data(), Data.size());
+ if (!NBT.IsValid())
+ {
+ // NBT Parsing failed
+ return false;
+ }
+
+ int CurrLine = NBT.FindChildByName(0, "map");
+ if (CurrLine >= 0)
+ {
+ m_MapCount = (int)NBT.GetShort(CurrLine) + 1;
+ }
+ else
+ {
+ m_MapCount = 0;
+ }
+
+ return true;
+}
+
+
+
+
+
+bool cIDCountSerializer::Save(void)
+{
+ cFastNBTWriter Writer;
+
+ if (m_MapCount > 0)
+ {
+ Writer.AddShort("map", m_MapCount - 1);
+ }
+
+ Writer.Finish();
+
+ #ifdef _DEBUG
+ cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
+ ASSERT(TestParse.IsValid());
+ #endif // _DEBUG
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ // NOTE: idcounts.dat is not compressed (raw format)
+
+ File.Write(Writer.GetResult().data(), Writer.GetResult().size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
+
+
+
diff --git a/src/WorldStorage/MapSerializer.h b/src/WorldStorage/MapSerializer.h
new file mode 100644
index 000000000..eb7678a08
--- /dev/null
+++ b/src/WorldStorage/MapSerializer.h
@@ -0,0 +1,86 @@
+
+// MapSerializer.h
+
+// Declares the cMapSerializer class that is used for saving maps into NBT format used by Anvil
+
+
+
+
+
+#pragma once
+
+
+
+
+
+// fwd:
+class cFastNBTWriter;
+class cParsedNBT;
+class cMap;
+
+
+
+
+/** Utility class used to serialize maps. */
+class cMapSerializer
+{
+public:
+
+ cMapSerializer(const AString& a_WorldName, cMap * a_Map);
+
+ /** Try to load the scoreboard */
+ bool Load(void);
+
+ /** Try to save the scoreboard */
+ bool Save(void);
+
+
+private:
+
+ void SaveMapToNBT(cFastNBTWriter & a_Writer);
+
+ bool LoadMapFromNBT(const cParsedNBT & a_NBT);
+
+ cMap * m_Map;
+
+ AString m_Path;
+
+
+} ;
+
+
+
+
+/** Utility class used to serialize item ID counts.
+ *
+ * In order to perform bounds checking (while loading),
+ * the last registered ID of each item is serialized to an NBT file.
+ */
+class cIDCountSerializer
+{
+public:
+
+ cIDCountSerializer(const AString & a_WorldName);
+
+ /** Try to load the ID counts */
+ bool Load(void);
+
+ /** Try to save the ID counts */
+ bool Save(void);
+
+ inline unsigned int GetMapCount(void) const { return m_MapCount; }
+
+ inline void SetMapCount(unsigned int a_MapCount) { m_MapCount = a_MapCount; }
+
+
+private:
+
+ AString m_Path;
+
+ unsigned int m_MapCount;
+
+};
+
+
+
+
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 2a1eda523..c1c659b36 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -409,6 +409,14 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.BeginCompound("");
AddBasicEntity(a_Monster, EntityClass);
+ m_Writer.BeginList("DropChances", TAG_Float);
+ m_Writer.AddFloat("", a_Monster->GetDropChanceWeapon());
+ m_Writer.AddFloat("", a_Monster->GetDropChanceHelmet());
+ m_Writer.AddFloat("", a_Monster->GetDropChanceChestplate());
+ m_Writer.AddFloat("", a_Monster->GetDropChanceLeggings());
+ m_Writer.AddFloat("", a_Monster->GetDropChanceBoots());
+ m_Writer.EndList();
+ m_Writer.AddByte("CanPickUpLoot", (char)a_Monster->CanPickUpLoot());
switch (a_Monster->GetMobType())
{
case cMonster::mtBat:
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index d4490c7fe..05332d23d 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1485,6 +1485,11 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1500,6 +1505,11 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1515,6 +1525,11 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1530,6 +1545,11 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT &
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1545,6 +1565,11 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1560,6 +1585,11 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT &
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1575,6 +1605,11 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1591,6 +1626,11 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT &
return;
}
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
a_Entities.push_back(Monster.release());
}
@@ -1606,6 +1646,11 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
return;
}
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
a_Entities.push_back(Monster.release());
}
@@ -1620,6 +1665,11 @@ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1646,6 +1696,11 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1661,6 +1716,11 @@ void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1682,6 +1742,11 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1697,6 +1762,11 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1712,6 +1782,11 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1727,6 +1802,11 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1748,6 +1828,11 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1763,6 +1848,11 @@ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1784,6 +1874,11 @@ void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT &
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1805,6 +1900,11 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1820,6 +1920,11 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1835,6 +1940,11 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1850,6 +1960,11 @@ void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1871,6 +1986,11 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT &
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1886,6 +2006,11 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1901,6 +2026,11 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1916,6 +2046,10 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
{
return;
}
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner");
if (OwnerIdx > 0)
{
@@ -1964,6 +2098,11 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
a_Entities.push_back(Monster.release());
}
@@ -1980,6 +2119,11 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
return;
}
+ if (!LoadMonsterBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
a_Entities.push_back(Monster.release());
}
@@ -2023,6 +2167,27 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
+bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ float DropChance[5];
+ if (!LoadFloatsListFromNBT(DropChance, 5, a_NBT, a_NBT.FindChildByName(a_TagIdx, "DropChance")))
+ {
+ return false;
+ }
+ a_Monster.SetDropChanceWeapon(DropChance[0]);
+ a_Monster.SetDropChanceHelmet(DropChance[1]);
+ a_Monster.SetDropChanceChestplate(DropChance[2]);
+ a_Monster.SetDropChanceLeggings(DropChance[3]);
+ a_Monster.SetDropChanceBoots(DropChance[4]);
+ bool CanPickUpLoot = (a_NBT.GetByte(a_NBT.FindChildByName(a_TagIdx, "CanPickUpLoot")) == 1);
+ a_Monster.SetCanPickUpLoot(CanPickUpLoot);
+ return true;
+}
+
+
+
+
+
bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{
if (!LoadEntityBaseFromNBT(a_Entity, a_NBT, a_TagIdx))
@@ -2065,6 +2230,24 @@ bool cWSSAnvil::LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, con
+bool cWSSAnvil::LoadFloatsListFromNBT(float * a_Floats, int a_NumFloats, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Float))
+ {
+ return false;
+ }
+ int idx = 0;
+ for (int Tag = a_NBT.GetFirstChild(a_TagIdx); (Tag > 0) && (idx < a_NumFloats); Tag = a_NBT.GetNextSibling(Tag), ++idx)
+ {
+ a_Floats[idx] = a_NBT.GetFloat(Tag);
+ } // for Tag - PosTag[]
+ return (idx == a_NumFloats); // Did we read enough doubles?
+}
+
+
+
+
+
bool cWSSAnvil::GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int & a_X, int & a_Y, int & a_Z)
{
int x = a_NBT.FindChildByName(a_TagIdx, "x");
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 541371560..4acf3f2a1 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -10,6 +10,7 @@
#include "WorldStorage.h"
#include "FastNBT.h"
+#include "../Mobs/Monster.h"
@@ -194,12 +195,18 @@ protected:
/// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
+ /// Loads monster common data from the NBT compound; returns true if successful
+ bool LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT & a_NBT, int a_TagIdx);
+
/// Loads projectile common data from the NBT compound; returns true if successful
bool LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIx);
/// Loads an array of doubles of the specified length from the specified NBT list tag a_TagIdx; returns true if successful
bool LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx);
+ /// Loads an array of floats of the specified length from the specified NBT list tag a_TagIdx; returns true if successful
+ bool LoadFloatsListFromNBT(float * a_Floats, int a_NumFloats, const cParsedNBT & a_NBT, int a_TagIdx);
+
/// Helper function for extracting the X, Y, and Z int subtags of a NBT compound; returns true if successful
bool GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int & a_X, int & a_Y, int & a_Z);