Cuberite
A lightweight, fast and extensible game server for Minecraft
MapSerializer.cpp
Go to the documentation of this file.
1 
2 // MapSerializer.cpp
3 
4 
5 #include "Globals.h"
6 #include "MapSerializer.h"
7 #include "OSSupport/GZipFile.h"
8 #include "FastNBT.h"
9 
10 #include "../Map.h"
11 #include "../World.h"
12 
13 
14 
15 
16 
17 cMapSerializer::cMapSerializer(const AString & a_WorldName, cMap * a_Map):
18  m_Map(a_Map)
19 {
20  auto DataPath = fmt::format(FMT_STRING("{}{}data"), a_WorldName, cFile::PathSeparator());
21  m_Path = fmt::format(FMT_STRING("{}{}map_{}.dat"), DataPath, cFile::PathSeparator(), a_Map->GetID());
22  cFile::CreateFolder(DataPath);
23 }
24 
25 
26 
27 
28 
30 {
31  const auto Data = GZipFile::ReadRestOfFile(m_Path);
32  const cParsedNBT NBT(Data.GetView());
33 
34  if (!NBT.IsValid())
35  {
36  // NBT Parsing failed
37  return false;
38  }
39 
40  return LoadMapFromNBT(NBT);
41 }
42 
43 
44 
45 
46 
48 {
49  cFastNBTWriter Writer;
50  SaveMapToNBT(Writer);
51  Writer.Finish();
52 
53  #ifndef NDEBUG
54  cParsedNBT TestParse(Writer.GetResult());
55  ASSERT(TestParse.IsValid());
56  #endif // !NDEBUG
57 
58  GZipFile::Write(m_Path, Writer.GetResult());
59 
60  return true;
61 }
62 
63 
64 
65 
66 
68 {
69  a_Writer.BeginCompound("data");
70 
71  a_Writer.AddByte("scale", static_cast<Byte>(m_Map->GetScale()));
72  a_Writer.AddByte("dimension", static_cast<Byte>(m_Map->GetDimension()));
73 
74  a_Writer.AddShort("width", static_cast<Int16>(m_Map->GetWidth()));
75  a_Writer.AddShort("height", static_cast<Int16>(m_Map->GetHeight()));
76 
77  a_Writer.AddInt("xCenter", m_Map->GetCenterX());
78  a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
79 
80  const cMap::cColorList & Data = m_Map->GetData();
81  a_Writer.AddByteArray("colors", reinterpret_cast<const char *>(Data.data()), Data.size());
82 
83  a_Writer.EndCompound();
84 }
85 
86 
87 
88 
89 
91 {
92  int Data = a_NBT.FindChildByName(0, "data");
93  if (Data < 0)
94  {
95  return false;
96  }
97 
98  int CurrLine = a_NBT.FindChildByName(Data, "scale");
99  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte))
100  {
101  unsigned int Scale = static_cast<unsigned int>(a_NBT.GetByte(CurrLine));
102  m_Map->SetScale(Scale);
103  }
104 
105  CurrLine = a_NBT.FindChildByName(Data, "dimension");
106  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte))
107  {
108  eDimension Dimension = static_cast<eDimension>(a_NBT.GetByte(CurrLine));
109 
110  if (Dimension != m_Map->m_World->GetDimension())
111  {
112  // TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c.
113  return false;
114  }
115  }
116 
117  CurrLine = a_NBT.FindChildByName(Data, "width");
118  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
119  {
120  unsigned int Width = static_cast<unsigned int>(a_NBT.GetShort(CurrLine));
121  if (Width != 128)
122  {
123  return false;
124  }
125  m_Map->m_Width = Width;
126  }
127 
128  CurrLine = a_NBT.FindChildByName(Data, "height");
129  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short))
130  {
131  unsigned int Height = static_cast<unsigned int>(a_NBT.GetShort(CurrLine));
132  if (Height >= cChunkDef::Height)
133  {
134  return false;
135  }
136  m_Map->m_Height = Height;
137  }
138 
139  CurrLine = a_NBT.FindChildByName(Data, "xCenter");
140  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
141  {
142  int CenterX = a_NBT.GetInt(CurrLine);
143  m_Map->m_CenterX = CenterX;
144  }
145 
146  CurrLine = a_NBT.FindChildByName(Data, "zCenter");
147  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int))
148  {
149  int CenterZ = a_NBT.GetInt(CurrLine);
150  m_Map->m_CenterZ = CenterZ;
151  }
152 
153  unsigned int NumPixels = m_Map->GetNumPixels();
154  m_Map->m_Data.resize(NumPixels);
155 
156  CurrLine = a_NBT.FindChildByName(Data, "colors");
157  if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
158  {
159  memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels);
160  }
161 
162  return true;
163 }
164 
165 
166 
167 
168 
169 cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
170 {
171  auto DataPath = fmt::format(FMT_STRING("{}{}data"), a_WorldName, cFile::PathSeparator());
172  m_Path = fmt::format(FMT_STRING("{}{}idcounts.dat"), DataPath, cFile::PathSeparator());
173  cFile::CreateFolder(DataPath);
174 }
175 
176 
177 
178 
179 
181 {
183  if (Data.empty())
184  {
185  return false;
186  }
187 
188  // NOTE: idcounts.dat is not compressed (raw format)
189 
190  // Parse the NBT data:
191  cParsedNBT NBT({ reinterpret_cast<const std::byte *>(Data.data()), Data.size() });
192  if (!NBT.IsValid())
193  {
194  // NBT Parsing failed
195  return false;
196  }
197 
198  int CurrLine = NBT.FindChildByName(0, "map");
199  if (CurrLine >= 0)
200  {
201  m_MapCount = static_cast<unsigned int>(NBT.GetShort(CurrLine) + 1);
202  }
203  else
204  {
205  m_MapCount = 0;
206  }
207 
208  return true;
209 }
210 
211 
212 
213 
214 
216 {
217  cFastNBTWriter Writer;
218 
219  if (m_MapCount > 0)
220  {
221  Writer.AddShort("map", static_cast<Int16>(m_MapCount - 1));
222  }
223 
224  Writer.Finish();
225 
226  #ifndef NDEBUG
227  cParsedNBT TestParse(Writer.GetResult());
228  ASSERT(TestParse.IsValid());
229  #endif // !NDEBUG
230 
231  cFile File;
232  if (!File.Open(m_Path, cFile::fmWrite))
233  {
234  return false;
235  }
236 
237  // NOTE: idcounts.dat is not compressed (raw format)
238 
239  File.Write(Writer.GetResult().data(), Writer.GetResult().size());
240  File.Close();
241 
242  return true;
243 }
eDimension
Dimension of a world.
Definition: Defines.h:231
signed short Int16
Definition: Globals.h:153
#define ASSERT(x)
Definition: Globals.h:276
unsigned char Byte
Definition: Globals.h:161
std::string AString
Definition: StringUtils.h:11
@ TAG_ByteArray
Definition: FastNBT.h:39
@ TAG_Short
Definition: FastNBT.h:34
@ TAG_Byte
Definition: FastNBT.h:33
@ TAG_Int
Definition: FastNBT.h:35
void Write(const std::string &a_FileName, ContiguousByteBufferView a_Contents)
Writes a_Contents into file, compressing it along the way.
Definition: GZipFile.cpp:27
Compression::Result ReadRestOfFile(const std::string &a_FileName)
Reads the rest of the file and returns the decompressed contents.
Definition: GZipFile.cpp:14
static const int Height
Definition: ChunkDef.h:125
Encapsulates an in-game world map.
Definition: Map.h:83
unsigned int m_Height
Definition: Map.h:180
eDimension GetDimension(void) const
Definition: Map.cpp:185
unsigned int GetHeight(void) const
Definition: Map.h:145
int m_CenterX
Definition: Map.h:185
int m_CenterZ
Definition: Map.h:186
const cColorList & GetData(void) const
Definition: Map.h:170
unsigned int GetWidth(void) const
Definition: Map.h:144
cWorld * m_World
Definition: Map.h:191
void SetScale(unsigned int a_Scale)
Definition: Map.h:138
unsigned int GetNumPixels(void) const
Definition: Map.cpp:256
int GetCenterZ(void) const
Definition: Map.h:150
unsigned int GetScale(void) const
Definition: Map.h:147
int GetCenterX(void) const
Definition: Map.h:149
std::vector< ColorID > cColorList
Definition: Map.h:109
unsigned int GetID(void) const
Definition: Map.h:152
unsigned int m_Width
Definition: Map.h:179
cColorList m_Data
Column-major array of colours.
Definition: Map.h:189
Definition: File.h:38
static bool CreateFolder(const AString &a_FolderPath)
Creates a new folder with the specified name.
Definition: File.cpp:454
static char PathSeparator()
Definition: File.h:42
@ fmWrite
Definition: File.h:55
bool Open(const AString &iFileName, eMode iMode)
Definition: File.cpp:52
static AString ReadWholeFile(const AString &a_FileName)
Returns the entire contents of the specified file as a string.
Definition: File.cpp:573
int Write(const void *a_Buffer, size_t a_NumBytes)
Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written,...
Definition: File.cpp:180
void Close(void)
Definition: File.cpp:102
virtual eDimension GetDimension(void) const override
Definition: World.h:133
Parses and contains the parsed data Also implements data accessor functions for tree traversal and va...
Definition: FastNBT.h:153
Int16 GetShort(int a_Tag) const
Returns the value stored in a Short tag.
Definition: FastNBT.h:227
const std::byte * GetData(int a_Tag) const
Returns the data stored in this tag.
Definition: FastNBT.h:191
bool IsValid(void) const
Definition: FastNBT.h:157
eTagType GetType(int a_Tag) const
Definition: FastNBT.h:210
int FindChildByName(int a_Tag, const AString &a_Name) const
Returns the direct child tag of the specified name, or -1 if no such tag.
Definition: FastNBT.h:199
unsigned char GetByte(int a_Tag) const
Returns the value stored in a Byte tag.
Definition: FastNBT.h:220
Int32 GetInt(int a_Tag) const
Returns the value stored in an Int tag.
Definition: FastNBT.h:234
void AddByteArray(const AString &a_Name, const char *a_Value, size_t a_NumElements)
Definition: FastNBT.cpp:628
void AddByte(const AString &a_Name, unsigned char a_Value)
Definition: FastNBT.cpp:551
void AddShort(const AString &a_Name, Int16 a_Value)
Definition: FastNBT.cpp:561
void AddInt(const AString &a_Name, Int32 a_Value)
Definition: FastNBT.cpp:572
void Finish(void)
Definition: FastNBT.cpp:674
void EndCompound(void)
Definition: FastNBT.cpp:499
void BeginCompound(const AString &a_Name)
Definition: FastNBT.cpp:481
ContiguousByteBufferView GetResult(void) const
Definition: FastNBT.h:351
void SaveMapToNBT(cFastNBTWriter &a_Writer)
bool LoadMapFromNBT(const cParsedNBT &a_NBT)
bool Load(void)
Try to load the map.
cMapSerializer(const AString &a_WorldName, cMap *a_Map)
bool Save(void)
Try to save the map.
bool Save(void)
Try to save the ID counts.
unsigned int m_MapCount
Definition: MapSerializer.h:79
bool Load(void)
Try to load the ID counts.
cIDCountSerializer(const AString &a_WorldName)