2014-02-16 02:51:04 +01:00
|
|
|
#include "stdafx.h"
|
2015-10-26 22:09:31 +01:00
|
|
|
#include "Emu/System.h"
|
2016-03-21 20:42:14 +01:00
|
|
|
#include "Emu/IdManager.h"
|
|
|
|
|
#include "Emu/Cell/PPUModule.h"
|
2014-03-17 20:34:19 +01:00
|
|
|
|
2017-01-28 13:32:45 +01:00
|
|
|
#include "restore_new.h"
|
2014-08-23 22:40:04 +02:00
|
|
|
#include "Utilities/rXml.h"
|
2017-01-28 13:32:45 +01:00
|
|
|
#include "define_new_memleakdetect.h"
|
2014-02-16 02:51:04 +01:00
|
|
|
#include "Loader/TRP.h"
|
2014-03-20 19:23:14 +01:00
|
|
|
#include "Loader/TROPUSR.h"
|
2016-03-21 20:42:14 +01:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
#include "sceNp.h"
|
|
|
|
|
#include "sceNpTrophy.h"
|
2014-04-01 02:33:55 +02:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
#include "Utilities/StrUtil.h"
|
|
|
|
|
|
2016-05-13 15:55:34 +02:00
|
|
|
logs::channel sceNpTrophy("sceNpTrophy", logs::level::notice);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
struct trophy_context_t
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
static const u32 id_base = 1;
|
|
|
|
|
static const u32 id_step = 1;
|
2017-01-29 17:50:18 +01:00
|
|
|
static const u32 id_count = 1023;
|
2017-01-25 18:50:30 +01:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
std::string trp_name;
|
2016-03-21 20:42:14 +01:00
|
|
|
fs::file trp_stream;
|
2014-04-18 13:28:27 +02:00
|
|
|
std::unique_ptr<TROPUSRLoader> tropusr;
|
2015-07-02 03:54:36 +02:00
|
|
|
};
|
2014-04-15 16:12:15 +02:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
struct trophy_handle_t
|
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
static const u32 id_base = 1;
|
|
|
|
|
static const u32 id_step = 1;
|
2017-01-29 17:50:18 +01:00
|
|
|
static const u32 id_count = 1023;
|
2015-07-02 03:54:36 +02:00
|
|
|
};
|
2014-04-18 13:28:27 +02:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
// Functions
|
|
|
|
|
s32 sceNpTrophyInit(vm::ptr<void> pool, u32 poolSize, u32 containerId, u64 options)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyInit(pool=*0x%x, poolSize=0x%x, containerId=0x%x, options=0x%llx)", pool, poolSize, containerId, options);
|
2014-04-18 13:28:27 +02:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sceNpTrophyTerm()
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyTerm()");
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sceNpTrophyCreateHandle(vm::ptr<u32> handle)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyCreateHandle(handle=*0x%x)", handle);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!handle)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2015-07-02 03:54:36 +02:00
|
|
|
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
2014-02-16 02:51:04 +01:00
|
|
|
}
|
|
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
*handle = idm::make<trophy_handle_t>();
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
2015-02-08 12:37:10 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyDestroyHandle(u32 handle)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyDestroyHandle(handle=0x%x)", handle);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
idm::remove<trophy_handle_t>(handle);
|
2014-09-22 21:00:28 +02:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyAbortHandle(u32 handle)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophyAbortHandle(handle=0x%x)", handle);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!hndl)
|
2015-04-25 23:26:54 +02:00
|
|
|
{
|
2015-07-02 03:54:36 +02:00
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
2015-04-25 23:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunicationId> commId, vm::cptr<SceNpCommunicationSignature> commSign, u64 options)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyCreateContext(context=*0x%x, commId=*0x%x, commSign=*0x%x, options=0x%llx)", context, commId, commSign, options);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
// rough checks for further fmt::format call
|
|
|
|
|
if (commId->term || commId->num > 99)
|
2015-04-25 23:26:54 +02:00
|
|
|
{
|
2015-07-02 03:54:36 +02:00
|
|
|
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
|
2015-04-25 23:26:54 +02:00
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
// generate trophy context name
|
|
|
|
|
std::string name = fmt::format("%s_%02d", commId->data, commId->num);
|
|
|
|
|
|
|
|
|
|
// open trophy pack file
|
2016-03-21 20:42:14 +01:00
|
|
|
fs::file stream(vfs::get("/app_home/../TROPDIR/" + name + "/TROPHY.TRP"));
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
// check if exists and opened
|
2016-03-21 20:42:14 +01:00
|
|
|
if (!stream)
|
2015-04-25 23:26:54 +02:00
|
|
|
{
|
2014-02-16 02:51:04 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
|
2015-04-25 23:26:54 +02:00
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
// create trophy context
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::make_ptr<trophy_context_t>();
|
2014-02-16 16:37:32 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
// set trophy context parameters (could be passed to constructor through make_ptr call)
|
|
|
|
|
ctxt->trp_name = std::move(name);
|
|
|
|
|
ctxt->trp_stream = std::move(stream);
|
2017-02-04 16:09:02 +01:00
|
|
|
*context = idm::last_id();
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
2014-02-16 02:51:04 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyDestroyContext(u32 context)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyDestroyContext(context=0x%x)", context);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
idm::remove<trophy_context_t>(context);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
s32 sceNpTrophyRegisterContext(ppu_thread& CPU, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<u32> arg, u64 options)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT");
|
2014-03-06 13:27:58 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
2015-02-08 12:37:10 +01:00
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!hndl)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE");
|
2015-07-02 03:54:36 +02:00
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
2014-03-06 13:27:58 +01:00
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
TRPLoader trp(ctxt->trp_stream);
|
2014-03-17 20:34:19 +01:00
|
|
|
if (!trp.LoadHeader())
|
2015-07-13 21:06:16 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE");
|
2014-03-17 20:34:19 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE;
|
2015-07-13 21:06:16 +02:00
|
|
|
}
|
2014-03-17 20:34:19 +01:00
|
|
|
|
|
|
|
|
// Rename or discard certain entries based on the files found
|
2014-04-15 16:12:15 +02:00
|
|
|
const size_t kTargetBufferLength = 31;
|
2015-07-13 21:06:16 +02:00
|
|
|
char target[kTargetBufferLength + 1];
|
2014-04-15 16:12:15 +02:00
|
|
|
target[kTargetBufferLength] = 0;
|
2016-03-21 20:42:14 +01:00
|
|
|
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", /*rpcs3::config.system.language.value()*/0));
|
2014-03-17 20:34:19 +01:00
|
|
|
|
2015-07-13 21:06:16 +02:00
|
|
|
if (trp.ContainsEntry(target))
|
|
|
|
|
{
|
2014-03-17 20:34:19 +01:00
|
|
|
trp.RemoveEntry("TROPCONF.SFM");
|
|
|
|
|
trp.RemoveEntry("TROP.SFM");
|
|
|
|
|
trp.RenameEntry(target, "TROPCONF.SFM");
|
|
|
|
|
}
|
2015-07-13 21:06:16 +02:00
|
|
|
else if (trp.ContainsEntry("TROP.SFM"))
|
|
|
|
|
{
|
2014-03-17 20:34:19 +01:00
|
|
|
trp.RemoveEntry("TROPCONF.SFM");
|
|
|
|
|
trp.RenameEntry("TROP.SFM", "TROPCONF.SFM");
|
|
|
|
|
}
|
2015-07-13 21:06:16 +02:00
|
|
|
else if (!trp.ContainsEntry("TROPCONF.SFM"))
|
|
|
|
|
{
|
2014-03-17 20:34:19 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Discard unnecessary TROP_XX.SFM files
|
2015-07-13 21:06:16 +02:00
|
|
|
for (s32 i = 0; i <= 18; i++)
|
|
|
|
|
{
|
2015-08-12 20:38:17 +02:00
|
|
|
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i));
|
2016-03-21 20:42:14 +01:00
|
|
|
if (i != /*rpcs3::config.system.language.value()*/0)
|
2015-07-13 21:06:16 +02:00
|
|
|
{
|
2014-03-17 20:34:19 +01:00
|
|
|
trp.RemoveEntry(target);
|
2015-07-13 21:06:16 +02:00
|
|
|
}
|
2014-03-17 20:34:19 +01:00
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
|
|
|
|
// TODO: Get the path of the current user
|
2015-07-02 03:54:36 +02:00
|
|
|
std::string trophyPath = "/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name;
|
2014-03-20 19:23:14 +01:00
|
|
|
if (!trp.Install(trophyPath))
|
2015-07-13 21:06:16 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE");
|
2014-03-17 20:34:19 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE;
|
2015-07-13 21:06:16 +02:00
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2014-03-20 19:23:14 +01:00
|
|
|
TROPUSRLoader* tropusr = new TROPUSRLoader();
|
2014-03-21 15:07:05 +01:00
|
|
|
std::string trophyUsrPath = trophyPath + "/TROPUSR.DAT";
|
|
|
|
|
std::string trophyConfPath = trophyPath + "/TROPCONF.SFM";
|
|
|
|
|
tropusr->Load(trophyUsrPath, trophyConfPath);
|
2015-07-02 03:54:36 +02:00
|
|
|
ctxt->tropusr.reset(tropusr);
|
2014-03-20 19:23:14 +01:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
// TODO: Callbacks
|
2015-07-02 03:54:36 +02:00
|
|
|
statusCb(CPU, context, SCE_NP_TROPHY_STATUS_INSTALLED, 100, 100, arg);
|
|
|
|
|
statusCb(CPU, context, SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 100, 100, arg);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2014-03-17 20:34:19 +01:00
|
|
|
return CELL_OK;
|
2014-02-16 02:51:04 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr<u64> reqspace, u64 options)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophyGetRequiredDiskSpace(context=0x%x, handle=0x%x, reqspace=*0x%x, options=0x%llx)", context, handle, reqspace, options);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
2014-03-06 13:27:58 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
2015-02-08 12:37:10 +01:00
|
|
|
}
|
2014-02-27 04:21:08 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: This is not accurate. It's just an approximation of the real value
|
2016-03-21 20:42:14 +01:00
|
|
|
*reqspace = ctxt->trp_stream.size();
|
2014-03-06 13:27:58 +01:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophySetSoundLevel(u32 context, u32 handle, u32 level, u64 options)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophySetSoundLevel(context=0x%x, handle=0x%x, level=%d, options=0x%llx)", context, handle, level, options);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptr<SceNpTrophyGameDetails> details, vm::ptr<SceNpTrophyGameData> data)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyGetGameInfo(context=0x%x, handle=0x%x, details=*0x%x, data=*0x%x)", context, handle, details, data);
|
2014-09-30 20:42:15 +02:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2014-09-30 20:42:15 +02:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
|
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2014-03-09 04:57:19 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
2014-03-09 04:57:19 +01:00
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
// TODO: Get the path of the current user
|
|
|
|
|
const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
|
|
|
|
|
|
|
|
|
|
// TODO: rXmlDocument can open only real file
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), !fs::get_virtual_device(path);
|
2014-05-02 08:30:32 +02:00
|
|
|
rXmlDocument doc;
|
|
|
|
|
doc.Load(path);
|
2014-03-20 19:23:14 +01:00
|
|
|
|
|
|
|
|
std::string titleName;
|
|
|
|
|
std::string titleDetail;
|
2015-07-26 11:15:15 +02:00
|
|
|
for (std::shared_ptr<rXmlNode> n = doc.GetRoot()->GetChildren(); n; n = n->GetNext())
|
|
|
|
|
{
|
2014-03-20 19:23:14 +01:00
|
|
|
if (n->GetName() == "title-name")
|
2014-05-02 08:30:32 +02:00
|
|
|
titleName = n->GetNodeContent();
|
2014-03-20 19:23:14 +01:00
|
|
|
if (n->GetName() == "title-detail")
|
2014-05-02 08:30:32 +02:00
|
|
|
titleDetail = n->GetNodeContent();
|
2014-03-20 19:23:14 +01:00
|
|
|
if (n->GetName() == "trophy")
|
|
|
|
|
{
|
2014-05-02 08:30:32 +02:00
|
|
|
u32 trophy_id = atoi(n->GetAttribute("id").c_str());
|
2014-03-20 19:23:14 +01:00
|
|
|
|
|
|
|
|
details->numTrophies++;
|
2014-05-02 08:30:32 +02:00
|
|
|
switch (n->GetAttribute("ttype")[0]) {
|
2014-03-20 19:23:14 +01:00
|
|
|
case 'B': details->numBronze++; break;
|
|
|
|
|
case 'S': details->numSilver++; break;
|
|
|
|
|
case 'G': details->numGold++; break;
|
|
|
|
|
case 'P': details->numPlatinum++; break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (ctxt->tropusr->GetTrophyUnlockState(trophy_id))
|
2014-03-20 19:23:14 +01:00
|
|
|
{
|
|
|
|
|
data->unlockedTrophies++;
|
2014-05-02 08:30:32 +02:00
|
|
|
switch (n->GetAttribute("ttype")[0]) {
|
2014-03-20 19:23:14 +01:00
|
|
|
case 'B': data->unlockedBronze++; break;
|
|
|
|
|
case 'S': data->unlockedSilver++; break;
|
|
|
|
|
case 'G': data->unlockedGold++; break;
|
|
|
|
|
case 'P': data->unlockedPlatinum++; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
strcpy_trunc(details->title, titleName);
|
|
|
|
|
strcpy_trunc(details->description, titleDetail);
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::ptr<u32> platinumId)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyUnlockTrophy(context=0x%x, handle=0x%x, trophyId=%d, platinumId=*0x%x)", context, handle, trophyId, platinumId);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
|
|
|
|
}
|
2014-03-20 19:23:14 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trophyId >= (s32)ctxt->tropusr->GetTrophiesCount())
|
2014-03-20 19:23:14 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
|
2015-07-02 03:54:36 +02:00
|
|
|
if (ctxt->tropusr->GetTrophyUnlockState(trophyId))
|
2014-03-20 19:23:14 +01:00
|
|
|
return SCE_NP_TROPHY_ERROR_ALREADY_UNLOCKED;
|
|
|
|
|
|
2015-07-06 01:21:15 +02:00
|
|
|
ctxt->tropusr->UnlockTrophy(trophyId, 0, 0); // TODO
|
2015-07-02 03:54:36 +02:00
|
|
|
std::string trophyPath = "/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPUSR.DAT";
|
|
|
|
|
ctxt->tropusr->Save(trophyPath);
|
2014-03-20 19:23:14 +01:00
|
|
|
|
2014-09-01 02:51:48 +02:00
|
|
|
*platinumId = SCE_NP_TROPHY_INVALID_TROPHY_ID; // TODO
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr<SceNpTrophyFlagArray> flags, vm::ptr<u32> count)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyGetTrophyUnlockState(context=0x%x, handle=0x%x, flags=*0x%x, count=*0x%x)", context, handle, flags, count);
|
2014-09-22 21:00:28 +02:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2014-09-22 21:00:28 +02:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
|
|
|
|
}
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2014-03-20 19:23:14 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
2015-02-08 12:37:10 +01:00
|
|
|
}
|
2014-03-20 19:23:14 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
u32 count_ = ctxt->tropusr->GetTrophiesCount();
|
2015-02-08 12:37:10 +01:00
|
|
|
*count = count_;
|
|
|
|
|
if (count_ > 128)
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.error("sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected!");
|
2014-03-20 19:23:14 +01:00
|
|
|
|
|
|
|
|
// Pack up to 128 bools in u32 flag_bits[4]
|
2015-02-08 12:37:10 +01:00
|
|
|
for (u32 id = 0; id < count_; id++)
|
2014-03-20 19:23:14 +01:00
|
|
|
{
|
2015-07-02 03:54:36 +02:00
|
|
|
if (ctxt->tropusr->GetTrophyUnlockState(id))
|
2014-03-20 19:23:14 +01:00
|
|
|
flags->flag_bits[id/32] |= 1<<(id%32);
|
|
|
|
|
else
|
|
|
|
|
flags->flag_bits[id/32] &= ~(1<<(id%32));
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceNpTrophyDetails> details, vm::ptr<SceNpTrophyData> data)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.warning("sceNpTrophyGetTrophyInfo(context=0x%x, handle=0x%x, trophyId=%d, details=*0x%x, data=*0x%x)", context, handle, trophyId, details, data);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto ctxt = idm::get<trophy_context_t>(context);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
if (!ctxt)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto hndl = idm::get<trophy_handle_t>(handle);
|
2014-03-06 01:52:23 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
if (!hndl)
|
|
|
|
|
{
|
|
|
|
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
|
|
|
|
}
|
2014-08-05 12:18:22 +02:00
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
// TODO: Get the path of the current user
|
|
|
|
|
const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
|
|
|
|
|
|
|
|
|
|
// TODO: rXmlDocument can open only real file
|
2016-08-15 02:11:49 +02:00
|
|
|
verify(HERE), !fs::get_virtual_device(path);
|
2016-03-21 20:42:14 +01:00
|
|
|
rXmlDocument doc;
|
2014-05-02 08:30:32 +02:00
|
|
|
doc.Load(path);
|
2014-03-20 19:23:14 +01:00
|
|
|
|
|
|
|
|
std::string name;
|
|
|
|
|
std::string detail;
|
2014-05-02 08:30:32 +02:00
|
|
|
for (std::shared_ptr<rXmlNode> n = doc.GetRoot()->GetChildren(); n; n = n->GetNext()) {
|
|
|
|
|
if (n->GetName() == "trophy" && (trophyId == atoi(n->GetAttribute("id").c_str())))
|
2014-03-20 19:23:14 +01:00
|
|
|
{
|
|
|
|
|
details->trophyId = trophyId;
|
2014-05-02 08:30:32 +02:00
|
|
|
switch (n->GetAttribute("ttype")[0]) {
|
2014-03-20 19:23:14 +01:00
|
|
|
case 'B': details->trophyGrade = SCE_NP_TROPHY_GRADE_BRONZE; break;
|
|
|
|
|
case 'S': details->trophyGrade = SCE_NP_TROPHY_GRADE_SILVER; break;
|
|
|
|
|
case 'G': details->trophyGrade = SCE_NP_TROPHY_GRADE_GOLD; break;
|
|
|
|
|
case 'P': details->trophyGrade = SCE_NP_TROPHY_GRADE_PLATINUM; break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
switch (n->GetAttribute("ttype")[0]) {
|
2014-03-20 19:23:14 +01:00
|
|
|
case 'y': details->hidden = true; break;
|
|
|
|
|
case 'n': details->hidden = false; break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
for (std::shared_ptr<rXmlNode> n2 = n->GetChildren(); n2; n2 = n2->GetNext()) {
|
|
|
|
|
if (n2->GetName() == "name") name = n2->GetNodeContent();
|
|
|
|
|
if (n2->GetName() == "detail") detail = n2->GetNodeContent();
|
2014-03-20 19:23:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->trophyId = trophyId;
|
2015-07-02 03:54:36 +02:00
|
|
|
data->unlocked = ctxt->tropusr->GetTrophyUnlockState(trophyId) != 0; // ???
|
|
|
|
|
data->timestamp = ctxt->tropusr->GetTrophyTimestamp(trophyId);
|
2014-03-20 19:23:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-03-09 04:57:19 +01:00
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
memcpy(details->name, name.c_str(), std::min((size_t) SCE_NP_TROPHY_NAME_MAX_SIZE, name.length() + 1));
|
|
|
|
|
memcpy(details->description, detail.c_str(), std::min((size_t) SCE_NP_TROPHY_DESCR_MAX_SIZE, detail.length() + 1));
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetGameProgress(u32 context, u32 handle, vm::ptr<s32> percentage)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophyGetGameProgress(context=0x%x, handle=0x%x, percentage=*0x%x)", context, handle, percentage);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
2014-02-16 02:51:04 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
s32 sceNpTrophyGetGameIcon(u32 context, u32 handle, vm::ptr<void> buffer, vm::ptr<u32> size)
|
2014-02-16 02:51:04 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophyGetGameIcon(context=0x%x, handle=0x%x, buffer=*0x%x, size=*0x%x)", context, handle, buffer, size);
|
2014-02-16 02:51:04 +01:00
|
|
|
|
2015-07-02 03:54:36 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sceNpTrophyGetTrophyIcon(u32 context, u32 handle, s32 trophyId, vm::ptr<void> buffer, vm::ptr<u32> size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sceNpTrophy.todo("sceNpTrophyGetTrophyIcon(context=0x%x, handle=0x%x, trophyId=%d, buffer=*0x%x, size=*0x%x)", context, handle, trophyId, buffer, size);
|
2015-07-02 03:54:36 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
DECLARE(ppu_module_manager::sceNpTrophy)("sceNpTrophy", []()
|
2015-07-02 03:54:36 +02:00
|
|
|
{
|
2015-02-20 14:58:40 +01:00
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetGameProgress);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyRegisterContext);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyCreateHandle);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophySetSoundLevel);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetRequiredDiskSpace);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyDestroyContext);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyInit);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyAbortHandle);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetGameInfo);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyDestroyHandle);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyUnlockTrophy);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyTerm);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetTrophyUnlockState);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetTrophyIcon);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyCreateContext);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetTrophyInfo);
|
|
|
|
|
REG_FUNC(sceNpTrophy, sceNpTrophyGetGameIcon);
|
2015-02-18 17:22:06 +01:00
|
|
|
});
|