mirror of
https://github.com/Patoke/4JLibs.git
synced 2026-05-21 21:24:31 +00:00
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:
133
IMPLEMENTATION_GUIDE.md
Normal file
133
IMPLEMENTATION_GUIDE.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 4JLibs implementation guide
|
||||
|
||||
Whilst the library can be a direct replacement to the standard libraries shipped by the source leak, we can apply some enhancements to the original code
|
||||
|
||||
Some functions were misimplemented due to the Windows library being a direct port off the Xbox 360 libraries, and because this platform was never supposed to see the light of day
|
||||
|
||||
This guide will explain every change you can do in the source leak to improve it, like displaying save thumbnails, displaying save titles on the load menu and more
|
||||
|
||||
## Save thumbnails
|
||||
|
||||
#### The original code for displaying and saving thumbnails was broken for the Windows platform, either by poor ports or lack of care, in this section it will be explained how to enable this feature for the Windows platform using 4JLibs
|
||||
|
||||
In the files ``ConsoleSaveFileOriginal.cpp`` and ``ConsoleSaveFileSplit.cpp`` (the latter might not exist if you are using the December build) there was a mistake when calling ``app.GetSaveThumbnail``
|
||||
|
||||
To fix this issue, you need to replace the line of code:
|
||||
|
||||
```cpp
|
||||
#if ( defined _XBOX || defined _DURANGO )
|
||||
```
|
||||
|
||||
For:
|
||||
```cpp
|
||||
#if ( defined _XBOX || defined _DURANGO || defined _WINDOWS64 )
|
||||
```
|
||||
|
||||
In the files ``Windows64_App.h`` and ``Windows64_App.cpp``, it is assumed that thumbnail capturing is broken, therefore the functions responsible for doing the capturing are empty, we need to fill them back up as follows:
|
||||
|
||||
Below the implementation of:
|
||||
```cpp
|
||||
class CConsoleMinecraftApp : public CMinecraftApp
|
||||
{
|
||||
public:
|
||||
```
|
||||
|
||||
You need to add the line:
|
||||
```cpp
|
||||
ImageFileBuffer m_ThumbnailBuffer;
|
||||
```
|
||||
|
||||
Then, in ``Windows64_App.cpp``, you need to replace the empty implementations of ``CConsoleMinecraftApp::CaptureSaveThumbnail()`` and ``CConsoleMinecraftApp::GetSaveThumbnail`` with the following:
|
||||
```cpp
|
||||
void CConsoleMinecraftApp::CaptureSaveThumbnail()
|
||||
{
|
||||
RenderManager.CaptureThumbnail(&m_ThumbnailBuffer);
|
||||
}
|
||||
void CConsoleMinecraftApp::GetSaveThumbnail(PBYTE *pbData,DWORD *pdwSize)
|
||||
{
|
||||
if (m_ThumbnailBuffer.Allocated())
|
||||
{
|
||||
if (pbData)
|
||||
{
|
||||
*pbData = new BYTE[m_ThumbnailBuffer.GetBufferSize()];
|
||||
*pdwSize = m_ThumbnailBuffer.GetBufferSize();
|
||||
memcpy(*pbData, m_ThumbnailBuffer.GetBufferPointer(), *pdwSize);
|
||||
}
|
||||
m_ThumbnailBuffer.Release();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These changes are enough to display the save thumbnails in the save selector, but we also need to fix the save data displayed in the actual load menu, which we will do as follows
|
||||
|
||||
In the file ``UIScene_LoadMenu.cpp``, you need to replace the line:
|
||||
```cpp
|
||||
#if defined(__PS3__) || defined(__ORBIS__)|| defined(_DURANGO) || defined (__PSVITA__)
|
||||
```
|
||||
|
||||
With:
|
||||
```cpp
|
||||
#if defined(__PS3__) || defined(__ORBIS__)|| defined(_DURANGO) || defined (__PSVITA__) || defined (_WINDOWS64)
|
||||
```
|
||||
|
||||
Then, below that, there's the following chunk of code:
|
||||
```cpp
|
||||
#else // __ORBIS__
|
||||
{
|
||||
SceCesUcsContext Context;
|
||||
sceCesUcsContextInit( &Context );
|
||||
uint32_t utf8Len, utf16Len;
|
||||
sceCesUtf8StrToUtf16Str(&Context, (uint8_t *)params->saveDetails->UTF8SaveFilename, srclen, &utf8Len, u16Message, dstlen, &utf16Len);
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
You want to modify the ``#else`` conditional to be:
|
||||
```cpp
|
||||
#elif defined(__ORBIS__) || defined(__PSVITA__)
|
||||
```
|
||||
|
||||
This way the Windows platform doesn't try accessing PS4/PSVita functions
|
||||
|
||||
Then you want to comment/remove the following chunk of code:
|
||||
```cpp
|
||||
if(params->saveDetails->pbThumbnailData)
|
||||
{
|
||||
m_pbThumbnailData = params->saveDetails->pbThumbnailData;
|
||||
m_uiThumbnailSize = params->saveDetails->dwThumbnailSize;
|
||||
m_bSaveThumbnailReady = true;
|
||||
}
|
||||
else
|
||||
```
|
||||
|
||||
You can replace it for
|
||||
```cpp
|
||||
//if(params->saveDetails->pbThumbnailData)
|
||||
//{
|
||||
// m_pbThumbnailData = params->saveDetails->pbThumbnailData;
|
||||
// m_uiThumbnailSize = params->saveDetails->dwThumbnailSize;
|
||||
// m_bSaveThumbnailReady = true;
|
||||
//}
|
||||
//else
|
||||
```
|
||||
|
||||
This is because, for a ``SAVE_DETAILS`` object, the thumbnail data is always pointing to valid memory (aka, it's always allocated)
|
||||
|
||||
|
||||
After all these changes, save titles and thumbnails should be properly displayed across the game
|
||||
|
||||
## Renderer bugs/artifacts on newer Visual Studio versions
|
||||
|
||||
In the file ``Windows64_Minecraft.cpp``, the depth stencil view descriptor is not null terminated which causes undefined behaviour
|
||||
|
||||
In the case of newer compilers like Visual Studio 2022/2026, this causes the ``descDSView.Flags`` field to be filled with garbage data, and therefore causing visual glitches in game because the depth stencil fails to be created
|
||||
|
||||
To fix this issue, below the line:
|
||||
```cpp
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC descDSView;
|
||||
```
|
||||
|
||||
You need to fill the structure with zeros, you can do it like this:
|
||||
```cpp
|
||||
ZeroMemory(&descDSView, sizeof(descDSView));
|
||||
```
|
||||
13
README.md
13
README.md
@@ -2,18 +2,9 @@
|
||||
|
||||
A project that aims at rebuilding the 4J libraries source code via decompilation for the Minecraft: Legacy Console Edition
|
||||
|
||||
## NOTICE
|
||||
## Implementation
|
||||
|
||||
There's a bug in the main game code where the depth stencil view descriptor isn't zero initialized, this happens in the file ``Windows64_Minecraft.cpp`` at the
|
||||
```D3D11_DEPTH_STENCIL_VIEW_DESC descDSView;``` line
|
||||
|
||||
|
||||
This causes the depth stencil view creation to fail and consequently breaks the game, to fix this you will need to add the following line after the definition described:
|
||||
|
||||
```ZeroMemory(&descDSView, sizeof(descDSView));```
|
||||
|
||||
This issue only happens when building with newer versions of the Visual Studio compiler, Visual Studio 2012 isn't affected by this, so if you're working on a fork of the main source
|
||||
remember to add this line to avoid breaking the game for other people
|
||||
For implementation details, please look at the [IMPLEMENTATION_GUIDE.md](IMPLEMENTATION_GUIDE.md) file
|
||||
|
||||
## Why?
|
||||
|
||||
|
||||
@@ -472,7 +472,7 @@ public:
|
||||
bool m_bSuspended;
|
||||
|
||||
// @Patoke add
|
||||
ID3D11Texture2D *m_backBufferTexture = NULL;
|
||||
ID3D11Texture2D *m_backBufferTexture;
|
||||
};
|
||||
|
||||
// Singleton
|
||||
|
||||
@@ -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