summaryrefslogtreecommitdiffstats
path: root/src/WorldStorage
diff options
context:
space:
mode:
Diffstat (limited to 'src/WorldStorage')
-rw-r--r--src/WorldStorage/CMakeLists.txt1
-rw-r--r--src/WorldStorage/FastNBT.cpp46
-rw-r--r--src/WorldStorage/FastNBT.h78
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp10
-rw-r--r--src/WorldStorage/FireworksSerializer.h4
-rw-r--r--src/WorldStorage/MapSerializer.cpp8
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp100
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h4
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp43
-rw-r--r--src/WorldStorage/StatSerializer.cpp146
-rw-r--r--src/WorldStorage/StatSerializer.h55
-rw-r--r--src/WorldStorage/WSSAnvil.cpp81
-rw-r--r--src/WorldStorage/WSSAnvil.h4
-rw-r--r--src/WorldStorage/WSSCompact.cpp47
-rw-r--r--src/WorldStorage/WSSCompact.h7
-rw-r--r--src/WorldStorage/WorldStorage.cpp3
16 files changed, 479 insertions, 158 deletions
diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt
index 2c83c4662..2844f7fe5 100644
--- a/src/WorldStorage/CMakeLists.txt
+++ b/src/WorldStorage/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(WorldStorage ${SOURCE})
diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp
index be25fd1a4..a047d67c7 100644
--- a/src/WorldStorage/FastNBT.cpp
+++ b/src/WorldStorage/FastNBT.cpp
@@ -29,7 +29,7 @@
// cParsedNBT:
#define NEEDBYTES(N) \
- if (m_Length - m_Pos < N) \
+ if (m_Length - m_Pos < (size_t)N) \
{ \
return false; \
}
@@ -38,7 +38,7 @@
-cParsedNBT::cParsedNBT(const char * a_Data, int a_Length) :
+cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) :
m_Data(a_Data),
m_Length(a_Length),
m_Pos(0)
@@ -79,14 +79,14 @@ bool cParsedNBT::Parse(void)
-bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen)
+bool cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen)
{
NEEDBYTES(2);
a_StringStart = m_Pos + 2;
- a_StringLen = GetBEShort(m_Data + m_Pos);
- if (a_StringLen < 0)
+ a_StringLen = (size_t)GetBEShort(m_Data + m_Pos);
+ if (a_StringLen > 0xffff)
{
- // Invalid string length
+ // Suspicious string length
return false;
}
m_Pos += 2 + a_StringLen;
@@ -99,8 +99,10 @@ bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen)
bool cParsedNBT::ReadCompound(void)
{
+ ASSERT(m_Tags.size() > 0);
+
// Reads the latest tag as a compound
- int ParentIdx = m_Tags.size() - 1;
+ int ParentIdx = (int)m_Tags.size() - 1;
int PrevSibling = -1;
for (;;)
{
@@ -114,13 +116,13 @@ bool cParsedNBT::ReadCompound(void)
m_Tags.push_back(cFastNBTTag(TagType, ParentIdx, PrevSibling));
if (PrevSibling >= 0)
{
- m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1;
+ m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1;
}
else
{
- m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1;
+ m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1;
}
- PrevSibling = m_Tags.size() - 1;
+ PrevSibling = (int)m_Tags.size() - 1;
RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength));
RETURN_FALSE_IF_FALSE(ReadTag());
} // while (true)
@@ -146,20 +148,20 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType)
}
// Read items:
- int ParentIdx = m_Tags.size() - 1;
+ int ParentIdx = (int)m_Tags.size() - 1;
int PrevSibling = -1;
for (int i = 0; i < Count; i++)
{
m_Tags.push_back(cFastNBTTag(a_ChildrenType, ParentIdx, PrevSibling));
if (PrevSibling >= 0)
{
- m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1;
+ m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1;
}
else
{
- m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1;
+ m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1;
}
- PrevSibling = m_Tags.size() - 1;
+ PrevSibling = (int)m_Tags.size() - 1;
RETURN_FALSE_IF_FALSE(ReadTag());
} // for (i)
m_Tags[ParentIdx].m_LastChild = PrevSibling;
@@ -279,7 +281,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen
for (int Child = m_Tags[a_Tag].m_FirstChild; Child != -1; Child = m_Tags[Child].m_NextSibling)
{
if (
- (m_Tags[Child].m_NameLength == (int)a_NameLength) &&
+ (m_Tags[Child].m_NameLength == a_NameLength) &&
(memcmp(m_Data + m_Tags[Child].m_NameStart, a_Name, a_NameLength) == 0)
)
{
@@ -336,7 +338,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) :
m_Stack[0].m_Type = TAG_Compound;
m_Result.reserve(100 * 1024);
m_Result.push_back(TAG_Compound);
- WriteString(a_RootTagName.data(), a_RootTagName.size());
+ WriteString(a_RootTagName.data(), (UInt16)a_RootTagName.size());
}
@@ -345,7 +347,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) :
void cFastNBTWriter::BeginCompound(const AString & a_Name)
{
- if (m_CurrentStack >= MAX_STACK)
+ if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;
@@ -376,7 +378,7 @@ void cFastNBTWriter::EndCompound(void)
void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
{
- if (m_CurrentStack >= MAX_STACK)
+ if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;
@@ -389,7 +391,7 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
++m_CurrentStack;
m_Stack[m_CurrentStack].m_Type = TAG_List;
- m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4;
+ m_Stack[m_CurrentStack].m_Pos = (int)m_Result.size() - 4;
m_Stack[m_CurrentStack].m_Count = 0;
m_Stack[m_CurrentStack].m_ItemType = a_ChildrenType;
}
@@ -493,7 +495,7 @@ void cFastNBTWriter::AddString(const AString & a_Name, const AString & a_Value)
void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements)
{
TagCommon(a_Name, TAG_ByteArray);
- Int32 len = htonl(a_NumElements);
+ u_long len = htonl((u_long)a_NumElements);
m_Result.append((const char *)&len, 4);
m_Result.append(a_Value, a_NumElements);
}
@@ -505,7 +507,7 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value,
void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, size_t a_NumElements)
{
TagCommon(a_Name, TAG_IntArray);
- Int32 len = htonl(a_NumElements);
+ u_long len = htonl((u_long)a_NumElements);
size_t cap = m_Result.capacity();
size_t size = m_Result.length();
if ((cap - size) < (4 + a_NumElements * 4))
@@ -534,7 +536,7 @@ void cFastNBTWriter::Finish(void)
-void cFastNBTWriter::WriteString(const char * a_Data, short a_Length)
+void cFastNBTWriter::WriteString(const char * a_Data, UInt16 a_Length)
{
Int16 Len = htons(a_Length);
m_Result.append((const char *)&Len, 2);
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index 1b8b09c21..fe28005ac 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -61,10 +61,10 @@ public:
// The following members are indices into the data stream. m_DataLength == 0 if no data available
// They must not be pointers, because the datastream may be copied into another AString object in the meantime.
- int m_NameStart;
- int m_NameLength;
- int m_DataStart;
- int m_DataLength;
+ size_t m_NameStart;
+ size_t m_NameLength;
+ size_t m_DataStart;
+ size_t m_DataLength;
// The following members are indices into the array returned; -1 if not valid
// They must not be pointers, because pointers would not survive std::vector reallocation
@@ -114,7 +114,7 @@ Each primitive tag also stores the length of the contained data, in bytes.
class cParsedNBT
{
public:
- cParsedNBT(const char * a_Data, int a_Length);
+ cParsedNBT(const char * a_Data, size_t a_Length);
bool IsValid(void) const {return m_IsValid; }
@@ -122,33 +122,33 @@ public:
int GetRoot(void) const {return 0; }
/** Returns the first child of the specified tag, or -1 if none / not applicable. */
- int GetFirstChild (int a_Tag) const { return m_Tags[a_Tag].m_FirstChild; }
+ int GetFirstChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_FirstChild; }
/** Returns the last child of the specified tag, or -1 if none / not applicable. */
- int GetLastChild (int a_Tag) const { return m_Tags[a_Tag].m_LastChild; }
+ int GetLastChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_LastChild; }
/** Returns the next sibling of the specified tag, or -1 if none. */
- int GetNextSibling(int a_Tag) const { return m_Tags[a_Tag].m_NextSibling; }
+ int GetNextSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_NextSibling; }
/** Returns the previous sibling of the specified tag, or -1 if none. */
- int GetPrevSibling(int a_Tag) const { return m_Tags[a_Tag].m_PrevSibling; }
+ int GetPrevSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_PrevSibling; }
/** Returns the length of the tag's data, in bytes.
Not valid for Compound or List tags! */
- int GetDataLength (int a_Tag) const
+ size_t GetDataLength (int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
- ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound);
- return m_Tags[a_Tag].m_DataLength;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound);
+ return m_Tags[(size_t)a_Tag].m_DataLength;
}
/** Returns the data stored in this tag.
Not valid for Compound or List tags! */
const char * GetData(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
- ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound);
- return m_Data + m_Tags[a_Tag].m_DataStart;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound);
+ return m_Data + m_Tags[(size_t)a_Tag].m_DataStart;
}
/** Returns the direct child tag of the specified name, or -1 if no such tag. */
@@ -163,47 +163,47 @@ public:
/** Returns the child tag of the specified path (Name1\Name2\Name3...), or -1 if no such tag. */
int FindTagByPath(int a_Tag, const AString & a_Path) const;
- eTagType GetType(int a_Tag) const { return m_Tags[a_Tag].m_Type; }
+ eTagType GetType(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_Type; }
/** Returns the children type for a List tag; undefined on other tags. If list empty, returns TAG_End. */
eTagType GetChildrenType(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_List);
- return (m_Tags[a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[m_Tags[a_Tag].m_FirstChild].m_Type;
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_List);
+ return (m_Tags[(size_t)a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[(size_t)m_Tags[(size_t)a_Tag].m_FirstChild].m_Type;
}
/** Returns the value stored in a Byte tag. Not valid for any other tag type. */
inline unsigned char GetByte(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Byte);
- return (unsigned char)(m_Data[m_Tags[a_Tag].m_DataStart]);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Byte);
+ return (unsigned char)(m_Data[(size_t)m_Tags[(size_t)a_Tag].m_DataStart]);
}
/** Returns the value stored in a Short tag. Not valid for any other tag type. */
inline Int16 GetShort(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Short);
- return GetBEShort(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Short);
+ return GetBEShort(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in an Int tag. Not valid for any other tag type. */
inline Int32 GetInt(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Int);
- return GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Int);
+ return GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a Long tag. Not valid for any other tag type. */
inline Int64 GetLong(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Long);
- return NetworkToHostLong8(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Long);
+ return NetworkToHostLong8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a Float tag. Not valid for any other tag type. */
inline float GetFloat(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Float);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Float);
// 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
@@ -212,7 +212,7 @@ public:
UNUSED(Check1);
UNUSED(Check2);
- Int32 i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
+ Int32 i = GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
float f;
memcpy(&f, &i, sizeof(f));
return f;
@@ -228,16 +228,16 @@ public:
UNUSED(Check1);
UNUSED(Check2);
- ASSERT(m_Tags[a_Tag].m_Type == TAG_Double);
- return NetworkToHostDouble8(m_Data + m_Tags[a_Tag].m_DataStart);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Double);
+ return NetworkToHostDouble8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart);
}
/** Returns the value stored in a String tag. Not valid for any other tag type. */
inline AString GetString(int a_Tag) const
{
- ASSERT(m_Tags[a_Tag].m_Type == TAG_String);
+ ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_String);
AString res;
- res.assign(m_Data + m_Tags[a_Tag].m_DataStart, m_Tags[a_Tag].m_DataLength);
+ res.assign(m_Data + m_Tags[(size_t)a_Tag].m_DataStart, (size_t)m_Tags[(size_t)a_Tag].m_DataLength);
return res;
}
@@ -245,21 +245,21 @@ public:
inline AString GetName(int a_Tag) const
{
AString res;
- res.assign(m_Data + m_Tags[a_Tag].m_NameStart, m_Tags[a_Tag].m_NameLength);
+ res.assign(m_Data + m_Tags[(size_t)a_Tag].m_NameStart, (size_t)m_Tags[(size_t)a_Tag].m_NameLength);
return res;
}
protected:
const char * m_Data;
- int m_Length;
+ size_t m_Length;
std::vector<cFastNBTTag> m_Tags;
bool m_IsValid; // True if parsing succeeded
// Used while parsing:
- int m_Pos;
+ size_t m_Pos;
bool Parse(void);
- bool ReadString(int & a_StringStart, int & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors
+ bool ReadString(size_t & a_StringStart, size_t & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors
bool ReadCompound(void); // Reads the latest tag as a compound
bool ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType
bool ReadTag(void); // Reads the latest tag, depending on its m_Type setting
@@ -319,7 +319,7 @@ protected:
bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); }
- void WriteString(const char * a_Data, short a_Length);
+ void WriteString(const char * a_Data, UInt16 a_Length);
inline void TagCommon(const AString & a_Name, eTagType a_Type)
{
@@ -330,7 +330,7 @@ protected:
{
// Compound: add the type and name:
m_Result.push_back((char)a_Type);
- WriteString(a_Name.c_str(), (short)a_Name.length());
+ WriteString(a_Name.c_str(), (UInt16)a_Name.length());
}
else
{
diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
index 744fc731f..181cfde0d 100644
--- a/src/WorldStorage/FireworksSerializer.cpp
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -96,7 +96,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
if (ExplosionName == "Colors")
{
// Divide by four as data length returned in bytes
- int DataLength = a_NBT.GetDataLength(explosiontag);
+ size_t DataLength = a_NBT.GetDataLength(explosiontag);
// round to the next highest multiple of four
DataLength -= DataLength % 4;
if (DataLength == 0)
@@ -105,14 +105,14 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
}
const char * ColourData = (a_NBT.GetData(explosiontag));
- for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ for (size_t i = 0; i < DataLength; i += 4)
{
a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
}
}
else if (ExplosionName == "FadeColors")
{
- int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4;
// round to the next highest multiple of four
DataLength -= DataLength % 4;
if (DataLength == 0)
@@ -121,7 +121,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
}
const char * FadeColourData = (a_NBT.GetData(explosiontag));
- for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ for (size_t i = 0; i < DataLength; i += 4)
{
a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
}
@@ -231,7 +231,7 @@ void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkIte
-int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
+int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta)
{
/*
Colours are supposed to be calculated via: R << 16 + G << 8 + B
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
index 5b87bafdb..59f1b09b0 100644
--- a/src/WorldStorage/FireworksSerializer.h
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -81,7 +81,7 @@ public:
static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
/** Returns a colour code for fireworks used by the network code */
- static int GetVanillaColourCodeFromDye(short a_DyeMeta);
+ static int GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta);
bool m_HasFlicker;
bool m_HasTrail;
@@ -89,4 +89,4 @@ public:
short m_FlightTimeInTicks;
std::vector<int> m_Colours;
std::vector<int> m_FadeColours;
-}; \ No newline at end of file
+};
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index df72d1cc9..012fc52f3 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -152,6 +152,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
if (CurrLine >= 0)
{
unsigned int Width = a_NBT.GetShort(CurrLine);
+ if (Width != 128)
+ {
+ return false;
+ }
m_Map->m_Width = Width;
}
@@ -159,6 +163,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
if (CurrLine >= 0)
{
unsigned int Height = a_NBT.GetShort(CurrLine);
+ if (Height >= 256)
+ {
+ return false;
+ }
m_Map->m_Height = Height;
}
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 415693ae2..a3b0d57be 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -28,7 +28,7 @@
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -39,7 +39,7 @@
#include "../Mobs/Creeper.h"
#include "../Mobs/Enderman.h"
#include "../Mobs/Horse.h"
-#include "../Mobs/Magmacube.h"
+#include "../Mobs/MagmaCube.h"
#include "../Mobs/Sheep.h"
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
@@ -88,23 +88,48 @@ void cNBTChunkSerializer::Finish(void)
void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName)
{
m_Writer.BeginCompound(a_CompoundName);
- m_Writer.AddShort("id", (short)(a_Item.m_ItemType));
- m_Writer.AddShort("Damage", a_Item.m_ItemDamage);
- m_Writer.AddByte ("Count", a_Item.m_ItemCount);
+ m_Writer.AddShort("id", (short)(a_Item.m_ItemType));
+ m_Writer.AddShort("Damage", a_Item.m_ItemDamage);
+ m_Writer.AddByte ("Count", a_Item.m_ItemCount);
if (a_Slot >= 0)
{
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
}
- // Write the enchantments:
- if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
+ // Write the tag compound (for enchantment, firework, custom name and repair cost):
+ if (
+ (!a_Item.m_Enchantments.IsEmpty()) ||
+ ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) ||
+ (a_Item.m_RepairCost > 0) ||
+ (a_Item.m_CustomName != "") ||
+ (a_Item.m_Lore != "")
+ )
{
m_Writer.BeginCompound("tag");
+ if (a_Item.m_RepairCost > 0)
+ {
+ m_Writer.AddInt("RepairCost", a_Item.m_RepairCost);
+ }
+
+ if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != ""))
+ {
+ m_Writer.BeginCompound("display");
+ if (a_Item.m_CustomName != "")
+ {
+ m_Writer.AddString("Name", a_Item.m_CustomName);
+ }
+ if (a_Item.m_Lore != "")
+ {
+ m_Writer.AddString("Lore", a_Item.m_Lore);
+ }
+ m_Writer.EndCompound();
+ }
+
if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
{
cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
}
-
+
if (!a_Item.m_Enchantments.IsEmpty())
{
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
@@ -366,38 +391,41 @@ void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
{
- const char * EntityClass = NULL;
- switch (a_Minecart->GetPayload())
- {
- case cMinecart::mpNone: EntityClass = "MinecartRideable"; break;
- case cMinecart::mpChest: EntityClass = "MinecartChest"; break;
- case cMinecart::mpFurnace: EntityClass = "MinecartFurnace"; break;
- case cMinecart::mpTNT: EntityClass = "MinecartTNT"; break;
- case cMinecart::mpHopper: EntityClass = "MinecartHopper"; break;
- default:
- {
- ASSERT(!"Unhandled minecart payload type");
- return;
- }
- } // switch (payload)
-
m_Writer.BeginCompound("");
- AddBasicEntity(a_Minecart, EntityClass);
+
switch (a_Minecart->GetPayload())
{
case cMinecart::mpChest:
{
+ AddBasicEntity(a_Minecart, "MinecartChest");
// Add chest contents into the Items tag:
AddMinecartChestContents((cMinecartWithChest *)a_Minecart);
break;
}
-
case cMinecart::mpFurnace:
{
+ AddBasicEntity(a_Minecart, "MinecartFurnace");
// TODO: Add "Push" and "Fuel" tags
break;
}
+ case cMinecart::mpHopper:
+ {
+ AddBasicEntity(a_Minecart, "MinecartHopper");
+ // TODO: Add hopper contents?
+ break;
+ }
+ case cMinecart::mpTNT:
+ {
+ AddBasicEntity(a_Minecart, "MinecartTNT");
+ break;
+ }
+ case cMinecart::mpNone:
+ {
+ AddBasicEntity(a_Minecart, "MinecartRideable");
+ break;
+ }
} // switch (Payload)
+
m_Writer.EndCompound();
}
@@ -490,7 +518,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
case cMonster::mtMagmaCube:
{
- m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize());
+ m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize());
break;
}
case cMonster::mtSheep:
@@ -516,7 +544,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
case cMonster::mtWither:
{
- m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks());
break;
}
case cMonster::mtWolf:
@@ -621,10 +649,17 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
switch (a_Hanging->GetDirection())
{
- case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
- case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
- case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
- case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break;
+
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
+ case BLOCK_FACE_NONE:
+ {
+ break;
+ }
}
}
@@ -692,10 +727,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca
-bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{
m_IsLightValid = a_IsLightValid;
- return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 51d104970..112afc27e 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../ChunkDef.h"
+#include "ChunkDataCallback.h"
@@ -121,7 +121,7 @@ protected:
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides:
- virtual bool LightIsValid(bool a_IsLightValid) override;
+ virtual void LightIsValid(bool a_IsLightValid) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index d8531d965..1cf99efd9 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -14,6 +14,39 @@
+#ifdef SELF_TEST
+
+static class cSchematicStringSelfTest
+{
+public:
+ cSchematicStringSelfTest(void)
+ {
+ cBlockArea ba;
+ ba.Create(21, 256, 21);
+ ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1);
+ AString Schematic;
+ if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic))
+ {
+ assert_test(!"Schematic failed to save!");
+ }
+ cBlockArea ba2;
+ if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic))
+ {
+ assert_test(!"Schematic failed to load!");
+ }
+ }
+} g_SelfTest;
+
+#endif
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSchematicFileSerializer:
+
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
{
// Un-GZip the contents:
@@ -159,7 +192,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
int SizeX = a_NBT.GetShort(TSizeX);
int SizeY = a_NBT.GetShort(TSizeY);
int SizeZ = a_NBT.GetShort(TSizeZ);
- if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1))
+ if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > 256) || (SizeZ < 1) || (SizeZ > 65535))
{
LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ);
return false;
@@ -197,11 +230,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
// Copy the block types and metas:
- int NumBytes = a_BlockArea.GetBlockCount();
+ size_t NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
{
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- NumBytes, a_NBT.GetDataLength(TBlockTypes)
+ (int)NumBytes, (int)a_NBT.GetDataLength(TBlockTypes)
);
NumBytes = a_NBT.GetDataLength(TBlockTypes);
}
@@ -209,11 +242,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
if (AreMetasPresent)
{
- int NumBytes = a_BlockArea.GetBlockCount();
+ size_t NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
{
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- NumBytes, a_NBT.GetDataLength(TBlockMetas)
+ (int)NumBytes, (int)a_NBT.GetDataLength(TBlockMetas)
);
NumBytes = a_NBT.GetDataLength(TBlockMetas);
}
diff --git a/src/WorldStorage/StatSerializer.cpp b/src/WorldStorage/StatSerializer.cpp
new file mode 100644
index 000000000..74113941c
--- /dev/null
+++ b/src/WorldStorage/StatSerializer.cpp
@@ -0,0 +1,146 @@
+
+// StatSerializer.cpp
+
+
+#include "Globals.h"
+#include "StatSerializer.h"
+
+#include "../Statistics.h"
+
+
+
+
+
+cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager)
+ : m_Manager(a_Manager)
+{
+ // Even though stats are shared between worlds, they are (usually) saved
+ // inside the folder of the default world.
+
+ AString StatsPath;
+ Printf(StatsPath, "%s/stats", a_WorldName.c_str());
+
+ m_Path = StatsPath + "/" + a_PlayerName + ".json";
+
+ // Ensure that the directory exists.
+ cFile::CreateFolder(FILE_IO_PREFIX + StatsPath);
+}
+
+
+
+
+
+bool cStatSerializer::Load(void)
+{
+ AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
+ if (Data.empty())
+ {
+ return false;
+ }
+
+ Json::Value Root;
+ Json::Reader Reader;
+
+ if (Reader.parse(Data, Root, false))
+ {
+ return LoadStatFromJSON(Root);
+ }
+
+ return false;
+}
+
+
+
+
+
+bool cStatSerializer::Save(void)
+{
+ Json::Value Root;
+ SaveStatToJSON(Root);
+
+ cFile File;
+ if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
+ {
+ return false;
+ }
+
+ Json::StyledWriter Writer;
+ AString JsonData = Writer.write(Root);
+
+ File.Write(JsonData.data(), JsonData.size());
+ File.Close();
+
+ return true;
+}
+
+
+
+
+
+void cStatSerializer::SaveStatToJSON(Json::Value & a_Out)
+{
+ for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
+ {
+ StatValue Value = m_Manager->GetValue((eStatistic) i);
+
+ if (Value != 0)
+ {
+ const AString & StatName = cStatInfo::GetName((eStatistic) i);
+
+ a_Out[StatName] = Value;
+ }
+
+ // TODO 2014-05-11 xdot: Save "progress"
+ }
+}
+
+
+
+
+
+bool cStatSerializer::LoadStatFromJSON(const Json::Value & a_In)
+{
+ m_Manager->Reset();
+
+ for (Json::ValueIterator it = a_In.begin() ; it != a_In.end() ; ++it)
+ {
+ AString StatName = it.key().asString();
+
+ eStatistic StatType = cStatInfo::GetType(StatName);
+
+ if (StatType == statInvalid)
+ {
+ LOGWARNING("Invalid statistic type \"%s\"", StatName.c_str());
+ continue;
+ }
+
+ Json::Value & Node = *it;
+
+ if (Node.isInt())
+ {
+ m_Manager->SetValue(StatType, Node.asInt());
+ }
+ else if (Node.isObject())
+ {
+ StatValue Value = Node.get("value", 0).asInt();
+
+ // TODO 2014-05-11 xdot: Load "progress"
+
+ m_Manager->SetValue(StatType, Value);
+ }
+ else
+ {
+ LOGWARNING("Invalid statistic value for type \"%s\"", StatName.c_str());
+ }
+ }
+
+ return true;
+}
+
+
+
+
+
+
+
+
diff --git a/src/WorldStorage/StatSerializer.h b/src/WorldStorage/StatSerializer.h
new file mode 100644
index 000000000..72f8d74f1
--- /dev/null
+++ b/src/WorldStorage/StatSerializer.h
@@ -0,0 +1,55 @@
+
+// StatSerializer.h
+
+// Declares the cStatSerializer class that is used for saving stats into JSON
+
+
+
+
+
+#pragma once
+
+#include "json/json.h"
+
+
+
+
+
+// fwd:
+class cStatManager;
+
+
+
+
+class cStatSerializer
+{
+public:
+
+ cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager);
+
+ /* Try to load the player statistics. Returns whether the operation was successful or not. */
+ bool Load(void);
+
+ /* Try to save the player statistics. Returns whether the operation was successful or not. */
+ bool Save(void);
+
+
+protected:
+
+ void SaveStatToJSON(Json::Value & a_Out);
+
+ bool LoadStatFromJSON(const Json::Value & a_In);
+
+
+private:
+
+ cStatManager* m_Manager;
+
+ AString m_Path;
+
+
+} ;
+
+
+
+
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 48934d074..d310c9124 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -27,7 +27,6 @@
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
-
#include "../Mobs/Monster.h"
#include "../Mobs/IncludeAllMonsters.h"
@@ -36,7 +35,12 @@
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/ThrownEggEntity.h"
+#include "../Entities/ThrownEnderPearlEntity.h"
+#include "../Entities/ThrownSnowballEntity.h"
+#include "../Entities/FireChargeEntity.h"
+#include "../Entities/GhastFireballEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -92,7 +96,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
gzFile gz = gzopen((FILE_IO_PREFIX + fnam).c_str(), "wb");
if (gz != NULL)
{
- gzwrite(gz, Writer.GetResult().data(), Writer.GetResult().size());
+ gzwrite(gz, Writer.GetResult().data(), (unsigned)Writer.GetResult().size());
}
gzclose(gz);
}
@@ -248,7 +252,7 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString &
strm.next_out = (Bytef *)Uncompressed;
strm.avail_out = sizeof(Uncompressed);
strm.next_in = (Bytef *)a_Data.data();
- strm.avail_in = a_Data.size();
+ strm.avail_in = (uInt)a_Data.size();
int res = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
if (res != Z_STREAM_END)
@@ -401,7 +405,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
-void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length)
+void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length)
{
int Child = a_NBT.FindChildByName(a_Tag, a_ChildName);
if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length))
@@ -436,8 +440,8 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
// Save blockdata:
a_Writer.BeginList("Sections", TAG_Compound);
- int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
- int SliceSizeNibble = SliceSizeBlock / 2;
+ size_t SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
+ size_t SliceSizeNibble = SliceSizeBlock / 2;
const char * BlockTypes = (const char *)(Serializer.m_BlockTypes);
const char * BlockMetas = (const char *)(Serializer.m_BlockMetas);
#ifdef DEBUG_SKYLIGHT
@@ -641,18 +645,16 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
}
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
- if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
+ if ((Damage > 0) && (a_NBT.GetType(Damage) == TAG_Short))
{
- return false;
+ a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
}
- a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(a_TagIdx, "Count");
- if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
+ if ((Count > 0) && (a_NBT.GetType(Count) == TAG_Byte))
{
- return false;
+ a_Item.m_ItemCount = a_NBT.GetByte(Count);
}
- a_Item.m_ItemCount = a_NBT.GetByte(Count);
// Find the "tag" tag, used for enchantments and other extra data
int TagTag = a_NBT.FindChildByName(a_TagIdx, "tag");
@@ -662,6 +664,29 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
return true;
}
+ // Load repair cost:
+ int RepairCost = a_NBT.FindChildByName(TagTag, "RepairCost");
+ if ((RepairCost > 0) && (a_NBT.GetType(RepairCost) == TAG_Int))
+ {
+ a_Item.m_RepairCost = a_NBT.GetInt(RepairCost);
+ }
+
+ // Load display name:
+ int DisplayTag = a_NBT.FindChildByName(TagTag, "display");
+ if (DisplayTag > 0)
+ {
+ int DisplayName = a_NBT.FindChildByName(DisplayTag, "Name");
+ if ((DisplayName > 0) && (a_NBT.GetType(DisplayName) == TAG_String))
+ {
+ a_Item.m_CustomName = a_NBT.GetString(DisplayName);
+ }
+ int Lore = a_NBT.FindChildByName(DisplayTag, "Lore");
+ if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String))
+ {
+ a_Item.m_Lore = a_NBT.GetString(Lore);
+ }
+ }
+
// Load enchantments:
const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
int EnchTag = a_NBT.FindChildByName(TagTag, EnchName);
@@ -670,6 +695,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
}
+ // Load firework data:
int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
if (EnchTag > 0)
{
@@ -1052,7 +1078,7 @@ void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, cons
-void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength)
+void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength)
{
if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0)
{
@@ -1757,7 +1783,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cCavespider> Monster(new cCavespider());
+ std::auto_ptr<cCaveSpider> Monster(new cCaveSpider());
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
{
return;
@@ -1970,7 +1996,10 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT
{
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
- if (SizeIdx < 0) { return; }
+ if (SizeIdx < 0)
+ {
+ return;
+ }
int Size = a_NBT.GetInt(SizeIdx);
@@ -2128,7 +2157,10 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
- if (SizeIdx < 0) { return; }
+ if (SizeIdx < 0)
+ {
+ return;
+ }
int Size = a_NBT.GetInt(SizeIdx);
@@ -2272,7 +2304,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
if (CurrLine > 0)
{
- Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ Monster->SetWitherInvulnerableTicks(a_NBT.GetInt(CurrLine));
}
a_Entities.push_back(Monster.release());
@@ -2598,14 +2630,14 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
unsigned ChunkOffset = ChunkLocation >> 8;
- m_File.Seek(ChunkOffset * 4096);
+ m_File.Seek((int)ChunkOffset * 4096);
int ChunkSize = 0;
if (m_File.Read(&ChunkSize, 4) != 4)
{
return false;
}
- ChunkSize = ntohl(ChunkSize);
+ ChunkSize = ntohl((u_long)ChunkSize);
char CompressionType = 0;
if (m_File.Read(&CompressionType, 1) != 1)
{
@@ -2650,7 +2682,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
// Store the chunk data:
m_File.Seek(ChunkSector * 4096);
- unsigned ChunkSize = htonl(a_Data.size() + 1);
+ u_long ChunkSize = htonl((u_long)a_Data.size() + 1);
if (m_File.Write(&ChunkSize, 4) != 4)
{
LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
@@ -2668,8 +2700,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
return false;
}
+ // Add padding to 4K boundary:
+ size_t BytesWritten = a_Data.size() + MCA_CHUNK_HEADER_LENGTH;
+ static const char Padding[4095] = {0};
+ m_File.Write(Padding, 4096 - (BytesWritten % 4096));
+
// Store the header:
- ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
+ ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
ASSERT(ChunkSize < 256);
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
if (m_File.Seek(0) < 0)
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 1773ee882..7542a828a 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -145,7 +145,7 @@ protected:
void LoadMobHeadFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
- void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
+ void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength);
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
@@ -221,7 +221,7 @@ protected:
cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk);
/// Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer
- void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length);
+ void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length);
// cWSSchema overrides:
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index bb9d4b9e6..7a113849a 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -107,15 +107,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
-bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
{
- if (!a_IsLightValid)
+ if (a_IsLightValid)
{
- return false;
+ m_Root["IsLightValid"] = true;
+ m_HasJsonData = true;
}
- m_Root["IsLightValid"] = true;
- m_HasJsonData = true;
- return true;
}
@@ -468,7 +466,15 @@ cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_
for (int i = 0; i < NumChunks; i++)
{
sChunkHeader * Header = new sChunkHeader;
- READ(*Header);
+
+ // Here we do not use the READ macro, as it does not free the resources
+ // allocated with new in case of error.
+ if (f.Read(Header, sizeof(*Header)) != sizeof(*Header))
+ {
+ LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell());
+ delete Header;
+ return;
+ }
m_ChunkHeaders.push_back(Header);
} // for i - chunk headers
@@ -593,7 +599,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Decompress the data:
AString UncompressedData;
{
- int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize);
+ int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -673,7 +679,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Re-compress data
AString CompressedData;
{
- int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor);
+ int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@@ -685,9 +691,9 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
}
// Save into file's cache
- Header->m_UncompressedSize = Converted.size();
- Header->m_CompressedSize = CompressedData.size();
- NewDataContents.append( CompressedData );
+ Header->m_UncompressedSize = (int)Converted.size();
+ Header->m_CompressedSize = (int)CompressedData.size();
+ NewDataContents.append(CompressedData);
}
// Done converting
@@ -723,7 +729,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
Offset += Header->m_CompressedSize;
// Crude data integrity check:
- const int ExpectedSize = (16*256*16)*2 + (16*256*16)/2; // For version 2
+ const int ExpectedSize = (16 * 256 * 16) * 2 + (16 * 256 * 16) / 2; // For version 2
if (UncompressedSize < ExpectedSize)
{
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing",
@@ -737,7 +743,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Decompress the data:
AString UncompressedData;
{
- int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize);
+ int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -797,7 +803,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
++index2;
}
InChunkOffset += index2 / 2;
- index2 = 0;
AString Converted(ConvertedData, ExpectedSize);
@@ -822,9 +827,9 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
}
// Save into file's cache
- Header->m_UncompressedSize = Converted.size();
- Header->m_CompressedSize = CompressedData.size();
- NewDataContents.append( CompressedData );
+ Header->m_UncompressedSize = (int)Converted.size();
+ Header->m_CompressedSize = (int)CompressedData.size();
+ NewDataContents.append(CompressedData);
}
// Done converting
@@ -839,7 +844,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
-bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World)
+bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World)
{
// Crude data integrity check:
if (a_UncompressedSize < cChunkDef::BlockDataSize)
@@ -854,7 +859,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
// Decompress the data:
AString UncompressedData;
- int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, a_UncompressedSize);
+ int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, (size_t)a_UncompressedSize);
if (errorcode != Z_OK)
{
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
@@ -866,7 +871,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
if (a_UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
a_UncompressedSize, UncompressedData.size(),
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
);
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 4df146ec3..b148005f6 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -14,6 +14,7 @@
#include "WorldStorage.h"
#include "../Vector3.h"
#include "json/json.h"
+#include "ChunkDataCallback.h"
@@ -21,7 +22,7 @@
/// Helper class for serializing a chunk into Json
class cJsonChunkSerializer :
- public cChunkDataCollector
+ public cChunkDataArrayCollector
{
public:
@@ -42,7 +43,7 @@ protected:
// cChunkDataCollector overrides:
virtual void Entity (cEntity * a_Entity) override;
virtual void BlockEntity (cBlockEntity * a_Entity) override;
- virtual bool LightIsValid (bool a_IsLightValid) override;
+ virtual void LightIsValid (bool a_IsLightValid) override;
} ;
@@ -135,7 +136,7 @@ protected:
bool EraseChunkData(const cChunkCoords & a_Chunk);
/// Loads the chunk from the data (no locking needed)
- bool LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World);
+ bool LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World);
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);
diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp
index 711c8612f..6867ad5bc 100644
--- a/src/WorldStorage/WorldStorage.cpp
+++ b/src/WorldStorage/WorldStorage.cpp
@@ -150,7 +150,7 @@ size_t cWorldStorage::GetSaveQueueLength(void)
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate)
{
- m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
+ m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
m_Event.Set();
}
@@ -243,7 +243,6 @@ void cWorldStorage::Execute(void)
bool Success;
do
{
- Success = false;
if (m_ShouldTerminate)
{
return;