aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/ConsoleSaveFileSplit.h
blob: 0b2017a2ef602ecf7cce41b1d763bf88c52b9e3f (plain)
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
#pragma once

#include "FileHeader.h"
#include "ConsoleSavePath.h"
#include "ConsoleSaveFile.h"

class ProgressRenderer;

class ConsoleSaveFileSplit : public ConsoleSaveFile
{
private:
	FileHeader header;

	static const int WRITE_BANDWIDTH_BYTESPERSECOND = 1048576;						// Average bytes per second we will cap to when writing region files during the tick() method
	static const int WRITE_BANDWIDTH_MEASUREMENT_PERIOD_SECONDS = 10;				// Time period over which the bytes per second average is calculated
	static const int WRITE_TICK_RATE_MS = 500;										// Time between attempts to work out which regions we should write during the tick
	static const int WRITE_MAX_WRITE_PER_TICK = WRITE_BANDWIDTH_BYTESPERSECOND;		// Maximum number of bytes we can add in a single tick

	class WriteHistory
	{
	public:
		int64_t			writeTime;
		unsigned int	writeSize;
	} ;

	class DirtyRegionFile
	{
	public:
		int64_t			lastWritten;
		unsigned int	fileRef;
		bool			operator<(const DirtyRegionFile& rhs) { return lastWritten < rhs.lastWritten; }
	};

	class RegionFileReference
	{
	public:
		RegionFileReference(int index, unsigned int regionIndex, unsigned int length = 0, unsigned char *data = NULL);
		~RegionFileReference();
		void			Compress();				// Compress from data to dataCompressed
		void			Decompress();			// Decompress from dataCompressed -> data
		unsigned int	GetCompressedSize();	// Gets byte size for what this region will compress to
		void			ReleaseCompressed();	// Release dataCompressed
		FileEntry		*fileEntry;
		unsigned char	*data;				
		unsigned char   *dataCompressed;
		unsigned int	dataCompressedSize;
		int				index;
		bool			dirty;
		int64_t			lastWritten;
	};
	unordered_map<unsigned int, RegionFileReference *> regionFiles;
	vector<WriteHistory> writeHistory;
	int64_t				m_lastTickTime;

	FileEntry *GetRegionFileEntry(unsigned int regionIndex);

	wstring m_fileName;
	bool m_autosave;

//	HANDLE hHeap;
	static void *pvHeap;
	static unsigned int pagesCommitted;
#ifdef _LARGE_WORLDS
	static const unsigned int CSF_PAGE_SIZE = 64 * 1024;
	static const unsigned int MAX_PAGE_COUNT = 32 * 1024; // 2GB virtual allocation
#else
	static const unsigned int CSF_PAGE_SIZE = 64 * 1024;
	static const unsigned int MAX_PAGE_COUNT = 1024;
#endif
	LPVOID pvSaveMem;

	CRITICAL_SECTION m_lock;

	void PrepareForWrite( FileEntry *file, DWORD nNumberOfBytesToWrite );
	void MoveDataBeyond(FileEntry *file, DWORD nNumberOfBytesToWrite);

	bool GetNumericIdentifierFromName(const wstring &fileName, unsigned int *idOut);
	wstring GetNameFromNumericIdentifier(unsigned int idIn);
	void processSubfilesForWrite();
	void processSubfilesAfterWrite();
public:
	static int SaveSaveDataCallback(LPVOID lpParam,bool bRes);
	static int SaveRegionFilesCallback(LPVOID lpParam,bool bRes);
	
private:
	void _init(const wstring &fileName, LPVOID pvSaveData, DWORD fileSize, ESavePlatform plat);

public:
	ConsoleSaveFileSplit(const wstring &fileName, LPVOID pvSaveData = NULL, DWORD fileSize = 0, bool forceCleanSave = false, ESavePlatform plat = SAVE_FILE_PLATFORM_LOCAL);
	ConsoleSaveFileSplit(ConsoleSaveFile *sourceSave, bool alreadySmallRegions = true, ProgressListener *progress = NULL);
	virtual ~ConsoleSaveFileSplit();

	// 4J Stu - Initial implementation is intended to have a similar interface to the standard Xbox file access functions

	virtual FileEntry *createFile( const ConsoleSavePath &fileName );
	virtual void deleteFile( FileEntry *file );

	virtual void setFilePointer(FileEntry *file,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod);
	virtual BOOL writeFile(	FileEntry *file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten );
	virtual BOOL zeroFile(FileEntry *file, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten);
	virtual BOOL readFile( FileEntry *file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead );
	virtual BOOL closeHandle( FileEntry *file );

	virtual void finalizeWrite();
	virtual void tick();

	virtual bool doesFileExist(ConsoleSavePath file);

	virtual void Flush(bool autosave, bool updateThumbnail = true);

#ifndef _CONTENT_PACKAGE
	virtual void DebugFlushToFile(void *compressedData = NULL, unsigned int compressedDataSize = 0);
#endif
	virtual unsigned int getSizeOnDisk();

	virtual wstring getFilename();

	virtual vector<FileEntry *> *getFilesWithPrefix(const wstring &prefix);
	virtual vector<FileEntry *> *getRegionFilesByDimension(unsigned int dimensionIndex);

#if defined(__PS3__) || defined(__ORBIS__)
	virtual wstring getPlayerDataFilenameForLoad(const PlayerUID& pUID);
	virtual wstring getPlayerDataFilenameForSave(const PlayerUID& pUID);
	virtual vector<FileEntry *> *getValidPlayerDatFiles();
#endif //__PS3__

	virtual int getSaveVersion();
	virtual int getOriginalSaveVersion();

	virtual void LockSaveAccess();
	virtual void ReleaseSaveAccess();

	virtual ESavePlatform getSavePlatform();
	virtual bool isSaveEndianDifferent();
	virtual void setLocalPlatform();
	virtual void setPlatform(ESavePlatform plat);
	virtual ByteOrder getSaveEndian();
	virtual ByteOrder getLocalEndian();
	virtual void setEndian(ByteOrder endian);

	virtual void ConvertRegionFile(File sourceFile);
	virtual void ConvertToLocalPlatform();
};