2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
// MapSerializer.cpp
|
|
|
|
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "MapSerializer.h"
|
|
|
|
#include "../StringCompression.h"
|
|
|
|
#include "zlib/zlib.h"
|
|
|
|
#include "FastNBT.h"
|
|
|
|
|
|
|
|
#include "../Map.h"
|
2014-02-13 14:36:24 -05:00
|
|
|
#include "../World.h"
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-05-09 05:16:56 -04:00
|
|
|
cMapSerializer::cMapSerializer(const AString & a_WorldName, cMap * a_Map):
|
|
|
|
m_Map(a_Map)
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
|
|
|
AString DataPath;
|
2015-05-09 03:25:09 -04:00
|
|
|
Printf(DataPath, "%s%cdata", a_WorldName.c_str(), cFile::PathSeparator);
|
2014-02-13 10:13:09 -05:00
|
|
|
|
2015-05-09 03:25:09 -04:00
|
|
|
Printf(m_Path, "%s%cmap_%i.dat", DataPath.c_str(), cFile::PathSeparator, a_Map->GetID());
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
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();
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-13 10:13:09 -05:00
|
|
|
#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");
|
|
|
|
|
2015-05-19 14:32:10 -04:00
|
|
|
a_Writer.AddByte("scale", static_cast<Byte>(m_Map->GetScale()));
|
|
|
|
a_Writer.AddByte("dimension", static_cast<Byte>(m_Map->GetDimension()));
|
2014-02-13 10:13:09 -05:00
|
|
|
|
2015-05-19 14:32:10 -04:00
|
|
|
a_Writer.AddShort("width", static_cast<Int16>(m_Map->GetWidth()));
|
|
|
|
a_Writer.AddShort("height", static_cast<Int16>(m_Map->GetHeight()));
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
a_Writer.AddInt("xCenter", m_Map->GetCenterX());
|
|
|
|
a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
|
|
|
|
|
|
|
|
const cMap::cColorList & Data = m_Map->GetData();
|
2015-07-29 11:04:03 -04:00
|
|
|
a_Writer.AddByteArray("colors", reinterpret_cast<const char *>(Data.data()), Data.size());
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
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");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
unsigned int Scale = static_cast<unsigned int>(a_NBT.GetByte(CurrLine));
|
2014-02-14 09:21:16 -05:00
|
|
|
m_Map->SetScale(Scale);
|
2014-02-13 10:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "dimension");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
eDimension Dimension = static_cast<eDimension>(a_NBT.GetByte(CurrLine));
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-24 06:29:19 -04:00
|
|
|
if (Dimension != m_Map->m_World->GetDimension())
|
|
|
|
{
|
|
|
|
// TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c.
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-13 10:13:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "width");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
unsigned int Width = static_cast<unsigned int>(a_NBT.GetShort(CurrLine));
|
2014-05-09 12:30:47 -04:00
|
|
|
if (Width != 128)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-13 10:13:09 -05:00
|
|
|
m_Map->m_Width = Width;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "height");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
unsigned int Height = static_cast<unsigned int>(a_NBT.GetShort(CurrLine));
|
2014-05-09 12:30:47 -04:00
|
|
|
if (Height >= 256)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-13 10:13:09 -05:00
|
|
|
m_Map->m_Height = Height;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "xCenter");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
|
|
|
int CenterX = a_NBT.GetInt(CurrLine);
|
|
|
|
m_Map->m_CenterX = CenterX;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "zCenter");
|
2014-09-26 08:31:52 -04:00
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
|
2014-02-13 10:13:09 -05:00
|
|
|
{
|
|
|
|
int CenterZ = a_NBT.GetInt(CurrLine);
|
|
|
|
m_Map->m_CenterZ = CenterZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int NumPixels = m_Map->GetNumPixels();
|
|
|
|
m_Map->m_Data.resize(NumPixels);
|
|
|
|
|
2014-02-14 09:21:16 -05:00
|
|
|
CurrLine = a_NBT.FindChildByName(Data, "colors");
|
|
|
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
|
|
|
|
{
|
2014-10-21 08:20:06 -04:00
|
|
|
memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels);
|
2014-02-14 09:21:16 -05:00
|
|
|
}
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-02-13 14:36:24 -05:00
|
|
|
cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
|
|
|
|
{
|
|
|
|
AString DataPath;
|
2015-05-09 03:25:09 -04:00
|
|
|
Printf(DataPath, "%s%cdata", a_WorldName.c_str(), cFile::PathSeparator);
|
2014-02-13 14:36:24 -05:00
|
|
|
|
2015-05-09 03:25:09 -04:00
|
|
|
Printf(m_Path, "%s%cidcounts.dat", DataPath.c_str(), cFile::PathSeparator);
|
2014-02-13 14:36:24 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2015-05-19 14:32:10 -04:00
|
|
|
m_MapCount = static_cast<unsigned int>(NBT.GetShort(CurrLine) + 1);
|
2014-02-17 09:27:12 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_MapCount = 0;
|
2014-02-13 14:36:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cIDCountSerializer::Save(void)
|
|
|
|
{
|
|
|
|
cFastNBTWriter Writer;
|
|
|
|
|
2014-02-17 09:27:12 -05:00
|
|
|
if (m_MapCount > 0)
|
|
|
|
{
|
2015-05-19 14:32:10 -04:00
|
|
|
Writer.AddShort("map", static_cast<Int16>(m_MapCount - 1));
|
2014-02-17 09:27:12 -05:00
|
|
|
}
|
2014-02-13 14:36:24 -05:00
|
|
|
|
|
|
|
Writer.Finish();
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-13 14:36:24 -05:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-02-13 10:13:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
|