int sceNpTrophyRegisterContext(u32 context, u32 handle, u32 statusCb_addr, u32 arg_addr, u64 options) { sceNpTrophy.Warning("sceNpTrophyRegisterContext(context=%d, handle=%d, statusCb_addr=0x%x, arg_addr=0x%x, options=0x%llx)", context, handle, statusCb_addr, arg_addr, options); if (!(s_npTrophyInstance.m_bInitialized)) return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; if (!Memory.IsGoodAddr(statusCb_addr)) return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; if (options & (~(u64)1)) return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED; if (context >= s_npTrophyInstance.contexts.size()) return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; // TODO: There are other possible errors sceNpTrophyInternalContext& ctxt = s_npTrophyInstance.contexts[context]; if (!ctxt.trp_stream) return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; TRPLoader trp(*(ctxt.trp_stream)); if (!trp.LoadHeader()) return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; // Rename or discard certain entries based on the files found char target [32]; sprintf(target, "TROP_%02d.SFM", Ini.SysLanguage.GetValue()); if (trp.ContainsEntry(target)) { trp.RemoveEntry("TROPCONF.SFM"); trp.RemoveEntry("TROP.SFM"); trp.RenameEntry(target, "TROPCONF.SFM"); } else if (trp.ContainsEntry("TROP.SFM")) { trp.RemoveEntry("TROPCONF.SFM"); trp.RenameEntry("TROP.SFM", "TROPCONF.SFM"); } else if (!trp.ContainsEntry("TROPCONF.SFM")) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Discard unnecessary TROP_XX.SFM files for (int i=0; i<=18; i++) { sprintf(target, "TROP_%02d.SFM", i); if (i != Ini.SysLanguage.GetValue()) trp.RemoveEntry(target); } // TODO: Get the path of the current user std::string trophyPath = "/dev_hdd0/home/00000001/trophy/" + ctxt.trp_name; if (!trp.Install(trophyPath)) return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; TROPUSRLoader* tropusr = new TROPUSRLoader(); tropusr->Load(trophyPath + "/TROPUSR.DAT", trophyPath + "/TROPCONF.SFM"); ctxt.tropusr = tropusr; // TODO: Callbacks return CELL_OK; }
int sceNpTrophyRegisterContext(u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, u32 arg_addr, u64 options) { sceNpTrophy->Warning("sceNpTrophyRegisterContext(context=%d, handle=%d, statusCb_addr=0x%x, arg_addr=0x%x, options=0x%llx)", context, handle, statusCb.addr(), arg_addr, options); if (!(sceNpTrophyInstance.m_bInitialized)) return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; if (options & (~(u64)1)) return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED; if (context >= sceNpTrophyInstance.contexts.size()) return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; // TODO: There are other possible errors sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context]; if (!ctxt.trp_stream) return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; TRPLoader trp(*(ctxt.trp_stream)); if (!trp.LoadHeader()) return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; // Rename or discard certain entries based on the files found const size_t kTargetBufferLength = 31; char target[kTargetBufferLength+1]; target[kTargetBufferLength] = 0; strcpy_trunc(target, fmt::Format("TROP_%02d.SFM", Ini.SysLanguage.GetValue())); if (trp.ContainsEntry(target)) { trp.RemoveEntry("TROPCONF.SFM"); trp.RemoveEntry("TROP.SFM"); trp.RenameEntry(target, "TROPCONF.SFM"); } else if (trp.ContainsEntry("TROP.SFM")) { trp.RemoveEntry("TROPCONF.SFM"); trp.RenameEntry("TROP.SFM", "TROPCONF.SFM"); } else if (!trp.ContainsEntry("TROPCONF.SFM")) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Discard unnecessary TROP_XX.SFM files for (int i=0; i<=18; i++) { strcpy_trunc(target, fmt::Format("TROP_%02d.SFM", i)); if (i != Ini.SysLanguage.GetValue()) trp.RemoveEntry(target); } // TODO: Get the path of the current user std::string trophyPath = "/dev_hdd0/home/00000001/trophy/" + ctxt.trp_name; if (!trp.Install(trophyPath)) return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; TROPUSRLoader* tropusr = new TROPUSRLoader(); std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT"; std::string trophyConfPath = trophyPath + "/TROPCONF.SFM"; tropusr->Load(trophyUsrPath, trophyConfPath); ctxt.tropusr.reset(tropusr); // TODO: Callbacks statusCb(context, SCE_NP_TROPHY_STATUS_INSTALLED, 100, 100, arg_addr); statusCb(context, SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 100, 100, arg_addr); return CELL_OK; }
s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<u32> arg, u64 options) { sceNpTrophy.Error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options); const auto ctxt = idm::get<trophy_context_t>(context); if (!ctxt) { sceNpTrophy.Error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT"); return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; } const auto hndl = idm::get<trophy_handle_t>(handle); if (!hndl) { sceNpTrophy.Error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE"); return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } TRPLoader trp(*ctxt->trp_stream); if (!trp.LoadHeader()) { sceNpTrophy.Error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE"); return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Rename or discard certain entries based on the files found const size_t kTargetBufferLength = 31; char target[kTargetBufferLength + 1]; target[kTargetBufferLength] = 0; strcpy_trunc(target, fmt::format("TROP_%02d.SFM", Ini.SysLanguage.GetValue())); if (trp.ContainsEntry(target)) { trp.RemoveEntry("TROPCONF.SFM"); trp.RemoveEntry("TROP.SFM"); trp.RenameEntry(target, "TROPCONF.SFM"); } else if (trp.ContainsEntry("TROP.SFM")) { trp.RemoveEntry("TROPCONF.SFM"); trp.RenameEntry("TROP.SFM", "TROPCONF.SFM"); } else if (!trp.ContainsEntry("TROPCONF.SFM")) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Discard unnecessary TROP_XX.SFM files for (s32 i = 0; i <= 18; i++) { strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i)); if (i != Ini.SysLanguage.GetValue()) { trp.RemoveEntry(target); } } // TODO: Get the path of the current user std::string trophyPath = "/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name; if (!trp.Install(trophyPath)) { sceNpTrophy.Error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE"); return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } TROPUSRLoader* tropusr = new TROPUSRLoader(); std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT"; std::string trophyConfPath = trophyPath + "/TROPCONF.SFM"; tropusr->Load(trophyUsrPath, trophyConfPath); ctxt->tropusr.reset(tropusr); // TODO: Callbacks statusCb(CPU, context, SCE_NP_TROPHY_STATUS_INSTALLED, 100, 100, arg); statusCb(CPU, context, SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 100, 100, arg); return CELL_OK; }
error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg, u64 options) { sceNpTrophy.error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options); if (!statusCb) { return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; } const auto ctxt = idm::get<trophy_context_t>(context); if (!ctxt) { return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; } const auto hndl = idm::get<trophy_handle_t>(handle); if (!hndl) { return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } TRPLoader trp(ctxt->trp_stream); if (!trp.LoadHeader()) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Rename or discard certain entries based on the files found const size_t kTargetBufferLength = 31; char target[kTargetBufferLength + 1]; target[kTargetBufferLength] = 0; strcpy_trunc(target, fmt::format("TROP_%02d.SFM", static_cast<s32>(g_cfg.sys.language))); if (trp.ContainsEntry(target)) { trp.RemoveEntry("TROPCONF.SFM"); trp.RemoveEntry("TROP.SFM"); trp.RenameEntry(target, "TROPCONF.SFM"); } else if (trp.ContainsEntry("TROP.SFM")) { trp.RemoveEntry("TROPCONF.SFM"); trp.RenameEntry("TROP.SFM", "TROPCONF.SFM"); } else if (!trp.ContainsEntry("TROPCONF.SFM")) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } // Discard unnecessary TROP_XX.SFM files for (s32 i = 0; i <= 18; i++) { strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i)); if (i != g_cfg.sys.language) { trp.RemoveEntry(target); } } std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name; if (!trp.Install(trophyPath)) { return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE; } TROPUSRLoader* tropusr = new TROPUSRLoader(); std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT"; std::string trophyConfPath = trophyPath + "/TROPCONF.SFM"; tropusr->Load(trophyUsrPath, trophyConfPath); ctxt->tropusr.reset(tropusr); // TODO: Callbacks // From RE-ing a game's state machine, it seems the possible order is one of the following: // * Install (Not installed) - Setup - Progress * ? - Finalize - Complete - Installed // * Reinstall (Corrupted) - Setup - Progress * ? - Finalize - Complete - Installed // * Update (Required update) - Setup - Progress * ? - Finalize - Complete - Installed // * Installed // We will go with the easy path of Installed, and that's it. auto statuses = {SCE_NP_TROPHY_STATUS_NOT_INSTALLED, SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE}; for (auto status : statuses) { if (statusCb(ppu, context, status, 100, 100, arg) < 0) { return SCE_NP_TROPHY_ERROR_PROCESSING_ABORTED; } } return CELL_OK; }