summaryrefslogtreecommitdiffstats
path: root/src/WorldStorage/WSSAnvil.h
blob: 88d1a6bd422276edd237ec3b142ab66c9f448aa2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
#pragma once

#include "../BlockEntities/BlockEntity.h"
#include "WorldStorage.h"
#include "FastNBT.h"
#include "StringCompression.h"





// fwd:
class cItem;
class cItemGrid;
class cMonster;
class cProjectileEntity;
class cHangingEntity;
class cUUID;
class ChunkBlockData;





/** Implements the Anvil world storage schema. */
class cWSSAnvil : public cWSSchema
{
	using Super = cWSSchema;

  public:
	cWSSAnvil(cWorld * a_World, int a_CompressionFactor);
	virtual ~cWSSAnvil() override;

  protected:
	enum
	{
		/** Maximum number of chunks in an MCA file - also the count of the header items */
		MCA_MAX_CHUNKS = 32 * 32,

		/** The MCA header is 8 KiB */
		MCA_HEADER_SIZE = MCA_MAX_CHUNKS * 8,

		/** There are 5 bytes of header in front of each chunk */
		MCA_CHUNK_HEADER_LENGTH = 5,
	};


	class cMCAFile
	{
	  public:
		cMCAFile(cWSSAnvil & a_ParentSchema, const AString & a_FileName, int a_RegionX, int a_RegionZ);

