diff options
| author | dtentiion <dtentiongit@gmail.com> | 2026-03-05 20:57:37 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-05 14:57:37 -0600 |
| commit | aadb5115040cfe0199e79a3e32dada6aa4b99fda (patch) | |
| tree | 7aba2ccfc2d3361272ad0380ec69c98a4f6c3efe /Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp | |
| parent | f48a39ae3d72fc47ed3a050f6419716dc398d8f5 (diff) | |
Fix save list, delete save, exit without saving, and blank username on Windows64 (#539)
* Fix world save rename not applying new name
KeyboardCompleteWorldNameCallback had no _WINDOWS64 branch, so the
typed name was validated then silently discarded on every rename attempt.
Write the new name to a worldname.txt sidecar file next to the save
(Windows64\GameHDD\{folder}\worldname.txt) and update the in-memory
display name immediately. ReadLevelNameFromSaveFile now checks for this
sidecar first so renamed saves persist correctly across restarts.
* Fixed gamertag being blank upon renaming and re-joining a save
* Save deletion fix, exiting without saving fix
* Add native in-game keyboard UI for world naming and renaming
Diffstat (limited to 'Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp')
| -rw-r--r-- | Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp | 126 |
1 files changed, 121 insertions, 5 deletions
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp index 0c515ec0..8664aca1 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp @@ -31,6 +31,32 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath) { + // Check for a worldname.txt sidecar written by the rename feature first + size_t slashPos = filePath.rfind(L'\\'); + if (slashPos != wstring::npos) + { + wstring sidecarPath = filePath.substr(0, slashPos + 1) + L"worldname.txt"; + FILE *fr = NULL; + if (_wfopen_s(&fr, sidecarPath.c_str(), L"r") == 0 && fr) + { + char buf[128] = {}; + if (fgets(buf, sizeof(buf), fr)) + { + int len = (int)strlen(buf); + while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r' || buf[len-1] == ' ')) + buf[--len] = '\0'; + fclose(fr); + if (len > 0) + { + wchar_t wbuf[128] = {}; + mbstowcs(wbuf, buf, 127); + return wstring(wbuf); + } + } + else fclose(fr); + } + } + HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) return L""; @@ -110,8 +136,8 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath) if (freeSaveData) delete[] saveData; delete[] rawData; - // "world" is the engine default — it means no real name was ever set, so - // return empty to let the caller fall back to the save filename (timestamp). + // "world" is the engine default - it means no real name was ever set, + // so return empty to let the caller fall back to the save filename (timestamp). if (result == L"world") result = L""; return result; } @@ -644,8 +670,6 @@ void UIScene_LoadOrJoinMenu::tick() { UIScene::tick(); - - #if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined _WINDOWS64 || defined __PSVITA__) if(m_bExitScene) // navigate forward or back { @@ -1335,7 +1359,11 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo { uint16_t ui16Text[128]; ZeroMemory(ui16Text, 128 * sizeof(uint16_t) ); +#ifdef _WINDOWS64 + Win64_GetKeyboardText(ui16Text, 128); +#else InputManager.GetText(ui16Text); +#endif // check the name is valid if(ui16Text[0]!=0) @@ -1343,6 +1371,38 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo #if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined(__PSVITA__)) // open the save and overwrite the metadata StorageManager.RenameSaveData(pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC, ui16Text,&UIScene_LoadOrJoinMenu::RenameSaveDataReturned,pClass); +#elif defined(_WINDOWS64) + { + int listPos = pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC; + + // Convert the ui16Text input to a wide string + wchar_t wNewName[128] = {}; + for (int k = 0; k < 127 && ui16Text[k]; k++) + wNewName[k] = (wchar_t)ui16Text[k]; + + // Convert to narrow for storage and in-memory update + char narrowName[128] = {}; + wcstombs(narrowName, wNewName, 127); + + // Build the sidecar path: Windows64\GameHDD\{folder}\worldname.txt + wchar_t wFilename[MAX_SAVEFILENAME_LENGTH] = {}; + mbstowcs(wFilename, pClass->m_saveDetails[listPos].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1); + wstring sidecarPath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\worldname.txt"); + + FILE *fw = NULL; + if (_wfopen_s(&fw, sidecarPath.c_str(), L"w") == 0 && fw) + { + fputs(narrowName, fw); + fclose(fw); + } + + // Update the in-memory display name so the list reflects it immediately + strncpy_s(pClass->m_saveDetails[listPos].UTF8SaveName, narrowName, 127); + pClass->m_saveDetails[listPos].UTF8SaveName[127] = '\0'; + + // Reuse the existing callback to trigger the list repopulate + UIScene_LoadOrJoinMenu::RenameSaveDataReturned(pClass, true); + } #endif } else @@ -2189,6 +2249,31 @@ void UIScene_LoadOrJoinMenu::LoadSaveFromCloud() #endif //SONY_REMOTE_STORAGE_DOWNLOAD +#ifdef _WINDOWS64 +static bool Win64_DeleteSaveDirectory(const wchar_t* wPath) +{ + wchar_t wSearch[MAX_PATH]; + swprintf_s(wSearch, MAX_PATH, L"%s\\*", wPath); + WIN32_FIND_DATAW fd; + HANDLE hFind = FindFirstFileW(wSearch, &fd); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0) continue; + wchar_t wChild[MAX_PATH]; + swprintf_s(wChild, MAX_PATH, L"%s\\%s", wPath, fd.cFileName); + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + Win64_DeleteSaveDirectory(wChild); + else + DeleteFileW(wChild); + } while (FindNextFileW(hFind, &fd)); + FindClose(hFind); + } + return RemoveDirectoryW(wPath) != 0; +} +#endif // _WINDOWS64 + int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)pParam; @@ -2205,7 +2290,24 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JSt } else { +#ifdef _WINDOWS64 + { + // Use m_saveDetails (sorted display order) so the correct folder is targeted + int displayIdx = pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC; + bool bSuccess = false; + if (pClass->m_saveDetails && displayIdx >= 0 && pClass->m_saveDetails[displayIdx].UTF8SaveFilename[0]) + { + wchar_t wFilename[MAX_SAVEFILENAME_LENGTH] = {}; + mbstowcs_s(NULL, wFilename, MAX_SAVEFILENAME_LENGTH, pClass->m_saveDetails[displayIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1); + wchar_t wFolderPath[MAX_PATH] = {}; + swprintf_s(wFolderPath, MAX_PATH, L"Windows64\\GameHDD\\%s", wFilename); + bSuccess = Win64_DeleteSaveDirectory(wFolderPath); + } + UIScene_LoadOrJoinMenu::DeleteSaveDataReturned((LPVOID)pClass->GetCallbackUniqueId(), bSuccess); + } +#else StorageManager.DeleteSaveData(&pClass->m_pSaveDetails->SaveInfoA[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC], UIScene_LoadOrJoinMenu::DeleteSaveDataReturned, (LPVOID)pClass->GetCallbackUniqueId()); +#endif pClass->m_controlSavesTimer.setVisible( true ); } } @@ -2281,7 +2383,21 @@ int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JS case C4JStorage::EMessage_ResultDecline: // rename { pClass->m_bIgnoreInput=true; -#ifdef _DURANGO +#ifdef _WINDOWS64 + { + wchar_t wSaveName[128]; + ZeroMemory(wSaveName, 128 * sizeof(wchar_t)); + mbstowcs_s(NULL, wSaveName, 128, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, _TRUNCATE); + UIKeyboardInitData kbData; + kbData.title = app.GetString(IDS_RENAME_WORLD_TITLE); + kbData.defaultText = wSaveName; + kbData.maxChars = 25; + kbData.callback = &UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback; + kbData.lpParam = pClass; + kbData.pcMode = !Win64_IsControllerConnected(); + ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData); + } +#elif defined _DURANGO // bring up a keyboard InputManager.RequestKeyboard(app.GetString(IDS_RENAME_WORLD_TITLE), (pClass->m_saveDetails[pClass->m_iSaveListIndex-pClass->m_iDefaultButtonsC]).UTF16SaveName,(DWORD)0,25,&UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback,pClass,C_4JInput::EKeyboardMode_Default); #else |
