feat(docs): add an implementation guide for more in-depth details on how to use 4JLibs expansions
feat(storage): save titles are now encoded into the name of the save files feat(storage): added functionality to delete save files chore(storage): document functions which don't have to be implemented, as they're unused for the Windows platform chore(storage): rename some variables to be more accurate with the binaries fix(render): in vs2012, m_backBufferTexture cannot be initialized in a header fix(storage): in CDLC::GetMountedPath, m_szMountPath and m_szDirectoryPath were mixed up fix(storage): in CSaveGame::SetSaveTitle, there was a wide string to narrow string mismatch
This commit is contained in:
@@ -49,6 +49,7 @@ C4JStorage::EMessageResult C4JStorage::GetMessageBoxResult()
|
||||
|
||||
bool C4JStorage::SetSaveDevice(int (*Func)(LPVOID, const bool), LPVOID lpParam, bool bForceResetOfSaveDevice)
|
||||
{
|
||||
// @Patoke: majorly used in XUI
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,6 +66,7 @@ void C4JStorage::ResetSaveData()
|
||||
|
||||
void C4JStorage::SetDefaultSaveNameForKeyboardDisplay(LPCWSTR pwchDefaultSaveName)
|
||||
{
|
||||
// @Patoke: unused for all platforms
|
||||
;
|
||||
}
|
||||
|
||||
@@ -90,6 +92,7 @@ void C4JStorage::SetSaveUniqueFilename(char *szFilename)
|
||||
|
||||
void C4JStorage::SetState(ESaveGameControlState eControlState, int (*Func)(LPVOID, const bool), LPVOID lpParam)
|
||||
{
|
||||
// @Patoke: only used in the xbox 360 platform
|
||||
;
|
||||
}
|
||||
|
||||
@@ -130,32 +133,38 @@ C4JStorage::ESaveGameState C4JStorage::SaveSaveData(int (*Func)(LPVOID, const bo
|
||||
|
||||
void C4JStorage::CopySaveDataToNewSave(PBYTE pbThumbnail, DWORD cbThumbnail, WCHAR *wchNewName, int (*Func)(LPVOID lpParam, bool), LPVOID lpParam)
|
||||
{
|
||||
// @Patoke: unused for other platforms that aren't the xbox 360
|
||||
;
|
||||
}
|
||||
|
||||
void C4JStorage::SetSaveDeviceSelected(unsigned int uiPad, bool bSelected)
|
||||
{
|
||||
// @Patoke: majorly used in XUI
|
||||
;
|
||||
}
|
||||
|
||||
bool C4JStorage::GetSaveDeviceSelected(unsigned int iPad)
|
||||
{
|
||||
// @Patoke: majorly used in XUI
|
||||
return true;
|
||||
}
|
||||
|
||||
C4JStorage::ESaveGameState C4JStorage::DoesSaveExist(bool *pbExists)
|
||||
{
|
||||
// @Patoke: implementation is stubbed out in other platforms too
|
||||
*pbExists = true;
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
|
||||
bool C4JStorage::EnoughSpaceForAMinSaveGame()
|
||||
{
|
||||
// @Patoke: implementation is stubbed out in other platforms too
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4JStorage::SetSaveMessageVPosition(float fY)
|
||||
{
|
||||
// @Patoke: completely unused
|
||||
;
|
||||
}
|
||||
|
||||
@@ -183,11 +192,13 @@ C4JStorage::ESaveGameState C4JStorage::LoadSaveDataThumbnail(PSAVE_INFO pSaveInf
|
||||
|
||||
void C4JStorage::GetSaveCacheFileInfo(DWORD dwFile, XCONTENT_DATA &xContentData)
|
||||
{
|
||||
// @Patoke: xbox 360 leftover
|
||||
;
|
||||
}
|
||||
|
||||
void C4JStorage::GetSaveCacheFileInfo(DWORD dwFile, PBYTE *ppbImageData, DWORD *pdwImageBytes)
|
||||
{
|
||||
// @Patoke: xbox 360 leftover
|
||||
;
|
||||
}
|
||||
|
||||
@@ -203,6 +214,7 @@ C4JStorage::ESaveGameState C4JStorage::DeleteSaveData(PSAVE_INFO pSaveInfo, int
|
||||
|
||||
void C4JStorage::RegisterMarketplaceCountsCallback(int (*Func)(LPVOID lpParam, C4JStorage::DLC_TMS_DETAILS *, int), LPVOID lpParam)
|
||||
{
|
||||
// @Patoke: only used in the xbox 360 platform
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,11 +208,11 @@ std::string CDLC::GetMountedPath(std::string szMount)
|
||||
if (szMount[ch] == ':')
|
||||
{
|
||||
std::string driveName = szMount.substr(0, ch);
|
||||
for (int i = 0; i < m_vDLCDriveMappings.size(); ++i)
|
||||
for (int i = 0; i < m_vDLCDriveMappings.size(); i++)
|
||||
{
|
||||
if (m_vDLCDriveMappings[i].m_szDirectoryPath == driveName)
|
||||
if (m_vDLCDriveMappings[i].m_szMountPath == driveName)
|
||||
{
|
||||
std::string newPath = m_vDLCDriveMappings[i].m_szMountPath;
|
||||
std::string newPath = m_vDLCDriveMappings[i].m_szDirectoryPath;
|
||||
|
||||
newPath.append(szMount.substr(ch + 1, -1));
|
||||
|
||||
@@ -256,7 +256,7 @@ void CDLC::Tick(void)
|
||||
if (m_iHasNewMountedDLCs)
|
||||
{
|
||||
m_iHasNewMountedDLCs = false;
|
||||
m_pMountedDLCFunc(m_pMountedDLCParam, 0, 0, dword94);
|
||||
m_pMountedDLCFunc(m_pMountedDLCParam, 0, 0, m_dwLicenseMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
;
|
||||
}
|
||||
|
||||
std::string m_szDirectoryPath;
|
||||
std::string m_szMountPath;
|
||||
std::string m_szDirectoryPath;
|
||||
};
|
||||
|
||||
XCONTENT_DATA &GetDLC(DWORD dw);
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
LPVOID m_pMountedDLCParam;
|
||||
std::string m_szMountPath;
|
||||
DWORD m_uiCurrentMappedDLC;
|
||||
DWORD dword94;
|
||||
DWORD m_dwLicenseMask;
|
||||
char m_szPackageRoot[40];
|
||||
DWORD dwordC0;
|
||||
std::vector<DriveMapping> m_vDLCDriveMappings;
|
||||
|
||||
@@ -115,7 +115,7 @@ C4JStorage::ESaveGameState CSaveGame::GetSavesInfo(int iPad, int (*Func)(LPVOID
|
||||
if (resultCount > 0)
|
||||
{
|
||||
m_pSaveDetails->SaveInfoA = new SAVE_INFO[resultCount];
|
||||
memset(m_pSaveDetails->SaveInfoA, 0, 184LL * resultCount);
|
||||
memset(m_pSaveDetails->SaveInfoA, 0, sizeof(SAVE_INFO) * resultCount);
|
||||
|
||||
m_pSaveDetails->iSaveC = 0;
|
||||
int i = 0;
|
||||
@@ -128,16 +128,45 @@ C4JStorage::ESaveGameState CSaveGame::GetSavesInfo(int iPad, int (*Func)(LPVOID
|
||||
strcmp(findFileData.cFileName, ".."))
|
||||
{
|
||||
strcpy_s(m_pSaveDetails->SaveInfoA[i].UTF8SaveFilename, findFileData.cFileName);
|
||||
strcpy_s(m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, findFileData.cFileName);
|
||||
|
||||
// @Patoke add: we want to preserve the title name, so we save this in the actual save file name
|
||||
char searchPath[280];
|
||||
sprintf(searchPath, "%s\\Windows64\\GameHDD\\%s\\*", dirName, findFileData.cFileName);
|
||||
|
||||
WIN32_FIND_DATAA saveFileData;
|
||||
HANDLE hSaveFile = FindFirstFileA(searchPath, &saveFileData);
|
||||
|
||||
char szTitleName[256] = {0};
|
||||
|
||||
if (hSaveFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
// @Patoke todo: we assume the first actual file here to be the save file, ideally we would want to check the extension
|
||||
// too but this is good enough for now
|
||||
if (!(saveFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
strcpy_s(szTitleName, sizeof(szTitleName), saveFileData.cFileName);
|
||||
strcpy_s(this->m_szSaveTitle, saveFileData.cFileName); // populate the save title
|
||||
break;
|
||||
}
|
||||
} while (FindNextFileA(hSaveFile, &saveFileData));
|
||||
|
||||
FindClose(hSaveFile);
|
||||
}
|
||||
|
||||
// set the actual save file name as the title now, before we would use the folder name which is the unique save name
|
||||
strcpy_s(m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, szTitleName);
|
||||
|
||||
char fileName[280];
|
||||
sprintf(fileName, "%s\\Windows64\\GameHDD\\%s\\saveData.ms", dirName, findFileData.cFileName);
|
||||
sprintf(fileName, "%s\\Windows64\\GameHDD\\%s\\%s", dirName, findFileData.cFileName, szTitleName);
|
||||
|
||||
GetFileAttributesExA(fileName, GetFileExInfoStandard, &fileInfoBuffer);
|
||||
m_pSaveDetails->SaveInfoA[i].metaData.dataSize = fileInfoBuffer.nFileSizeLow;
|
||||
|
||||
// @Patoke todo: a save can have multiple thumbnails, implement this behaviour
|
||||
char thumbName[280];
|
||||
sprintf(thumbName, "%s\\Windows64\\GameHDD\\%s\\thumbData.png", dirName, findFileData.cFileName);
|
||||
sprintf(thumbName, "%s\\Windows64\\GameHDD\\%s\\thumbnails\\thumbData.png", dirName, findFileData.cFileName);
|
||||
|
||||
GetFileAttributesExA(thumbName, GetFileExInfoStandard, &fileInfoBuffer);
|
||||
m_pSaveDetails->SaveInfoA[i++].metaData.thumbnailSize = fileInfoBuffer.nFileSizeLow;
|
||||
@@ -200,7 +229,7 @@ C4JStorage::ESaveGameState CSaveGame::LoadSaveDataThumbnail(PSAVE_INFO pSaveInfo
|
||||
const char *saveName = (const char *)pSaveInfo;
|
||||
|
||||
char thumbPath[512];
|
||||
sprintf(thumbPath, "%s/Windows64/GameHDD/%s/thumbData.ms", curDir, saveName);
|
||||
sprintf(thumbPath, "%s/Windows64/GameHDD/%s/thumbnails/thumbData.png", curDir, saveName);
|
||||
|
||||
HANDLE hThumb = CreateFileA(thumbPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
@@ -230,6 +259,8 @@ C4JStorage::ESaveGameState CSaveGame::LoadSaveData(PSAVE_INFO pSaveInfo, int (*F
|
||||
{
|
||||
SetSaveUniqueFilename(pSaveInfo->UTF8SaveFilename);
|
||||
|
||||
memcpy(this->m_szSaveTitle, pSaveInfo->UTF8SaveTitle, sizeof(this->m_szSaveTitle)); // @Patoke add
|
||||
|
||||
if (m_pSaveData)
|
||||
{
|
||||
free(m_pSaveData);
|
||||
@@ -244,7 +275,7 @@ C4JStorage::ESaveGameState CSaveGame::LoadSaveData(PSAVE_INFO pSaveInfo, int (*F
|
||||
GetCurrentDirectoryA(sizeof(curDir), curDir);
|
||||
sprintf(dirName, "%s/Windows64/GameHDD/%s", curDir, m_szSaveUniqueName);
|
||||
CreateDirectoryA(dirName, 0);
|
||||
sprintf(fileName, "%s/saveData.ms", dirName);
|
||||
sprintf(fileName, "%s/%s", dirName, this->m_szSaveTitle); // @Patoke add
|
||||
|
||||
HANDLE h = CreateFileA(fileName, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
@@ -320,7 +351,7 @@ bool CSaveGame::GetSaveUniqueFilename(char *pszName)
|
||||
void CSaveGame::SetSaveTitle(LPCWSTR pwchDefaultSaveName)
|
||||
{
|
||||
CreateSaveUniqueName();
|
||||
memmove(m_szSaveTitle, pwchDefaultSaveName, sizeof(m_szSaveTitle));
|
||||
sprintf(m_szSaveTitle, "%S", pwchDefaultSaveName); // @Patoke add
|
||||
}
|
||||
|
||||
PVOID CSaveGame::AllocateSaveData(unsigned int uiBytes)
|
||||
@@ -365,8 +396,7 @@ void CSaveGame::SetSaveImages(PBYTE pbThumbnail, DWORD dwThumbnailBytes, PBYTE p
|
||||
// inject text metadata into the thumbnail if it exists
|
||||
if (dwTextDataBytes > 0)
|
||||
{
|
||||
this->AddTextFieldToPNG(reinterpret_cast<unsigned __int8 *>(this->m_pbThumbnailData), dwThumbnailBytes, pbTextData, dwTextDataBytes,
|
||||
dwNewThumbnailBytes);
|
||||
this->AddTextFieldToPNG(this->m_pbThumbnailData, dwThumbnailBytes, pbTextData, dwTextDataBytes, dwNewThumbnailBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +490,7 @@ C4JStorage::ESaveGameState CSaveGame::SaveSaveData(int (*Func)(LPVOID, const boo
|
||||
GetCurrentDirectoryA(sizeof(curDir), curDir);
|
||||
sprintf(dirName, "%s/Windows64/GameHDD/%s", curDir, m_szSaveUniqueName);
|
||||
CreateDirectoryA(dirName, 0);
|
||||
sprintf(fileName, "%s/saveData.ms", dirName);
|
||||
sprintf(fileName, "%s/%s", dirName, this->m_szSaveTitle); // @Patoke add
|
||||
|
||||
HANDLE h = CreateFileA(fileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
@@ -473,7 +503,11 @@ C4JStorage::ESaveGameState CSaveGame::SaveSaveData(int (*Func)(LPVOID, const boo
|
||||
// @Patoke add
|
||||
if (this->m_pbThumbnailData != nullptr && this->m_uiThumbnailSize > 0)
|
||||
{
|
||||
sprintf(thumbName, "%s/thumbData.png", dirName);
|
||||
char thumbDir[280];
|
||||
sprintf(thumbDir, "%s/thumbnails", dirName);
|
||||
CreateDirectoryA(thumbDir, 0);
|
||||
|
||||
sprintf(thumbName, "%s/thumbnails/thumbData.png", dirName);
|
||||
|
||||
HANDLE hThumb = CreateFileA(thumbName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
@@ -489,8 +523,43 @@ C4JStorage::ESaveGameState CSaveGame::SaveSaveData(int (*Func)(LPVOID, const boo
|
||||
return C4JStorage::ESaveGame_Idle;
|
||||
}
|
||||
|
||||
// @Patoke add
|
||||
C4JStorage::ESaveGameState CSaveGame::DeleteSaveData(PSAVE_INFO pSaveInfo, int (*Func)(LPVOID lpParam, const bool), LPVOID lpParam)
|
||||
{
|
||||
char dirName[256];
|
||||
char curDir[256];
|
||||
char fileName[280];
|
||||
char thumbName[280];
|
||||
|
||||
GetCurrentDirectoryA(sizeof(curDir), curDir);
|
||||
|
||||
sprintf(dirName, "%s/Windows64/GameHDD/%s", curDir, pSaveInfo->UTF8SaveFilename);
|
||||
sprintf(fileName, "%s/%s", dirName, pSaveInfo->UTF8SaveTitle);
|
||||
sprintf(thumbName, "%s/thumbnails/thumbData.png", dirName);
|
||||
|
||||
DeleteFileA(fileName);
|
||||
DeleteFileA(thumbName);
|
||||
RemoveDirectoryA(dirName);
|
||||
|
||||
PSAVE_INFO m_pDeleteInfo = pSaveInfo; // only here for consistency with the xbox one assert
|
||||
assert((m_pDeleteInfo >= &m_pSaveDetails->SaveInfoA[0]) && (m_pDeleteInfo < &m_pSaveDetails->SaveInfoA[m_pSaveDetails->iSaveC]));
|
||||
|
||||
uint64_t index = pSaveInfo - this->m_pSaveDetails->SaveInfoA;
|
||||
|
||||
// shift all save data by 1 to fill the gap
|
||||
for (int j = index; j < this->m_pSaveDetails->iSaveC - 1; ++j)
|
||||
{
|
||||
this->m_pSaveDetails->SaveInfoA[j] = this->m_pSaveDetails->SaveInfoA[j + 1];
|
||||
}
|
||||
|
||||
--this->m_pSaveDetails->iSaveC;
|
||||
|
||||
// not calling this function is what caused the softlock in the original binaries
|
||||
if (Func)
|
||||
{
|
||||
Func(lpParam, true);
|
||||
}
|
||||
|
||||
return C4JStorage::ESaveGame_Idle;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user