summaryrefslogtreecommitdiffstats
path: root/source/WSSAnvil.h
blob: 85b4fcaf115db7189d6d4b3eda10edf182543720 (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

// WSSAnvil.h

// Interfaces to the cWSSAnvil class representing the Anvil world storage scheme




#pragma once

#include "WorldStorage.h"
#include "FastNBT.h"





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





// fwd: "NBT.h"
class cNBTTag;
class cNBTList;
class cNBTCompound;





class cWSSAnvil :
	public cWSSchema
{
	typedef cWSSchema super;
	
public:

	cWSSAnvil(cWorld * a_World);
	virtual ~cWSSAnvil();
	
protected:

	class cMCAFile
	{
	public:
	
		cMCAFile(const AString & a_FileName, int a_RegionX, int a_RegionZ);
		
		bool GetChunkData  (const cChunkCoords & a_Chunk, AString & a_Data);
		bool SetChunkData  (const cChunkCoords & a_Chunk, const AString & a_Data);
		bool EraseChunkData(const cChunkCoords & a_Chunk);
		
		int             GetRegionX (void) const {return m_RegionX; }
		int             GetRegionZ (void) const {return m_RegionZ; }
		const AString & GetFileName(void) const {return m_FileName; }
		
	protected:
	
		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, are unused by MCS
		
		/// Finds a free location large enough to hold a_Data. Gets a hint of the chunk coords, places the data there if it fits. Returns the sector number.
		unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, const AString & a_Data);
	} ;
	typedef std::list<cMCAFile *> cMCAFiles;
	
	cCriticalSection m_CS;
	cMCAFiles        m_Files;  // a MRU cache of MCA files

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

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

	/// Loads the chunk from the data (no locking needed)
	bool LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data);
	
	/// Saves the chunk into datastream (no locking needed)
	bool SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data);
	
	/// Loads the chunk from NBT data (no locking needed)
	bool LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT);
	
	/// Saves the chunk into NBT data using a_Writer; returns true on success
	bool SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer);
	
	/// 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(cBlockEntityList & a_BlockEntitites, const cParsedNBT & a_NBT, int a_Tag);
	
	void LoadChestFromNBT(cBlockEntityList & a_BlockEntities, 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, int & a_X, int & a_Y, int & a_Z);
	
	/// Gets the correct MCA file either from cache or from disk, manages the m_MCAFiles cache; assumes m_CS is locked
	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);
		
	// cWSSchema overrides:
	virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
	virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
	virtual const AString GetName(void) const override {return "anvil"; }
} ;