Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
15 kB · 497 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498#include "stdafx.h"#include "System.h"#include "InputOutputStream.h"#include "File.h"#include "RegionFile.h"
#include "ConsoleSaveFile.h"
byteArray RegionFile::emptySector(SECTOR_BYTES);
RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path){ _lastModified = 0;
m_saveFile = saveFile;
offsets = new int[SECTOR_INTS]; memset(offsets,0,SECTOR_BYTES); chunkTimestamps = new int[SECTOR_INTS]; memset(chunkTimestamps,0,SECTOR_BYTES);
/* 4J Jev, using files instead of strings: strncpy(fileName,path,MAX_PATH_SIZE); */
fileName = path;
// debugln("REGION LOAD " + fileName);
sizeDelta = 0;
// 4J - removed try/catch// try { /* 4J - Removed as _lastModifed not used and this is always failing as checking wrong thing if( path->exists() ) { _lastModified = path->lastModified(); } */
fileEntry = m_saveFile->createFile( fileName->getName() ); m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_END );
if ( fileEntry->getFileSize() < SECTOR_BYTES) { // 4J altered - the original code used to write out 2 empty sectors here, which we don't want to do as we might be at a point where we shouldn't be touching the save file. // This now happens in insertInitialSectors when we do a first write to the region m_bIsEmpty = true;
sizeDelta += SECTOR_BYTES * 2; } else { m_bIsEmpty = false; }
//if ((GetFileSize(file,NULL) & 0xfff) != 0) if ((fileEntry->getFileSize() & 0xfff) != 0) { //byte zero = 0; DWORD numberOfBytesWritten = 0; DWORD bytesToWrite = 0x1000 - (fileEntry->getFileSize() & 0xfff); byte *zeroBytes = new byte[ bytesToWrite ]; ZeroMemory(zeroBytes, bytesToWrite);
/* the file size is not a multiple of 4KB, grow it */ m_saveFile->writeFile(fileEntry,zeroBytes,bytesToWrite,&numberOfBytesWritten);
delete [] zeroBytes; }
/* set up the available sector map */ int nSectors; if( m_bIsEmpty ) // 4J - added this case for our empty files that we now don't create { nSectors = 2; } else { nSectors = (int) fileEntry->getFileSize() / SECTOR_BYTES; } sectorFree = new vector<bool>; sectorFree->reserve(nSectors);
for (int i = 0; i < nSectors; ++i) { sectorFree->push_back(true); }
sectorFree->at(0) = false; // chunk offset table sectorFree->at(1) = false; // for the last modified info
m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_BEGIN ); for (int i = 0; i < SECTOR_INTS; ++i) { unsigned int offset = 0; DWORD numberOfBytesRead = 0; if( !m_bIsEmpty ) // 4J added condition, don't read back if we've just created an empty file as we don't immediately write this anymore { m_saveFile->readFile(fileEntry, &offset, 4, &numberOfBytesRead);
if(saveFile->isSaveEndianDifferent()) System::ReverseULONG(&offset);
} offsets[i] = offset; if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree->size()) { for (unsigned int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum) { sectorFree->at((offset >> 8) + sectorNum) = false; } } } for (int i = 0; i < SECTOR_INTS; ++i) { int lastModValue = 0; DWORD numberOfBytesRead = 0; if( !m_bIsEmpty ) // 4J added condition, don't read back if we've just created an empty file as we don't immediately write this anymore { m_saveFile->readFile(fileEntry, &lastModValue, 4, &numberOfBytesRead);
if(saveFile->isSaveEndianDifferent()) System::ReverseINT(&lastModValue); } chunkTimestamps[i] = lastModValue; }
// } catch (IOException e) {// e.printStackTrace();// }}
void RegionFile::writeAllOffsets() // used for the file ConsoleSaveFile conversion between platforms{ if(m_bIsEmpty == false) { // save all the offsets and timestamps m_saveFile->LockSaveAccess();
DWORD numberOfBytesWritten = 0; m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_BEGIN ); m_saveFile->writeFile(fileEntry,offsets, SECTOR_BYTES ,&numberOfBytesWritten);
numberOfBytesWritten = 0; m_saveFile->setFilePointer( fileEntry, SECTOR_BYTES, NULL, FILE_BEGIN ); m_saveFile->writeFile(fileEntry, chunkTimestamps, SECTOR_BYTES, &numberOfBytesWritten);
m_saveFile->ReleaseSaveAccess(); }
}RegionFile::~RegionFile(){ delete[] offsets; delete[] chunkTimestamps; delete sectorFree; m_saveFile->closeHandle( fileEntry );}
__int64 RegionFile::lastModified(){ return _lastModified;}
int RegionFile::getSizeDelta() // TODO - was synchronized{ int ret = sizeDelta; sizeDelta = 0; return ret;}
DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was synchronized{ if (outOfBounds(x, z)) {// debugln("READ", x, z, "out of bounds"); return NULL; }
// 4J - removed try/catch// try { int offset = getOffset(x, z); if (offset == 0) { // debugln("READ", x, z, "miss"); return NULL; }
unsigned int sectorNumber = offset >> 8; unsigned int numSectors = offset & 0xFF;
if (sectorNumber + numSectors > sectorFree->size()) {// debugln("READ", x, z, "invalid sector"); return NULL; }
m_saveFile->LockSaveAccess();
//SetFilePointer(file,sectorNumber * SECTOR_BYTES,0,FILE_BEGIN); m_saveFile->setFilePointer( fileEntry, sectorNumber * SECTOR_BYTES, NULL, FILE_BEGIN); unsigned int length; unsigned int decompLength; unsigned int readDecompLength;
DWORD numberOfBytesRead = 0;
// 4J - this differs a bit from the java file format. Java has length stored as an int, then a type as a byte, then length-1 bytes of data // We store length and decompression length as ints, then length bytes of xbox LZX compressed data m_saveFile->readFile(fileEntry,&length,4,&numberOfBytesRead);
if(m_saveFile->isSaveEndianDifferent()) System::ReverseULONG(&length);
// Using to bit of length to signify that this data was compressed with RLE method bool useRLE = false; if( length & 0x80000000 ) { useRLE = true; length &= 0x7fffffff; } m_saveFile->readFile(fileEntry,&decompLength,4,&numberOfBytesRead);
if(m_saveFile->isSaveEndianDifferent()) System::ReverseULONG(&decompLength);
if (length > SECTOR_BYTES * numSectors) {// debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors); m_saveFile->ReleaseSaveAccess(); return NULL; }
MemSect(50); byte *data = new byte[length]; byte *decomp = new byte[decompLength]; MemSect(0); readDecompLength = decompLength; m_saveFile->readFile(fileEntry,data,length,&numberOfBytesRead);
m_saveFile->ReleaseSaveAccess();
Compression::getCompression()->SetDecompressionType(m_saveFile->getSavePlatform()); // if this save is from another platform, set the correct decompression type
if( useRLE ) { Compression::getCompression()->DecompressLZXRLE(decomp, &readDecompLength, data, length ); } else { Compression::getCompression()->Decompress(decomp, &readDecompLength, data, length ); }
Compression::getCompression()->SetDecompressionType(SAVE_FILE_PLATFORM_LOCAL); // and then set the decompression back to the local machine's standard type
delete [] data;
// 4J - was InflaterInputStream in here too, but we've already decompressed DataInputStream *ret = new DataInputStream(new ByteArrayInputStream( byteArray( decomp, readDecompLength) )); return ret;
// } catch (IOException e) {// debugln("READ", x, z, "exception");// return null;// }}
DataOutputStream *RegionFile::getChunkDataOutputStream(int x, int z){ // 4J - was DeflatorOutputStream in here too, but we've already compressed return new DataOutputStream( new ChunkBuffer(this, x, z)); }
/* write a chunk at (x,z) with length bytes of data to disk */void RegionFile::write(int x, int z, byte *data, int length) // TODO - was synchronized{ // 4J Stu - Do the compression here so that we know how much space we need to store the compressed data byte *compData = new byte[length + 2048]; // presuming compression is going to make this smaller... UPDATE - for some really small things this isn't the case. Added 2K on here to cover those. unsigned int compLength = length; Compression::getCompression()->CompressLZXRLE(compData,&compLength,data,length);
int sectorsNeeded = (compLength + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1;
// app.DebugPrintf(">>>>>>>>>>>>>> writing compressed data for 0x%.8x, %d %d\n",fileEntry->data.regionIndex,x,z);
// maximum chunk size is 1MB if (sectorsNeeded >= 256) { return; }
m_saveFile->LockSaveAccess(); { int offset = getOffset(x, z); int sectorNumber = offset >> 8; int sectorsAllocated = offset & 0xFF;
#ifndef _CONTENT_PACKAGE if(sectorNumber < 0) { __debugbreak(); }#endif
if (sectorNumber != 0 && sectorsAllocated == sectorsNeeded) { /* we can simply overwrite the old sectors */ // debug("SAVE", x, z, length, "rewrite"); #ifndef _CONTENT_PACKAGE //wprintf(L"Writing chunk (%d,%d) in %ls from current sector %d to %d\n", x,z, fileEntry->data.filename, sectorNumber, sectorNumber + sectorsNeeded - 1); #endif write(sectorNumber, compData, length, compLength); } else { /* we need to allocate new sectors */
/* mark the sectors previously used for this chunk as free */ for (int i = 0; i < sectorsAllocated; ++i) { sectorFree->at(sectorNumber + i) = true; } // 4J added - zero this now unused region of the file, so it can be better compressed until it is reused zero(sectorNumber, SECTOR_BYTES * sectorsAllocated);
PIXBeginNamedEvent(0,"Scanning for free space\n"); /* scan for a free space large enough to store this chunk */ int runStart = (int)(find(sectorFree->begin(),sectorFree->end(),true) - sectorFree->begin()); // 4J - was sectorFree.indexOf(true) int runLength = 0; if (runStart != -1) { for (unsigned int i = runStart; i < sectorFree->size(); ++i) { if (runLength != 0) { if (sectorFree->at(i)) runLength++; else runLength = 0; } else if (sectorFree->at(i)) { runStart = i; runLength = 1; } if (runLength >= sectorsNeeded) { break; } } } PIXEndNamedEvent();
if (runLength >= sectorsNeeded) { /* we found a free space large enough */ // debug("SAVE", x, z, length, "reuse"); sectorNumber = runStart; setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); #ifndef _CONTENT_PACKAGE //wprintf(L"Writing chunk (%d,%d) in %ls from old sector %d to %d\n", x,z, fileEntry->data.filename, sectorNumber, sectorNumber + sectorsNeeded - 1); #endif for (int i = 0; i < sectorsNeeded; ++i) { sectorFree->at(sectorNumber + i) = false; } write(sectorNumber, compData, length, compLength); } else { PIXBeginNamedEvent(0,"Expanding storage for %d sectors\n", sectorsNeeded); /* * no free space large enough found -- we need to grow the * file */ // debug("SAVE", x, z, length, "grow"); //SetFilePointer(file,0,0,FILE_END); m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_END );
sectorNumber = (int)sectorFree->size(); #ifndef _CONTENT_PACAKGE //wprintf(L"Writing chunk (%d,%d) in %ls from new sector %d to %d\n", x,z, fileEntry->data.filename, sectorNumber, sectorNumber + sectorsNeeded - 1); #endif DWORD numberOfBytesWritten = 0; for (int i = 0; i < sectorsNeeded; ++i) { //WriteFile(file,emptySector.data,SECTOR_BYTES,&numberOfBytesWritten,NULL); m_saveFile->writeFile(fileEntry,emptySector.data,SECTOR_BYTES,&numberOfBytesWritten); sectorFree->push_back(false); } sizeDelta += SECTOR_BYTES * sectorsNeeded;
write(sectorNumber, compData, length, compLength); setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); PIXEndNamedEvent(); } } setTimestamp(x, z, (int) (System::currentTimeMillis() / 1000L)); } m_saveFile->ReleaseSaveAccess();
// } catch (IOException e) {// e.printStackTrace();// }}
/* write a chunk data to the region file at specified sector number */void RegionFile::write(int sectorNumber, byte *data, int length, unsigned int compLength){ DWORD numberOfBytesWritten = 0; //SetFilePointer(file,sectorNumber * SECTOR_BYTES,0,FILE_BEGIN); m_saveFile->setFilePointer( fileEntry, sectorNumber * SECTOR_BYTES, NULL, FILE_BEGIN );
// 4J - this differs a bit from the java file format. Java has length stored as an int, then a type as a byte, then length-1 bytes of data // We store length and decompression length as ints, then length bytes of xbox LZX compressed data // 4J Stu - We need to do the compression at a level above this, where it is checking for free space
compLength |= 0x80000000; // 4J - signify that this has been encoded with RLE method ( see code in getChunkDataInputStream() for matching detection of this) m_saveFile->writeFile(fileEntry,&compLength,4,&numberOfBytesWritten); compLength &= 0x7fffffff; m_saveFile->writeFile(fileEntry,&length,4,&numberOfBytesWritten); m_saveFile->writeFile(fileEntry,data,compLength,&numberOfBytesWritten); delete[] data;}
void RegionFile::zero(int sectorNumber, int length){ DWORD numberOfBytesWritten = 0; //SetFilePointer(file,sectorNumber * SECTOR_BYTES,0,FILE_BEGIN); m_saveFile->setFilePointer( fileEntry, sectorNumber * SECTOR_BYTES, NULL, FILE_BEGIN ); m_saveFile->zeroFile( fileEntry, length, &numberOfBytesWritten );}
/* is this an invalid chunk coordinate? */bool RegionFile::outOfBounds(int x, int z){ return x < 0 || x >= 32 || z < 0 || z >= 32;}
int RegionFile::getOffset(int x, int z){ return offsets[x + z * 32];}
bool RegionFile::hasChunk(int x, int z){ return getOffset(x, z) != 0;}
// 4J added - write the initial two sectors that used to be written in the ctor when the file was emptyvoid RegionFile::insertInitialSectors(){ m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_BEGIN ); DWORD numberOfBytesWritten = 0; byte zeroBytes[ SECTOR_BYTES ]; ZeroMemory(zeroBytes, SECTOR_BYTES);
/* we need to write the chunk offset table */ m_saveFile->writeFile(fileEntry,zeroBytes,SECTOR_BYTES,&numberOfBytesWritten);
// write another sector for the timestamp info m_saveFile->writeFile(fileEntry,zeroBytes,SECTOR_BYTES,&numberOfBytesWritten);
m_bIsEmpty = false;}
void RegionFile::setOffset(int x, int z, int offset){ if( m_bIsEmpty ) { insertInitialSectors(); // 4J added }
DWORD numberOfBytesWritten = 0; offsets[x + z * 32] = offset; m_saveFile->setFilePointer( fileEntry, (x + z * 32) * 4, NULL, FILE_BEGIN ); m_saveFile->writeFile(fileEntry,&offset,4,&numberOfBytesWritten);}
void RegionFile::setTimestamp(int x, int z, int value){ if( m_bIsEmpty ) { insertInitialSectors(); // 4J added }
DWORD numberOfBytesWritten = 0; chunkTimestamps[x + z * 32] = value; m_saveFile->setFilePointer( fileEntry, SECTOR_BYTES + (x + z * 32) * 4, NULL, FILE_BEGIN ); m_saveFile->writeFile(fileEntry,&value,4,&numberOfBytesWritten);}
void RegionFile::close(){ m_saveFile->closeHandle( fileEntry );}