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.
32 kB · 1068 lines
C++
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069#include "stdafx.h"#include "StringHelpers.h"#include "ConsoleSaveFileOriginal.h"#include "File.h"#include <xuiapp.h>#include "compression.h"#include "..\Minecraft.Client\Minecraft.h"#include "..\Minecraft.Client\MinecraftServer.h"#include "..\Minecraft.Client\ServerLevel.h"#include "..\Minecraft.World\net.minecraft.world.level.h"#include "..\Minecraft.World\LevelData.h"#include "..\Minecraft.Client\Common\GameRules\LevelGenerationOptions.h"#include "..\Minecraft.World\net.minecraft.world.level.chunk.storage.h"
#ifdef _XBOX#define RESERVE_ALLOCATION MEM_RESERVE | MEM_LARGE_PAGES#define COMMIT_ALLOCATION MEM_COMMIT | MEM_LARGE_PAGES#else#define RESERVE_ALLOCATION MEM_RESERVE#define COMMIT_ALLOCATION MEM_COMMIT#endif
unsigned int ConsoleSaveFileOriginal::pagesCommitted = 0;void *ConsoleSaveFileOriginal::pvHeap = NULL;
ConsoleSaveFileOriginal::ConsoleSaveFileOriginal(const wstring &fileName, LPVOID pvSaveData /*= NULL*/, DWORD dFileSize /*= 0*/, bool forceCleanSave /*= false*/, ESavePlatform plat /*= SAVE_FILE_PLATFORM_LOCAL*/){ InitializeCriticalSectionAndSpinCount(&m_lock,5120);
// One time initialise of static stuff required for our storage if( pvHeap == NULL ) { // Reserve a chunk of 64MB of virtual address space for our saves, using 64KB pages. // We'll only be committing these as required to grow the storage we need, which will // the storage to grow without having to use realloc.
// AP - The Vita doesn't have virtual memory so a pretend system has been implemented in PSVitaStubs.cpp. // All access to the memory must be done via the access function as the pointer returned from VirtualAlloc // can't be used directly. pvHeap = VirtualAlloc(NULL, MAX_PAGE_COUNT * CSF_PAGE_SIZE, RESERVE_ALLOCATION, PAGE_READWRITE ); }
pvSaveMem = pvHeap; m_fileName = fileName;
DWORD fileSize = dFileSize;
// Load a save from the game rules bool bLevelGenBaseSave = false; LevelGenerationOptions *levelGen = app.getLevelGenerationOptions(); if( pvSaveData == NULL && levelGen != NULL && levelGen->requiresBaseSave()) { pvSaveData = levelGen->getBaseSaveData(fileSize); if(pvSaveData && fileSize != 0) bLevelGenBaseSave = true; }
if( pvSaveData == NULL || fileSize == 0) fileSize = StorageManager.GetSaveSize();
if( forceCleanSave ) fileSize = 0;
DWORD heapSize = max( fileSize, (DWORD)(1024 * 1024 * 2)); // 4J Stu - Our files are going to be bigger than 2MB so allocate high to start with
// Initially committ enough room to store headSize bytes (using CSF_PAGE_SIZE pages, so rounding up here). We should only ever have one save file at a time, // and the pages should be decommitted in the dtor, so pages committed should always be zero at this point. if( pagesCommitted != 0 ) {#ifndef _CONTENT_PACKAGE __debugbreak();#endif }
unsigned int pagesRequired = ( heapSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE;
void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); if( pvRet == NULL ) {#ifndef _CONTENT_PACKAGE // Out of physical memory __debugbreak();#endif } pagesCommitted = pagesRequired;
if( fileSize > 0) { bool AllocData = false; if(pvSaveData != NULL) {#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyTo(pvSaveMem, pvSaveData, fileSize);#else memcpy(pvSaveMem, pvSaveData, fileSize); if(bLevelGenBaseSave) { levelGen->deleteBaseSaveData(); }#endif } else { unsigned int storageLength;#ifdef __PSVITA__ // create a buffer to hold the compressed data pvSaveData = malloc(fileSize); AllocData = true; StorageManager.GetSaveData( pvSaveData, &storageLength );#else StorageManager.GetSaveData( pvSaveMem, &storageLength );#endif#ifdef __PS3__ StorageManager.FreeSaveData();#endif app.DebugPrintf("Filesize - %d, Adjusted size - %d\n",fileSize,storageLength); fileSize = storageLength; }
#ifdef __PSVITA__ if(plat == SAVE_FILE_PLATFORM_PSVITA) { // AP - decompress via the access function. This uses a special RLE format VirtualDecompress((unsigned char *)pvSaveData+8, fileSize-8 ); if( AllocData ) { // free the compressed data buffer if required free( pvSaveData ); } else if(bLevelGenBaseSave) { levelGen->deleteBaseSaveData(); } } else#endif {#ifdef __PSVITA__ void* pvSourceData = pvSaveData;#else void* pvSourceData = pvSaveMem;#endif int compressed = *(int*)pvSourceData; if( compressed == 0 ) { unsigned int decompSize = *( (int*)pvSourceData+1 ); if(isLocalEndianDifferent(plat)) System::ReverseULONG(&decompSize);
// An invalid save, so clear the memory and start from scratch if(decompSize == 0) { // 4J Stu - Saves created between 2/12/2011 and 7/12/2011 will have this problem app.DebugPrintf("Invalid save data format\n"); ZeroMemory( pvSourceData, fileSize ); // Clear the first 8 bytes that reference the header header.WriteHeader( pvSourceData ); } else { unsigned char *buf = new unsigned char[decompSize];#ifndef _XBOX if(plat == SAVE_FILE_PLATFORM_PSVITA) { Compression::VitaVirtualDecompress(buf, &decompSize, (unsigned char *)pvSourceData+8, fileSize-8 ); } else#endif { Compression::getCompression()->SetDecompressionType(plat); // if this save is from another platform, set the correct decompression type Compression::getCompression()->Decompress(buf, &decompSize, (unsigned char *)pvSourceData+8, fileSize-8 ); Compression::getCompression()->SetDecompressionType(SAVE_FILE_PLATFORM_LOCAL); // and then set the decompression back to the local machine's standard type }
// Only ReAlloc if we need to (we might already have enough) and align to 512 byte boundaries DWORD currentHeapSize = pagesCommitted * CSF_PAGE_SIZE;
DWORD desiredSize = decompSize;
if( desiredSize > currentHeapSize ) { unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); if( pvRet == NULL ) { // Out of physical memory __debugbreak(); } pagesCommitted = pagesRequired; }#ifdef __PSVITA__ VirtualCopyTo(pvSaveMem, buf, decompSize);#else memcpy(pvSaveMem, buf, decompSize);#endif delete[] buf; } } }
header.ReadHeader( pvSaveMem, plat );
} else { // Clear the first 8 bytes that reference the header header.WriteHeader( pvSaveMem ); }}
ConsoleSaveFileOriginal::~ConsoleSaveFileOriginal(){ VirtualFree( pvHeap, MAX_PAGE_COUNT * CSF_PAGE_SIZE, MEM_DECOMMIT ); pagesCommitted = 0; // Make sure we don't have any thumbnail data still waiting round - we can't need it now we've destroyed the save file anyway#if defined _XBOX app.GetSaveThumbnail(NULL,NULL);#elif defined __PS3__ app.GetSaveThumbnail(NULL,NULL, NULL,NULL);#endif
DeleteCriticalSection(&m_lock);}
// Add the file to our table of internal files if not already there// Open our actual save file ready for reading/writing, and the set the file pointer to the start of this fileFileEntry *ConsoleSaveFileOriginal::createFile( const ConsoleSavePath &fileName ){ LockSaveAccess(); FileEntry *file = header.AddFile( fileName.getName() ); ReleaseSaveAccess();
return file;}
void ConsoleSaveFileOriginal::deleteFile( FileEntry *file ){ if( file == NULL ) return;
LockSaveAccess();
DWORD numberOfBytesRead = 0; DWORD numberOfBytesWritten = 0;
const int bufferSize = 4096; int amountToRead = bufferSize; byte buffer[bufferSize]; DWORD bufferDataSize = 0;
char *readStartOffset = (char *)pvSaveMem + file->data.startOffset + file->getFileSize();
char *writeStartOffset = (char *)pvSaveMem + file->data.startOffset;
char *endOfDataOffset = (char *)pvSaveMem + header.GetStartOfNextData();
while(true) { // Fill buffer from file if( readStartOffset + bufferSize > endOfDataOffset ) { amountToRead = (int)(endOfDataOffset - readStartOffset); } else { amountToRead = bufferSize; }
if( amountToRead == 0 ) break;
#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyFrom( buffer, readStartOffset, amountToRead );#else memcpy( buffer, readStartOffset, amountToRead );#endif numberOfBytesRead = amountToRead;
bufferDataSize = amountToRead; readStartOffset += numberOfBytesRead;
// Write buffer to file#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyTo( (void *)writeStartOffset, buffer, bufferDataSize );#else memcpy( (void *)writeStartOffset, buffer, bufferDataSize );#endif numberOfBytesWritten = bufferDataSize;
writeStartOffset += numberOfBytesWritten; }
header.RemoveFile( file );
finalizeWrite();
ReleaseSaveAccess();}
void ConsoleSaveFileOriginal::setFilePointer(FileEntry *file,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod){ LockSaveAccess();
file->currentFilePointer = file->data.startOffset + lDistanceToMove;
if( dwMoveMethod == FILE_END) { file->currentFilePointer += file->getFileSize(); }
ReleaseSaveAccess();}
// If this file needs to grow, move the data after alongvoid ConsoleSaveFileOriginal::PrepareForWrite( FileEntry *file, DWORD nNumberOfBytesToWrite ){ int bytesToGrowBy = ( (file->currentFilePointer - file->data.startOffset) + nNumberOfBytesToWrite) - file->getFileSize(); if( bytesToGrowBy <= 0 ) return;
// 4J Stu - Not forcing a minimum size, it is up to the caller to write data in sensible amounts // This lets us keep some of the smaller files small //if( bytesToGrowBy < 1024 ) // bytesToGrowBy = 1024;
// Move all the data beyond us MoveDataBeyond(file, bytesToGrowBy);
// Update our length if( file->data.length < 0 ) file->data.length = 0; file->data.length += bytesToGrowBy;
// Write the header with the updated data finalizeWrite();}
BOOL ConsoleSaveFileOriginal::writeFile(FileEntry *file,LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten){ assert( pvSaveMem != NULL ); if( pvSaveMem == NULL ) { return 0; }
LockSaveAccess();
PrepareForWrite( file, nNumberOfBytesToWrite );
char *writeStartOffset = (char *)pvSaveMem + file->currentFilePointer; //printf("Write: pvSaveMem = %0xd, currentFilePointer = %d, writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, writeStartOffset);
#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyTo((void *)writeStartOffset, (void*)lpBuffer, nNumberOfBytesToWrite);#else memcpy( (void *)writeStartOffset, lpBuffer, nNumberOfBytesToWrite );#endif *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
if(file->data.length < 0) file->data.length = 0;
file->currentFilePointer += *lpNumberOfBytesWritten;
//wprintf(L"Wrote %d bytes to %s, new file pointer is %I64d\n", *lpNumberOfBytesWritten, file->data.filename, file->currentFilePointer);
file->updateLastModifiedTime();
ReleaseSaveAccess();
return 1;}
BOOL ConsoleSaveFileOriginal::zeroFile(FileEntry *file, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten){ assert( pvSaveMem != NULL ); if( pvSaveMem == NULL ) { return 0; }
LockSaveAccess();
PrepareForWrite( file, nNumberOfBytesToWrite );
char *writeStartOffset = (char *)pvSaveMem + file->currentFilePointer; //printf("Write: pvSaveMem = %0xd, currentFilePointer = %d, writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, writeStartOffset);
#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualMemset( (void *)writeStartOffset, 0, nNumberOfBytesToWrite );#else memset( (void *)writeStartOffset, 0, nNumberOfBytesToWrite );#endif *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
if(file->data.length < 0) file->data.length = 0;
file->currentFilePointer += *lpNumberOfBytesWritten;
//wprintf(L"Wrote %d bytes to %s, new file pointer is %I64d\n", *lpNumberOfBytesWritten, file->data.filename, file->currentFilePointer);
file->updateLastModifiedTime();
ReleaseSaveAccess();
return 1;}
BOOL ConsoleSaveFileOriginal::readFile( FileEntry *file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead){ DWORD actualBytesToRead; assert( pvSaveMem != NULL ); if( pvSaveMem == NULL ) { return 0; }
LockSaveAccess();
char *readStartOffset = (char *)pvSaveMem + file->currentFilePointer; //printf("Read: pvSaveMem = %0xd, currentFilePointer = %d, readStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, readStartOffset);
assert( nNumberOfBytesToRead <= file->getFileSize() );
actualBytesToRead = nNumberOfBytesToRead; if( file->currentFilePointer + nNumberOfBytesToRead > file->data.startOffset + file->data.length ) { actualBytesToRead = (file->data.startOffset + file->data.length) - file->currentFilePointer; }
#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyFrom( lpBuffer, readStartOffset, actualBytesToRead );#else memcpy( lpBuffer, readStartOffset, actualBytesToRead );#endif
*lpNumberOfBytesRead = actualBytesToRead;
file->currentFilePointer += *lpNumberOfBytesRead;
//wprintf(L"Read %d bytes from %s, new file pointer is %I64d\n", *lpNumberOfBytesRead, file->data.filename, file->currentFilePointer);
ReleaseSaveAccess();
return 1;}
BOOL ConsoleSaveFileOriginal::closeHandle( FileEntry *file ){ LockSaveAccess(); finalizeWrite(); ReleaseSaveAccess();
return TRUE;}
void ConsoleSaveFileOriginal::finalizeWrite(){ LockSaveAccess(); header.WriteHeader( pvSaveMem ); ReleaseSaveAccess();}
void ConsoleSaveFileOriginal::MoveDataBeyond(FileEntry *file, DWORD nNumberOfBytesToWrite){ DWORD numberOfBytesRead = 0; DWORD numberOfBytesWritten = 0;
const DWORD bufferSize = 4096; DWORD amountToRead = bufferSize; //assert( nNumberOfBytesToWrite <= bufferSize ); static byte buffer1[bufferSize]; static byte buffer2[bufferSize]; DWORD buffer1Size = 0; DWORD buffer2Size = 0;
// Only ReAlloc if we need to (we might already have enough) and align to 512 byte boundaries DWORD currentHeapSize = pagesCommitted * CSF_PAGE_SIZE;
DWORD desiredSize = header.GetFileSize() + nNumberOfBytesToWrite;
if( desiredSize > currentHeapSize ) { unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); if( pvRet == NULL ) { // Out of physical memory __debugbreak(); } pagesCommitted = pagesRequired; }
// This is the start of where we want the space to be, and the start of the data that we need to move char *spaceStartOffset = (char *)pvSaveMem + file->data.startOffset + file->getFileSize();
// This is the end of where we want the space to be char *spaceEndOffset = spaceStartOffset + nNumberOfBytesToWrite;
// This is the current end of the data that we want to move char *beginEndOfDataOffset = (char *)pvSaveMem + header.GetStartOfNextData();
// This is where the end of the data is going to be char *finishEndOfDataOffset = beginEndOfDataOffset + nNumberOfBytesToWrite;
// This is where we are going to read from (with the amount we want to read subtracted before we read) char *readStartOffset = beginEndOfDataOffset;
// This is where we can safely write to (with the amount we want write subtracted before we write) char *writeStartOffset = finishEndOfDataOffset;
//printf("\n******* MOVEDATABEYOND *******\n"); //printf("Space start: %d, space end: %d\n", spaceStartOffset - (char *)pvSaveMem, spaceEndOffset - (char *)pvSaveMem); //printf("Current end of data: %d, new end of data: %d\n", beginEndOfDataOffset - (char *)pvSaveMem, finishEndOfDataOffset - (char *)pvSaveMem);
// Optimisation for things that are being moved in whole region file sector (4K chunks). We could generalise this a bit more but seems safest at the moment to identify this particular type // of move and code explicitly for this situation if( ( nNumberOfBytesToWrite & 4095 ) == 0 ) { if( nNumberOfBytesToWrite > 0 ) { // Get addresses for start & end of the region we are copying from as uintptr_t, for easier maths uintptr_t uiFromStart = (uintptr_t)spaceStartOffset; uintptr_t uiFromEnd = (uintptr_t)beginEndOfDataOffset;
// Round both of these values to get 4096 byte chunks that we will need to at least partially move uintptr_t uiFromStartChunk = uiFromStart & ~((uintptr_t)4095); uintptr_t uiFromEndChunk = (uiFromEnd - 1 ) & ~((uintptr_t)4095);
// Loop through all the affected source 4096 chunks, going backwards so we don't overwrite anything we'll need in the future for( uintptr_t uiCurrentChunk = uiFromEndChunk; uiCurrentChunk >= uiFromStartChunk; uiCurrentChunk -= 4096 ) { // Establish chunk we'll need to copy uintptr_t uiCopyStart = uiCurrentChunk; uintptr_t uiCopyEnd = uiCurrentChunk + 4096; // Clamp chunk to the bounds of the full region we are trying to copy if( uiCopyStart < uiFromStart ) { // Needs to be clampged against the start of our region uiCopyStart = uiFromStart; } if ( uiCopyEnd > uiFromEnd ) { // Needs to be clamped to the end of our region uiCopyEnd = uiFromEnd; }#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualMove( (void *)(uiCopyStart + nNumberOfBytesToWrite), ( void *)uiCopyStart, uiCopyEnd - uiCopyStart);#else XMemCpy( (void *)(uiCopyStart + nNumberOfBytesToWrite), ( void *)uiCopyStart, uiCopyEnd - uiCopyStart );#endif } } } else { while(true) { // Copy buffer 1 to buffer 2 memcpy( buffer2, buffer1, buffer1Size); buffer2Size = buffer1Size;
// Fill buffer 1 from file if( (readStartOffset - bufferSize) < spaceStartOffset ) { amountToRead = (DWORD)(readStartOffset - spaceStartOffset); } else { amountToRead = bufferSize; }
// Push the read point back by the amount of bytes that we are going to read readStartOffset -= amountToRead;
//printf("About to read %u from %d\n", amountToRead, readStartOffset - (char *)pvSaveMem );#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyFrom(buffer1, readStartOffset, amountToRead);#else memcpy( buffer1, readStartOffset, amountToRead );#endif numberOfBytesRead = amountToRead;
buffer1Size = amountToRead;
// Move back the write pointer by the amount of bytes we are going to write writeStartOffset -= buffer2Size;
// Write buffer 2 to file if( (writeStartOffset + buffer2Size) <= finishEndOfDataOffset) { //printf("About to write %u to %d\n", buffer2Size, writeStartOffset - (char *)pvSaveMem );#ifdef __PSVITA__ // AP - use this to access the virtual memory VirtualCopyTo((void *)writeStartOffset, buffer2, buffer2Size);#else memcpy( (void *)writeStartOffset, buffer2, buffer2Size );#endif numberOfBytesWritten = buffer2Size; } else { assert((writeStartOffset + buffer2Size) <= finishEndOfDataOffset); numberOfBytesWritten = 0; }
if( numberOfBytesRead == 0 ) { //printf("\n************** MOVE COMPLETED *************** \n\n"); assert( writeStartOffset == spaceEndOffset ); break; } } }
header.AdjustStartOffsets( file, nNumberOfBytesToWrite );}
bool ConsoleSaveFileOriginal::doesFileExist(ConsoleSavePath file){ LockSaveAccess(); bool exists = header.fileExists( file.getName() ); ReleaseSaveAccess();
return exists;}
void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ){ LockSaveAccess();
#ifdef __PSVITA__ // On Vita we've had problems with saves being corrupted on rapid save/save-exiting so seems prudent to wait for idle while( StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle ) { app.DebugPrintf("Flush wait\n"); Sleep(10); }#endif
finalizeWrite();
// Get the frequency of the timer LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime; float fElapsedTime = 0.0f; QueryPerformanceFrequency( &qwTicksPerSec ); float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
unsigned int fileSize = header.GetFileSize();
// Assume that the compression will make it smaller so initially attempt to allocate the current file size // We add 4 bytes to the start so that we can signal compressed data // And another 4 bytes to store the decompressed data size unsigned int compLength = fileSize+8;
// 4J Stu - Added TU-1 interim
#ifdef __PS3__ // On PS3, don't compress the data as we can't really afford the extra memory this requires for the output buffer. Instead we'll be writing // directly from the save data. StorageManager.SetSaveData(pvSaveMem,fileSize); byte *compData = (byte *)pvSaveMem;#else // Attempt to allocate the required memory // We do not own this, it belongs to the StorageManager byte *compData = (byte *)StorageManager.AllocateSaveData( compLength );
#ifdef __PSVITA__ // AP - make sure we always allocate just what is needed so it will only SAVE what is needed. // If we don't do this the StorageManager will save a file of uncompressed size unnecessarily. compData = NULL;#endif
// If we failed to allocate then compData will be NULL // Pre-calculate the compressed data size so that we can attempt to allocate a smaller buffer if(compData == NULL) { // Length should be 0 here so that the compression call knows that we want to know the length back compLength = 0;
// Pre-calculate the buffer size required for the compressed data PIXBeginNamedEvent(0,"Pre-calc save compression"); // Save the start time QueryPerformanceCounter( &qwTime );#ifdef __PSVITA__ // AP - get the compressed size via the access function. This uses a special RLE format VirtualCompress(NULL,&compLength,pvSaveMem,fileSize);#else Compression::getCompression()->Compress(NULL,&compLength,pvSaveMem,fileSize);#endif QueryPerformanceCounter( &qwNewTime );
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Check buffer size: Elapsed time %f\n", fElapsedTime); PIXEndNamedEvent();
// We add 4 bytes to the start so that we can signal compressed data // And another 4 bytes to store the decompressed data size compLength = compLength+8;
// Attempt to allocate the required memory compData = (byte *)StorageManager.AllocateSaveData( compLength ); }#endif
if(compData != NULL) { // No compression on PS3 - see comment above#ifndef __PS3__ // Re-compress all save data before we save it to disk PIXBeginNamedEvent(0,"Actual save compression"); // Save the start time QueryPerformanceCounter( &qwTime );#ifdef __PSVITA__ // AP - compress via the access function. This uses a special RLE format VirtualCompress(compData+8,&compLength,pvSaveMem,fileSize);#else Compression::getCompression()->Compress(compData+8,&compLength,pvSaveMem,fileSize);#endif QueryPerformanceCounter( &qwNewTime );
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Compress: Elapsed time %f\n", fElapsedTime); PIXEndNamedEvent();
ZeroMemory(compData,8); int saveVer = 0; memcpy( compData, &saveVer, sizeof(int) ); memcpy( compData+4, &fileSize, sizeof(int) );
app.DebugPrintf("Save data compressed from %d to %d\n", fileSize, compLength);#endif
PBYTE pbThumbnailData=NULL; DWORD dwThumbnailDataSize=0;
PBYTE pbDataSaveImage=NULL; DWORD dwDataSizeSaveImage=0;
#if ( defined _XBOX || defined _DURANGO ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize);#elif ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize,&pbDataSaveImage,&dwDataSizeSaveImage);#endif
BYTE bTextMetadata[88]; ZeroMemory(bTextMetadata,88);
__int64 seed = 0; bool hasSeed = false; if(MinecraftServer::getInstance()!= NULL && MinecraftServer::getInstance()->levels[0]!=NULL) { seed = MinecraftServer::getInstance()->levels[0]->getLevelData()->getSeed(); hasSeed = true; }
int iTextMetadataBytes = app.CreateImageTextData(bTextMetadata, seed, hasSeed, app.GetGameHostOption(eGameHostOption_All), Minecraft::GetInstance()->getCurrentTexturePackId());
INT saveOrCheckpointId = 0; bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); TelemetryManager->RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId, compLength+8);
#ifdef _XBOX StorageManager.SaveSaveData( compLength+8,pbThumbnailData,dwThumbnailDataSize,bTextMetadata,iTextMetadataBytes ); delete [] pbThumbnailData; #ifndef _CONTENT_PACKAGE if( app.DebugSettingsOn()) { if(app.GetWriteSavesToFolderEnabled() ) { DebugFlushToFile(compData, compLength+8); } }#endif } else { // We have failed to allocate the memory required to save this file. Now what? }
ReleaseSaveAccess();#elif (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || defined _DURANGO || defined _WINDOWS64) // set the icon and save image StorageManager.SetSaveImages(pbThumbnailData,dwThumbnailDataSize,pbDataSaveImage,dwDataSizeSaveImage,bTextMetadata,iTextMetadataBytes); app.DebugPrintf("Save thumbnail size %d\n",dwThumbnailDataSize);
// save the data StorageManager.SaveSaveData( &ConsoleSaveFileOriginal::SaveSaveDataCallback, this );#ifndef _CONTENT_PACKAGE if( app.DebugSettingsOn()) { if(app.GetWriteSavesToFolderEnabled() ) { DebugFlushToFile(compData, compLength+8); } }#endif ReleaseSaveAccess(); }#else } ReleaseSaveAccess();#endif}
#if (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || defined _DURANGO || defined _WINDOWS64)
int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes){ ConsoleSaveFile *pClass=(ConsoleSaveFile *)lpParam;
return 0;}
#endif
#ifndef _CONTENT_PACKAGEvoid ConsoleSaveFileOriginal::DebugFlushToFile(void *compressedData /*= NULL*/, unsigned int compressedDataSize /*= 0*/){ LockSaveAccess();
finalizeWrite();
unsigned int fileSize = header.GetFileSize();
DWORD numberOfBytesWritten = 0;#ifdef _XBOX File targetFileDir(L"GAME:\\Saves");#else File targetFileDir(L"Saves");#endif // _XBOX
if(!targetFileDir.exists()) targetFileDir.mkdir();
wchar_t *fileName = new wchar_t[XCONTENT_MAX_FILENAME_LENGTH+1];
SYSTEMTIME t; GetSystemTime( &t );
//14 chars for the digits //11 chars for the separators + suffix //25 chars total wstring cutFileName = m_fileName; if(m_fileName.length() > XCONTENT_MAX_FILENAME_LENGTH - 25) { cutFileName = m_fileName.substr(0, XCONTENT_MAX_FILENAME_LENGTH - 25); } swprintf(fileName, XCONTENT_MAX_FILENAME_LENGTH+1, L"\\v%04d-%ls%02d.%02d.%02d.%02d.%02d.mcs",VER_PRODUCTBUILD,cutFileName.c_str(), t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
#ifdef _UNICODE wstring wtemp = targetFileDir.getPath() + wstring(fileName); LPCWSTR lpFileName = wtemp.c_str();#else LPCSTR lpFileName = wstringtofilename( targetFileDir.getPath() + wstring(fileName) );#endif#ifndef __PSVITA__ HANDLE hSaveFile = CreateFile( lpFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL);#endif
if(compressedData != NULL && compressedDataSize > 0) {#ifdef __PSVITA__ // AP - Use the access function to save VirtualWriteFile( lpFileName, compressedData, compressedDataSize, &numberOfBytesWritten, NULL);#else WriteFile( hSaveFile,compressedData,compressedDataSize,&numberOfBytesWritten,NULL);#endif assert(numberOfBytesWritten == compressedDataSize); } else {#ifdef __PSVITA__ // AP - Use the access function to save VirtualWriteFile( lpFileName, compressedData, compressedDataSize, &numberOfBytesWritten, NULL);#else WriteFile(hSaveFile,pvSaveMem,fileSize,&numberOfBytesWritten,NULL);#endif assert(numberOfBytesWritten == fileSize); }#ifndef __PSVITA__ CloseHandle( hSaveFile );#endif
delete[] fileName;
ReleaseSaveAccess();}#endif
unsigned int ConsoleSaveFileOriginal::getSizeOnDisk(){ return header.GetFileSize();}
wstring ConsoleSaveFileOriginal::getFilename(){ return m_fileName;}
vector<FileEntry *> *ConsoleSaveFileOriginal::getFilesWithPrefix(const wstring &prefix){ return header.getFilesWithPrefix( prefix );}
vector<FileEntry *> *ConsoleSaveFileOriginal::getRegionFilesByDimension(unsigned int dimensionIndex){ return NULL;}
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)wstring ConsoleSaveFileOriginal::getPlayerDataFilenameForLoad(const PlayerUID& pUID){ return header.getPlayerDataFilenameForLoad( pUID );}wstring ConsoleSaveFileOriginal::getPlayerDataFilenameForSave(const PlayerUID& pUID){ return header.getPlayerDataFilenameForSave( pUID );}vector<FileEntry *> *ConsoleSaveFileOriginal::getValidPlayerDatFiles(){ return header.getValidPlayerDatFiles();}#endif
int ConsoleSaveFileOriginal::getSaveVersion(){ return header.getSaveVersion();}
int ConsoleSaveFileOriginal::getOriginalSaveVersion(){ return header.getOriginalSaveVersion();}
void ConsoleSaveFileOriginal::LockSaveAccess(){ EnterCriticalSection(&m_lock);}
void ConsoleSaveFileOriginal::ReleaseSaveAccess(){ LeaveCriticalSection(&m_lock);}
ESavePlatform ConsoleSaveFileOriginal::getSavePlatform(){ return header.getSavePlatform();}
bool ConsoleSaveFileOriginal::isSaveEndianDifferent(){ return header.isSaveEndianDifferent();}
void ConsoleSaveFileOriginal::setLocalPlatform(){ header.setLocalPlatform();}
void ConsoleSaveFileOriginal::setPlatform(ESavePlatform plat){ header.setPlatform(plat);}
ByteOrder ConsoleSaveFileOriginal::getSaveEndian(){ return header.getSaveEndian();}
ByteOrder ConsoleSaveFileOriginal::getLocalEndian(){ return header.getLocalEndian();}
void ConsoleSaveFileOriginal::setEndian(ByteOrder endian){ header.setEndian(endian);}
bool ConsoleSaveFileOriginal::isLocalEndianDifferent( ESavePlatform plat ){ return getLocalEndian() != header.getEndian(plat);}
void ConsoleSaveFileOriginal::ConvertRegionFile(File sourceFile){ DWORD numberOfBytesWritten = 0; DWORD numberOfBytesRead = 0;
RegionFile sourceRegionFile(this, &sourceFile);
for(unsigned int x = 0; x < 32; ++x) { for(unsigned int z = 0; z < 32; ++z) { DataInputStream *dis = sourceRegionFile.getChunkDataInputStream(x,z);
if(dis) { byteArray inData(1024*1024); int read = dis->read(inData); dis->close(); dis->deleteChildStream(); delete dis;
DataOutputStream *dos = sourceRegionFile.getChunkDataOutputStream(x,z); dos->write(inData, 0, read);
dos->close(); dos->deleteChildStream(); delete dos; delete inData.data;
}
} } sourceRegionFile.writeAllOffsets(); // saves all the endian swapped offsets back out to the file (not all of these are written in the above processing).
}
void ConsoleSaveFileOriginal::ConvertToLocalPlatform(){ if(getSavePlatform() == SAVE_FILE_PLATFORM_LOCAL) { // already in the correct format return; } // convert each of the region files to the local platform vector<FileEntry *> *allFilesInSave = getFilesWithPrefix(wstring(L"")); for(AUTO_VAR(it, allFilesInSave->begin()); it < allFilesInSave->end(); ++it) { FileEntry *fe = *it; wstring fName( fe->data.filename ); wstring suffix(L".mcr"); if( fName.compare(fName.length() - suffix.length(), suffix.length(), suffix) == 0 ) { app.DebugPrintf("Processing a region file: %ls\n",fName.c_str()); ConvertRegionFile(File(fe->data.filename) ); } else { app.DebugPrintf("%ls is not a region file, ignoring\n", fName.c_str()); } }
setLocalPlatform(); // set the platform of this save to the local platform, now that it's been coverted}
void *ConsoleSaveFileOriginal::getWritePointer(FileEntry *file){ return (char *)pvSaveMem + file->currentFilePointer;;}