summaryrefslogblamecommitdiffstats
path: root/src/WorldStorage/MapSerializer.cpp
blob: 6f0449041187667f57f67d05d4495ec324223ad7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                 
                     








                                                                        
                                                                                
 
                                                                                                 
























































































                                                                                                       
                                                         
                                                                          
















                                                             
                                                                     
         
                                                                           
                                       


                                                            
                                                                     


                                                                            




                                                                                                     


                                                        
                                                                      
         
                                                                            



                                     



                                                         
                                                                      
         
                                                                             



                                     



                                                          
                                                                    





                                                          
                                                                    







                                                       


                                                                          
                                                                                 
         







                    


                                                                                   
                                                                                
 
                                                                                   




























                                                                     




                                                             












                                   



                                                       

























                                                                                   


 

// 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%cdata", a_WorldName.c_str(), cFile::PathSeparator);

	Printf(m_Path, "%s%cmap_%i.dat", DataPath.c_str(), cFile::PathSeparator, 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.data(), 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) && (a_NBT.GetType(CurrLine) == TAG_Byte))
	{
		unsigned int Scale = (unsigned int)a_NBT.GetByte(CurrLine);
		m_Map->SetScale(Scale);
	}

	CurrLine = a_NBT.FindChildByName(Data, "dimension");
	if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte))
	{
		eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
		
		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;
		}
	}

	CurrLine = a_NBT.FindChildByName(Data, "width");
	if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
	{
		unsigned int Width = (unsigned int)a_NBT.GetShort(CurrLine);
		if (Width != 128)
		{
			return false;
		}
		m_Map->m_Width = Width;
	}

	CurrLine = a_NBT.FindChildByName(Data, "height");
	if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
	{
		unsigned int Height = (unsigned int)a_NBT.GetShort(CurrLine);
		if (Height >= 256)
		{
			return false;
		}
		m_Map->m_Height = Height;
	}

	CurrLine = a_NBT.FindChildByName(Data, "xCenter");
	if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
	{
		int CenterX = a_NBT.GetInt(CurrLine);
		m_Map->m_CenterX = CenterX;
	}

	CurrLine = a_NBT.FindChildByName(Data, "zCenter");
	if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
	{
		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.data(), a_NBT.GetData(CurrLine), NumPixels);
	}

	return true;
}





cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
{
	AString DataPath;
	Printf(DataPath, "%s%cdata", a_WorldName.c_str(), cFile::PathSeparator);

	Printf(m_Path, "%s%cidcounts.dat", DataPath.c_str(), cFile::PathSeparator);

	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;
}