Merge branch 'save-corruption' into 'master'

Save corruption fixes

See merge request KartKrew/Kart!2314
This commit is contained in:
Eidolon 2024-04-30 20:49:02 +00:00
commit f4e023a38e
2 changed files with 35 additions and 21 deletions

View file

@ -13,6 +13,7 @@
#include <algorithm>
#include <cstdint>
#include <cstddef>
#include <exception>
#include <filesystem>
#include <fmt/format.h>
@ -286,7 +287,8 @@ void srb2::save_ng_gamedata()
std::string gamedataname_s {gamedatafilename};
fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)};
fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)};
int random_number = rand();
fs::path tmpsavepath {fmt::format("{}/{}_{}.tmp", srb2home, gamedataname_s, random_number)};
json ngdata_json = ng;
@ -294,20 +296,17 @@ void srb2::save_ng_gamedata()
{
std::string tmpsavepathstring = tmpsavepath.string();
srb2::io::FileStream file {tmpsavepathstring, srb2::io::FileStreamMode::kWrite};
srb2::io::BufferedOutputStream<srb2::io::FileStream> bos {std::move(file)};
// The header is necessary to validate during loading.
srb2::io::write(static_cast<uint32_t>(GD_VERSION_MAJOR), bos); // major
srb2::io::write(static_cast<uint8_t>(GD_VERSION_MINOR), bos); // minor/flags
srb2::io::write(static_cast<uint8_t>(gamedata->evercrashed), bos); // dirty (crash recovery)
srb2::io::write(static_cast<uint32_t>(GD_VERSION_MAJOR), file); // major
srb2::io::write(static_cast<uint8_t>(GD_VERSION_MINOR), file); // minor/flags
srb2::io::write(static_cast<uint8_t>(gamedata->evercrashed), file); // dirty (crash recovery)
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
srb2::io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson)));
bos.flush();
file = bos.stream();
srb2::io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson)));
file.close();
}
catch (const srb2::io::FileStreamException& ex)
catch (const std::exception& ex)
{
CONS_Alert(CONS_ERROR, "NG Gamedata save failed: %s\n", ex.what());
}
@ -434,6 +433,13 @@ void srb2::load_ng_gamedata()
json parsed = json::from_ubjson(remainder_as_u8);
js = parsed.template get<GamedataJson>();
}
catch (const std::exception& ex)
{
const char* gdfolder = G_GameDataFolder();
const char* what = ex.what();
I_Error("Game data is corrupt.\nDelete %s (maybe in %s) and try again.\n\nException: %s", gamedatafilename, gdfolder, what);
return;
}
catch (...)
{
const char* gdfolder = G_GameDataFolder();

View file

@ -12,6 +12,7 @@
/// \brief implements methods for profiles etc.
#include <algorithm>
#include <exception>
#include <fmt/format.h>
@ -315,26 +316,28 @@ void PR_SaveProfiles(void)
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE);
std::string tmppath = fmt::format("{}.tmp", realpath);
int random_number = rand();
std::string tmppath = fmt::format("{}_{}.tmp", realpath, random_number);
try
{
io::FileStream file {tmppath, io::FileStreamMode::kWrite};
io::BufferedOutputStream<io::FileStream> bos {std::move(file)};
io::write(static_cast<uint32_t>(0x52494E47), bos, io::Endian::kBE); // "RING"
io::write(static_cast<uint32_t>(0x5052464C), bos, io::Endian::kBE); // "PRFL"
io::write(static_cast<uint8_t>(0), bos); // reserved1
io::write(static_cast<uint8_t>(0), bos); // reserved2
io::write(static_cast<uint8_t>(0), bos); // reserved3
io::write(static_cast<uint8_t>(0), bos); // reserved4
io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson)));
bos.flush();
file = bos.stream();
io::write(static_cast<uint32_t>(0x52494E47), file, io::Endian::kBE); // "RING"
io::write(static_cast<uint32_t>(0x5052464C), file, io::Endian::kBE); // "PRFL"
io::write(static_cast<uint8_t>(0), file); // reserved1
io::write(static_cast<uint8_t>(0), file); // reserved2
io::write(static_cast<uint8_t>(0), file); // reserved3
io::write(static_cast<uint8_t>(0), file); // reserved4
io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson)));
file.close();
fs::rename(tmppath, realpath);
}
catch (const std::exception& ex)
{
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?\n\nException: %s", ex.what());
}
catch (...)
{
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
@ -398,9 +401,14 @@ void PR_LoadProfiles(void)
json parsed = json::from_ubjson(remainder_as_u8);
js = parsed.template get<ProfilesJson>();
}
catch (const std::exception& ex)
{
I_Error("Profiles file is corrupt.\n\nException: %s", ex.what());
return;
}
catch (...)
{
I_Error("Profiles file is corrupt");
I_Error("Profiles file is corrupt.");
return;
}