Fix recursive locking in sceNpTrophyUnlockTrophy

This commit is contained in:
Eladash 2020-02-14 18:10:06 +02:00 committed by Ivan
parent fa9330d0e0
commit cdda19c79f

View file

@ -156,28 +156,27 @@ void fmt_class_string<SceNpTrophyError>::format(std::string& out, u64 arg)
// Helpers // Helpers
void show_trophy_notification(u32 context, u32 handle, u32 trophyId, const std::string& context_name) static error_code NpTrophyGetTrophyInfo(const trophy_context_t* ctxt, s32 trophyId, SceNpTrophyDetails* details, SceNpTrophyData* data);
static void show_trophy_notification(const trophy_context_t* ctxt, s32 trophyId)
{ {
// Get icon for the notification. // Get icon for the notification.
const std::string padded_trophy_id = fmt::format("%03u", trophyId); const std::string padded_trophy_id = fmt::format("%03u", trophyId);
const std::string trophy_icon_path = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + context_name + "/TROP" + padded_trophy_id + ".PNG"; const std::string trophy_icon_path = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROP" + padded_trophy_id + ".PNG";
fs::file trophy_icon_file = fs::file(vfs::get(trophy_icon_path)); fs::file trophy_icon_file = fs::file(vfs::get(trophy_icon_path));
std::vector<uchar> trophy_icon_data; std::vector<uchar> trophy_icon_data;
trophy_icon_file.read(trophy_icon_data, trophy_icon_file.size()); trophy_icon_file.read(trophy_icon_data, trophy_icon_file.size());
vm::var<SceNpTrophyDetails> details({ 0 }); SceNpTrophyDetails details{};
vm::var<SceNpTrophyData> _({ 0 });
const s32 ret = sceNpTrophyGetTrophyInfo(context, handle, trophyId, details, _); if (const auto ret = NpTrophyGetTrophyInfo(ctxt, trophyId, &details, nullptr))
if (ret != CELL_OK)
{ {
sceNpTrophy.error("Failed to get info for trophy dialog. Error code %x", ret); sceNpTrophy.error("Failed to get info for trophy dialog. Error code 0x%x", +ret);
*details = SceNpTrophyDetails();
} }
if (auto trophy_notification_dialog = Emu.GetCallbacks().get_trophy_notification_dialog()) if (auto trophy_notification_dialog = Emu.GetCallbacks().get_trophy_notification_dialog())
{ {
trophy_notification_dialog->ShowTrophyNotification(*details, trophy_icon_data); trophy_notification_dialog->ShowTrophyNotification(details, trophy_icon_data);
} }
} }
@ -875,7 +874,7 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt
if (platinumId) if (platinumId)
{ {
*platinumId = unlocked_platinum_id; *platinumId = unlocked_platinum_id;
sceNpTrophy.warning("sceNpTrophyUnlockTrophy: platinumId was set to %d)", unlocked_platinum_id); sceNpTrophy.warning("sceNpTrophyUnlockTrophy: platinumId was set to %d", unlocked_platinum_id);
} }
const std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROPUSR.DAT"; const std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROPUSR.DAT";
@ -884,12 +883,12 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt
if (g_cfg.misc.show_trophy_popups) if (g_cfg.misc.show_trophy_popups)
{ {
// Enqueue popup for the regular trophy // Enqueue popup for the regular trophy
show_trophy_notification(context, handle, trophyId, ctxt->trp_name); show_trophy_notification(ctxt, trophyId);
if (unlocked_platinum_id != SCE_NP_TROPHY_INVALID_TROPHY_ID) if (unlocked_platinum_id != SCE_NP_TROPHY_INVALID_TROPHY_ID)
{ {
// Enqueue popup for the holy platinum trophy // Enqueue popup for the holy platinum trophy
show_trophy_notification(context, handle, unlocked_platinum_id, ctxt->trp_name); show_trophy_notification(ctxt, unlocked_platinum_id);
} }
} }
@ -953,29 +952,11 @@ error_code sceNpTrophyGetTrophyDetails()
return CELL_OK; return CELL_OK;
} }
error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceNpTrophyDetails> details, vm::ptr<SceNpTrophyData> data) static error_code NpTrophyGetTrophyInfo(const trophy_context_t* ctxt, s32 trophyId, SceNpTrophyDetails* details, SceNpTrophyData* data)
{ {
sceNpTrophy.warning("sceNpTrophyGetTrophyInfo(context=0x%x, handle=0x%x, trophyId=%d, details=*0x%x, data=*0x%x)", context, handle, trophyId, details, data); if (!details && !data)
if (trophyId < 0 || trophyId > 127) // max 128 trophies
{ {
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID; return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
const auto trophy_manager = g_fxo->get<sce_np_trophy_manager>();
std::shared_lock lock(trophy_manager->mtx);
if (!trophy_manager->is_initialized)
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
}
const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle);
if (error)
{
return error;
} }
if (!ctxt->tropusr) if (!ctxt->tropusr)
@ -984,11 +965,6 @@ error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::p
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED; return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED;
} }
if (!details && !data)
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
fs::file config(vfs::get("/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROPCONF.SFM")); fs::file config(vfs::get("/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROPCONF.SFM"));
if (!config) if (!config)
@ -1059,6 +1035,7 @@ error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::p
data->unlocked = unlocked; data->unlocked = unlocked;
data->timestamp = ctxt->tropusr->GetTrophyTimestamp(trophyId); data->timestamp = ctxt->tropusr->GetTrophyTimestamp(trophyId);
} }
break; break;
} }
} }
@ -1070,6 +1047,33 @@ error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::p
return CELL_OK; return CELL_OK;
} }
error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceNpTrophyDetails> details, vm::ptr<SceNpTrophyData> data)
{
sceNpTrophy.warning("sceNpTrophyGetTrophyInfo(context=0x%x, handle=0x%x, trophyId=%d, details=*0x%x, data=*0x%x)", context, handle, trophyId, details, data);
if (trophyId < 0 || trophyId > 127) // max 128 trophies
{
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
}
const auto trophy_manager = g_fxo->get<sce_np_trophy_manager>();
std::shared_lock lock(trophy_manager->mtx);
if (!trophy_manager->is_initialized)
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
}
const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle);
if (error)
{
return error;
}
return NpTrophyGetTrophyInfo(ctxt, trophyId, details ? details.get_ptr() : nullptr, data ? data.get_ptr() : nullptr);
}
error_code sceNpTrophyGetGameProgress(u32 context, u32 handle, vm::ptr<s32> percentage) error_code sceNpTrophyGetGameProgress(u32 context, u32 handle, vm::ptr<s32> percentage)
{ {