[Feature/fix] Save to temp file first (#3376)

* Add temp file flow to `SaveManager::SaveFileThreaded`.
Add "Save finish" info log message.

* Fix WiiU/Switch
This commit is contained in:
Malkierian 2023-11-14 18:46:50 -07:00 committed by GitHub
parent fb45b66903
commit afe032ea21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 28 deletions

View File

@ -47,6 +47,11 @@ std::filesystem::path SaveManager::GetFileName(int fileNum) {
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav"); return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav");
} }
std::filesystem::path SaveManager::GetFileTempName(int fileNum) {
const std::filesystem::path sSavePath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".temp");
}
SaveManager::SaveManager() { SaveManager::SaveManager() {
coreSectionIDsByName["base"] = SECTION_ID_BASE; coreSectionIDsByName["base"] = SECTION_ID_BASE;
coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER; coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER;
@ -874,6 +879,32 @@ void SaveManager::InitFileMaxed() {
gSaveContext.sceneFlags[5].swch = 0x40000000; gSaveContext.sceneFlags[5].swch = 0x40000000;
} }
#if defined(__WIIU__) || defined(__SWITCH__)
// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
int copy_file(const char* src, const char* dst) {
alignas(0x40) uint8_t buf[4096];
FILE* r = fopen(src, "r");
if (!r) {
return -1;
}
FILE* w = fopen(dst, "w");
if (!w) {
return -2;
}
size_t res;
while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
if (fwrite(buf, 1, res, w) != res) {
break;
}
}
fclose(r);
fclose(w);
return res >= 0 ? 0 : res;
}
#endif
// Threaded SaveFile takes copy of gSaveContext for local unmodified storage // Threaded SaveFile takes copy of gSaveContext for local unmodified storage
void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) { void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) {
@ -915,19 +946,42 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int se
svi.func(saveContext, sectionID, false); svi.func(saveContext, sectionID, false);
} }
std::filesystem::path fileName = GetFileName(fileNum);
std::filesystem::path tempFile = GetFileTempName(fileNum);
if (std::filesystem::exists(tempFile)) {
std::filesystem::remove(tempFile);
}
#if defined(__SWITCH__) || defined(__WIIU__) #if defined(__SWITCH__) || defined(__WIIU__)
FILE* w = fopen(GetFileName(fileNum).c_str(), "w"); FILE* w = fopen(tempFile.c_str(), "w");
std::string json_string = saveBlock.dump(4); std::string json_string = saveBlock.dump(4);
fwrite(json_string.c_str(), sizeof(char), json_string.length(), w); fwrite(json_string.c_str(), sizeof(char), json_string.length(), w);
fclose(w); fclose(w);
#else #else
std::ofstream output(GetFileName(fileNum)); std::ofstream output(tempFile);
output << std::setw(4) << saveBlock << std::endl; output << std::setw(4) << saveBlock << std::endl;
output.close();
#endif #endif
if (std::filesystem::exists(fileName)) {
std::filesystem::remove(fileName);
}
#if defined(__SWITCH__) || defined(__WIIU__)
copy_file(tempFile.c_str(), fileName.c_str());
#else
std::filesystem::copy_file(tempFile, fileName);
#endif
if (std::filesystem::exists(tempFile)) {
std::filesystem::remove(tempFile);
}
delete saveContext; delete saveContext;
InitMeta(fileNum); InitMeta(fileNum);
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaveFile>(fileNum); GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaveFile>(fileNum);
SPDLOG_INFO("Save File Finish - fileNum: {}", fileNum);
} }
// SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded // SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded
@ -2110,32 +2164,6 @@ void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) {
} }
} }
#if defined(__WIIU__) || defined(__SWITCH__)
// std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm
int copy_file(const char* src, const char* dst) {
alignas(0x40) uint8_t buf[4096];
FILE* r = fopen(src, "r");
if (!r) {
return -1;
}
FILE* w = fopen(dst, "w");
if (!w) {
return -2;
}
size_t res;
while ((res = fread(buf, 1, sizeof(buf), r)) > 0) {
if (fwrite(buf, 1, res, w) != res) {
break;
}
}
fclose(r);
fclose(w);
return res >= 0 ? 0 : res;
}
#endif
void SaveManager::CopyZeldaFile(int from, int to) { void SaveManager::CopyZeldaFile(int from, int to) {
assert(std::filesystem::exists(GetFileName(from))); assert(std::filesystem::exists(GetFileName(from)));
DeleteZeldaFile(to); DeleteZeldaFile(to);

View File

@ -142,6 +142,7 @@ class SaveManager {
private: private:
std::filesystem::path GetFileName(int fileNum); std::filesystem::path GetFileName(int fileNum);
std::filesystem::path GetFileTempName(int fileNum);
nlohmann::json saveBlock; nlohmann::json saveBlock;
void ConvertFromUnversioned(); void ConvertFromUnversioned();