diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index f170e8e0e0..87bcf54b93 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -578,11 +578,11 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } - TROPUSRLoader* tropusr = new TROPUSRLoader(); + const auto& tropusr = ctxt->tropusr = std::make_unique(); const std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT"; const std::string trophyConfPath = trophyPath + "/TROPCONF.SFM"; - tropusr->Load(trophyUsrPath, trophyConfPath); - ctxt->tropusr.reset(tropusr); + + ensure(tropusr->Load(trophyUsrPath, trophyConfPath).success); // This emulates vsh sending the events and ensures that not 2 events are processed at once const std::pair statuses[] = diff --git a/rpcs3/Loader/TROPUSR.cpp b/rpcs3/Loader/TROPUSR.cpp index 046ada451a..7da4b03f33 100644 --- a/rpcs3/Loader/TROPUSR.cpp +++ b/rpcs3/Loader/TROPUSR.cpp @@ -5,25 +5,52 @@ LOG_CHANNEL(trp_log, "Trophy"); -bool TROPUSRLoader::Load(const std::string& filepath, const std::string& configpath) +enum : u32 +{ + TROPUSR_MAGIC = 0x818F54AD +}; + +TROPUSRLoader::load_result TROPUSRLoader::Load(const std::string& filepath, const std::string& configpath) { const std::string& path = vfs::get(filepath); - if (!m_file.open(path, fs::read)) + load_result res{}; + + // Generate TROPUSR.DAT + auto generate = [&] { - if (!Generate(filepath, configpath)) + // Reset filesystem error + fs::g_tls_error = fs::error::ok; + + // Generate TROPUSR.DAT if not existing + res.success = Generate(filepath, configpath); + + if (!res.success) { - return false; + trp_log.error("TROPUSRLoader::Load(): Failed to generate TROPUSR.DAT (path='%s', cfg='%s', %s)", path, configpath, fs::g_tls_error); } + + m_file.close(); + return res; + }; + + if (!m_file.open(path)) + { + return generate(); } if (!LoadHeader() || !LoadTableHeaders() || !LoadTables()) { - return false; + // Ignore existing TROPUSR.DAT because it is invalid + m_file.close(); + res.discarded_existing = true; + trp_log.error("TROPUSRLoader::Load(): Failed to load existing TROPUSR.DAT, trying to generate new file with empty trophies history! (path='%s')", path); + return generate(); } - m_file.release(); - return true; + m_file.close(); + res.success = true; + return res; } bool TROPUSRLoader::LoadHeader() @@ -35,7 +62,7 @@ bool TROPUSRLoader::LoadHeader() m_file.seek(0); - if (!m_file.read(m_header)) + if (!m_file.read(m_header) || m_header.magic != TROPUSR_MAGIC) { return false; } @@ -180,14 +207,13 @@ bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& con m_tableHeaders.push_back(table4header); m_tableHeaders.push_back(table6header); - m_header.magic = 0x818F54AD; + std::memset(&m_header, 0, sizeof(m_header)); + m_header.magic = TROPUSR_MAGIC; m_header.unk1 = 0x00010000; m_header.tables_count = ::size32(m_tableHeaders); m_header.unk2 = 0; - Save(filepath); - - return true; + return Save(filepath); } u32 TROPUSRLoader::GetTrophiesCount() diff --git a/rpcs3/Loader/TROPUSR.h b/rpcs3/Loader/TROPUSR.h index 950ee5fa1f..bc6f6af88e 100644 --- a/rpcs3/Loader/TROPUSR.h +++ b/rpcs3/Loader/TROPUSR.h @@ -80,7 +80,13 @@ class TROPUSRLoader public: virtual ~TROPUSRLoader() = default; - virtual bool Load(const std::string& filepath, const std::string& configpath); + struct load_result + { + bool discarded_existing; + bool success; + }; + + virtual load_result Load(const std::string& filepath, const std::string& configpath); virtual bool Save(const std::string& filepath); virtual u32 GetTrophiesCount(); diff --git a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp index 83272d22bc..3ce63ebc55 100644 --- a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp @@ -358,7 +358,7 @@ bool trophy_manager_dialog::LoadTrophyFolderToDB(const std::string& trop_name) game_trophy_data->trop_usr.reset(new TROPUSRLoader()); const std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT"; const std::string trophyConfPath = trophyPath + "/TROPCONF.SFM"; - const bool success = game_trophy_data->trop_usr->Load(trophyUsrPath, trophyConfPath); + const bool success = game_trophy_data->trop_usr->Load(trophyUsrPath, trophyConfPath).success; fs::file config(vfs::get(trophyConfPath));