		bool GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);
		bool SetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data);

		int GetRegionX() const { return m_RegionX; }
		int GetRegionZ() const { return m_RegionZ; }
		const AString & GetFileName() const { return m_FileName; }

	  protected:
		cWSSAnvil & m_ParentSchema;

		int m_RegionX;
		int m_RegionZ;
		cFile m_File;
		AString m_FileName;

		// The header, copied from the file so we don't have to seek to it all the time
		// First 1024 entries are chunk locations - the 3 + 1 byte sector-offset and sector-count
		unsigned m_Header[MCA_MAX_CHUNKS];

		// Chunk timestamps, following the chunk headers
		unsigned m_TimeStamps[MCA_MAX_CHUNKS];

		/** Finds a free location large enough to hold a_Data. Returns the sector number. */
		unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, size_t a_DataSize);

		/** Opens a MCA file either for a Read operation (fails if doesn't exist) or for a Write operation (creates new
		 * if not found) */
		bool OpenFile(bool a_IsForReading);
	};

	/** Protects m_Files against multithreaded access. */
	cCriticalSection m_CS;

	/** A MRU cache of MCA files.
	Protected against multithreaded access by m_CS. */
	std::list<std::shared_ptr<cMCAFile>> m_Files;

	Compression::Extractor m_Extractor;
	Compression::Compressor m_Compressor;

	/** Reports that the specified chunk failed to load and saves the chunk data to an external file. */
	void ChunkLoadFailed(
		const cChunkCoords a_ChunkCoords,
		const AString & a_Reason,
		ContiguousByteBufferView a_ChunkDataToSave
	);

	/** Gets chunk data from the correct file; locks file CS as needed */
	bool GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);

	/** Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer */
	const std::byte * GetSectionData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, size_t a_Length);

	/** Sets chunk data into the correct file; locks file CS as needed */
	bool SetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data);

	/** Loads the chunk from the data (no locking needed) */
	bool LoadChunkFromData(const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data);

	/** Saves the chunk into datastream (no locking needed) */
	Compression::Result SaveChunkToData(const cChunkCoords & a_Chunk);

	/** Loads the chunk from NBT data (no locking needed).
	a_RawChunkData is the raw (compressed) chunk data, used for offloading when chunk loading fails. */
	bool LoadChunkFromNBT(
		const cChunkCoords & a_Chunk,
		const cParsedNBT & a_NBT,
		ContiguousByteBufferView a_RawChunkData
	);

	/** Loads the chunk's biome map into a_BiomeMap if biomes present and valid; returns false otherwise. */
	bool LoadBiomeMapFromNBT(cChunkDef::BiomeMap & a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx);

	/** Loads the chunk's height map into a_HeightMap if heights present and valid; returns false otherwise. */
	bool LoadHeightMapFromNBT(cChunkDef::HeightMap & a_HeightMap, const cParsedNBT & a_NBT, int a_TagIdx);

	/** Loads the chunk's entities from NBT data (a_Tag is the Level\\Entities list tag; may be -1) */
	void LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_Tag);

	/** Loads the chunk's BlockEntities from NBT data (a_Tag is the Level\\TileEntities list tag; may be -1) */
	void LoadBlockEntitiesFromNBT(
		cBlockEntities & a_BlockEntitites,
		const cParsedNBT & a_NBT,
		int a_Tag,
		const ChunkBlockData & a_BlockData
	);

	/** Loads the data for a block entity from the specified NBT tag.
	Returns the loaded block entity, or nullptr upon failure. */
	OwnedBlockEntity LoadBlockEntityFromNBT(
		const cParsedNBT & a_NBT,
		int a_Tag,
		Vector3i a_Pos,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta
	);

	/** Loads a cItem contents from the specified NBT tag; returns true if successful. Doesn't load the Slot tag */
	bool LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx);

	/** Loads contentents of an Items[] list tag into a cItemGrid
	ItemGrid begins at the specified slot offset
	Slots outside the ItemGrid range are ignored */
	void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0);

	/** Decodes the text contained within a sign.
	Older versions used direct string representation, newer versions use JSON-formatted string.
	This function extracts the text from either version. */
	AString DecodeSignLine(const AString & a_Line);

	/** Returns true iff the "id" child tag inside the specified tag equals (case-sensitive) any of the specified
	expected types. Logs a warning to the console on mismatch. The coordinates are used only for the log message. */
	bool CheckBlockEntityType(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		const AStringVector & a_ExpectedTypes,
		Vector3i a_Pos
	);

	OwnedBlockEntity LoadBannerFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadBeaconFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadBedFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadBrewingstandFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadChestFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadCommandBlockFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadDispenserFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadDropperFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadEnchantingTableFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadEnderChestFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadEndPortalFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadFlowerPotFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadFurnaceFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadHopperFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadJukeboxFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadMobHeadFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadMobSpawnerFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadNoteBlockFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);
	OwnedBlockEntity LoadSignFromNBT(
		const cParsedNBT & a_NBT,
		int a_TagIdx,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		Vector3i a_Pos
	);

	void LoadEntityFromNBT(
		cEntityList & a_Entities,
		const cParsedNBT & a_NBT,
		int a_EntityTagIdx,
		std::string_view a_EntityName
	);

	void LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadLeashKnotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);

	void LoadOldMinecartFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);

	void LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);

	void LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadCatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadCodFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadDolphinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadDonkeyFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadDrownedFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadElderGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEndermiteFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadEvokerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadFoxFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadHoglinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadHuskFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadIllusionerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadLlamaFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadMuleFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPandaFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadParrotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPhantomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPiglinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPiglinBruteFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPolarBearFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadPufferfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadRavagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSalmonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadShulkerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSkeletonHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadStrayFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadStriderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadTraderLlamaFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadTropicalFishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadTurtleFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadVexFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadVindicatorFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadWanderingTraderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadWitherSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadZoglinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadZombieHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadZombifiedPiglinFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
	void LoadZombieVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);

	/** Loads the owner name and UUID from the entity at the specified NBT tag.
	Returns a pair of {name, uuid}. If the entity is not owned, name is an empty string and uuid is nil. */
	std::pair<AString, cUUID> LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx);

	/** 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 the position to where is leashed the monster */
	void LoadLeashToPosition(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, Vector3i & a_AbsPos);

	/** Gets the correct MCA file either from cache or from disk, manages the m_MCAFiles cache; assumes m_CS is locked
	 */
	std::shared_ptr<cMCAFile> LoadMCAFile(const cChunkCoords & a_Chunk);

	// cWSSchema overrides:
	virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
	virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
	virtual const AString GetName() const override { return "anvil"; }
};