mirror of
https://github.com/SysRay/psOff_public.git
synced 2024-12-03 11:50:57 +00:00
+ sceNpTrophyGetGameInfo implementation
This commit is contained in:
parent
35eb9eecdb
commit
d5e8d1a122
@ -67,10 +67,25 @@ class Trophies: public ITrophies {
|
||||
ctx->itrop.data.title_name.clear();
|
||||
ctx->itrop.data.title_detail.clear();
|
||||
ctx->itrop.data.trophyset_version.clear();
|
||||
ctx->itrop.data.trophy_count = 0;
|
||||
ctx->itrop.data.group_count = 0;
|
||||
}
|
||||
|
||||
for (auto& chel: rootel.GetChildren()) {
|
||||
auto& cheln = chel->GetElementName();
|
||||
|
||||
if (cheln == "trophyset-version") {
|
||||
ctx->itrop.data.trophyset_version.assign(chel->GetContent());
|
||||
} else if (cheln == "title-name") {
|
||||
ctx->itrop.data.title_name.assign(chel->GetContent());
|
||||
} else if (cheln == "title-detail") {
|
||||
ctx->itrop.data.title_detail.assign(chel->GetContent());
|
||||
} else if (cheln == "trophy") {
|
||||
++ctx->itrop.data.trophy_count;
|
||||
} else if (cheln == "group") {
|
||||
++ctx->itrop.data.group_count;
|
||||
}
|
||||
|
||||
if (!ctx->entry.cancelled && cheln == "trophy") {
|
||||
ctx->entry.data.id = -1;
|
||||
ctx->entry.data.group = -1;
|
||||
@ -81,11 +96,11 @@ class Trophies: public ITrophies {
|
||||
for (auto& chvar: chel->GetVariables()) {
|
||||
auto& vname = chvar->GetName();
|
||||
if (vname == "id") {
|
||||
ctx->entry.data.id = chvar->GetValueInt(-1);
|
||||
if ((ctx->entry.data.id = chvar->GetValueInt(-1)) > 128) return ErrCodes::MAX_TROPHY_REACHED;
|
||||
} else if (vname == "hidden") {
|
||||
ctx->entry.data.hidden = chvar->GetValue() == "yes";
|
||||
} else if (vname == "ttype") {
|
||||
ctx->entry.data.type = chvar->GetValue().at(0);
|
||||
ctx->entry.data.type = std::tolower(chvar->GetValue().at(0));
|
||||
} else if (vname == "gid") {
|
||||
ctx->entry.data.group = chvar->GetValueInt(-1);
|
||||
}
|
||||
@ -127,17 +142,6 @@ class Trophies: public ITrophies {
|
||||
ctx->group.cancelled = ctx->group.func(&ctx->group.data);
|
||||
}
|
||||
}
|
||||
if (!ctx->itrop.cancelled) {
|
||||
if (cheln == "trophyset-version") {
|
||||
ctx->itrop.data.trophyset_version.assign(chel->GetContent());
|
||||
} else if (cheln == "title-name") {
|
||||
ctx->itrop.data.title_name.assign(chel->GetContent());
|
||||
} else if (cheln == "title-detail") {
|
||||
ctx->itrop.data.title_detail.assign(chel->GetContent());
|
||||
} else if (cheln == "trophy") {
|
||||
++ctx->itrop.data.trophy_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the final trophyset info to itrop callback
|
||||
@ -161,7 +165,7 @@ class Trophies: public ITrophies {
|
||||
if (((ent.flag >> 24) & 0x03) == 0) {
|
||||
ctx->pngim.data.pngsize = ent.len;
|
||||
ctx->pngim.data.pngname.assign(ent.name);
|
||||
ctx->pngim.data.pngdata = new char[ent.len]; // Developer should free this memory manually
|
||||
ctx->pngim.data.pngdata = ::calloc(ent.len, 1); // Developer should free this memory manually
|
||||
trfile.seekg(ent.pos);
|
||||
if (trfile.read((char*)ctx->pngim.data.pngdata, ent.len)) {
|
||||
ctx->pngim.cancelled = ctx->pngim.func(&ctx->pngim.data);
|
||||
@ -418,15 +422,36 @@ class Trophies: public ITrophies {
|
||||
} // trfile.is_open()
|
||||
|
||||
return ErrCodes::NO_TROPHIES;
|
||||
} // parseTRP()
|
||||
}
|
||||
|
||||
bool createContext(int32_t userId, uint32_t label) final {}
|
||||
const char* getError(ErrCodes ec) final {
|
||||
switch (ec) {
|
||||
case ErrCodes::SUCCESS: return "No errors";
|
||||
case ErrCodes::INVALID_CONTEXT: return "Passed context is nullptr";
|
||||
case ErrCodes::NO_ITROP: return "Invalid combination: trying to parse extended trophyset info from lightweight file";
|
||||
case ErrCodes::NO_KEY_SET: return "Invalid trophy key, decrypting is impossible";
|
||||
case ErrCodes::INVALID_MAGIC: return "Invalid trophy file magic, trophy00.trp is likely corruted";
|
||||
case ErrCodes::INVALID_VERSION: return "Unsupported trophy file version";
|
||||
case ErrCodes::INVALID_ENTSIZE: return "Invalid trophy file entry size, trophy00.trp is likely corruted";
|
||||
case ErrCodes::INVALID_AES: return "Trophy file contains unaligned AES blocks";
|
||||
case ErrCodes::NOT_IMPLEMENTED: return "This feature is not implemented yet";
|
||||
case ErrCodes::IO_FAIL: return "Your operating system reported IO failure";
|
||||
case ErrCodes::NO_CALLBACKS: return "No callbacks passed to parser";
|
||||
case ErrCodes::DECRYPT: return "Trophy file decryption failed";
|
||||
case ErrCodes::NO_TROPHIES: return "Trophy file is likely missing or does not contain requested esfm file";
|
||||
default: return "Unknown error code!";
|
||||
}
|
||||
}
|
||||
|
||||
bool getProgress(int32_t userId, uint32_t progress[4]) final {}
|
||||
bool createContext(int32_t userId, uint32_t label) final { return false; }
|
||||
|
||||
bool unlockTrophy(int32_t userId, int32_t trophyId) final {}
|
||||
bool destroyContext(int32_t userId) final { return false; }
|
||||
|
||||
bool resetUserInfo(int32_t userId) final {}
|
||||
bool getProgress(int32_t userId, uint32_t progress[4], uint32_t* count) final { return false; }
|
||||
|
||||
bool unlockTrophy(int32_t userId, int32_t trophyId) final { return false; }
|
||||
|
||||
bool resetUserInfo(int32_t userId) final { return false; }
|
||||
};
|
||||
|
||||
ITrophies& accessTrophies() {
|
||||
|
@ -17,20 +17,21 @@ class ITrophies {
|
||||
~ITrophies() = default;
|
||||
|
||||
enum class ErrCodes {
|
||||
SUCCESS = 0, // No errors, we're fine
|
||||
INVALID_CONTEXT, // Context is nullptr
|
||||
NO_ITROP, // There are no trophyset info in lightweight file
|
||||
CONTINUE, // Not an actual error code. For internal usage only!
|
||||
NO_KEY_SET, // No root key installed
|
||||
INVALID_MAGIC, // TRP file has invalid magic in its header
|
||||
INVALID_VERSION, // TRP file version is not valid
|
||||
INVALID_ENTSIZE, // TRP file has bigger entries
|
||||
INVALID_AES, // TRP file contains unaligned AES blocks
|
||||
NOT_IMPLEMENTED, // This feature is not implemented yet
|
||||
IO_FAIL, // Failed to read TRP file
|
||||
NO_CALLBACKS, // Parser called with no callbacks, it's pointless
|
||||
DECRYPT, // TRP file decryption failed
|
||||
NO_TROPHIES, // Failed to open TRP file or the said file does not contain any esfm file
|
||||
SUCCESS = 0, // No errors, we're fine
|
||||
INVALID_CONTEXT, // Context is nullptr
|
||||
NO_ITROP, // There are no trophyset info in lightweight file
|
||||
CONTINUE, // Not an actual error code. For internal usage only!
|
||||
NO_KEY_SET, // No root key installed
|
||||
INVALID_MAGIC, // TRP file has invalid magic in its header
|
||||
INVALID_VERSION, // TRP file version is not valid
|
||||
INVALID_ENTSIZE, // TRP file has bigger entries
|
||||
INVALID_AES, // TRP file contains unaligned AES blocks
|
||||
NOT_IMPLEMENTED, // This feature is not implemented yet
|
||||
IO_FAIL, // Failed to read TRP file
|
||||
NO_CALLBACKS, // Parser called with no callbacks, it's pointless
|
||||
DECRYPT, // TRP file decryption failed
|
||||
NO_TROPHIES, // Failed to open TRP file or the said file does not contain any esfm file
|
||||
MAX_TROPHY_REACHED, // The game hit the hard limit of 128 trophies
|
||||
};
|
||||
|
||||
struct trp_grp_cb {
|
||||
@ -75,6 +76,7 @@ class ITrophies {
|
||||
std::string title_detail;
|
||||
std::string trophyset_version;
|
||||
uint32_t trophy_count;
|
||||
uint32_t group_count;
|
||||
} data;
|
||||
|
||||
bool cancelled;
|
||||
@ -92,12 +94,14 @@ class ITrophies {
|
||||
inline bool cancelled() { return entry.cancelled && group.cancelled && pngim.cancelled && itrop.cancelled; }
|
||||
};
|
||||
|
||||
virtual ErrCodes parseTRP(trp_context* context) = 0;
|
||||
virtual ErrCodes parseTRP(trp_context* context) = 0;
|
||||
virtual const char* getError(ErrCodes ec) = 0;
|
||||
|
||||
virtual bool createContext(int32_t userId, uint32_t label) = 0;
|
||||
virtual bool getProgress(int32_t userId, uint32_t progress[4]) = 0;
|
||||
virtual bool unlockTrophy(int32_t userId, int32_t trophyId) = 0;
|
||||
virtual bool resetUserInfo(int32_t userId) = 0;
|
||||
virtual bool createContext(int32_t userId, uint32_t label) = 0;
|
||||
virtual bool destroyContext(int32_t userId) = 0;
|
||||
virtual bool getProgress(int32_t userId, uint32_t progress[4], uint32_t* count) = 0;
|
||||
virtual bool unlockTrophy(int32_t userId, int32_t trophyId) = 0;
|
||||
virtual bool resetUserInfo(int32_t userId) = 0;
|
||||
};
|
||||
|
||||
#if defined(__APICALL_EXTERN)
|
||||
|
@ -3,9 +3,10 @@
|
||||
|
||||
namespace Err {
|
||||
namespace NpTrophy {
|
||||
constexpr int32_t INVALID_ARGUMENT = -2141907452;
|
||||
constexpr int32_t ALREADY_EXISTS = -2141907437;
|
||||
constexpr int32_t EXCEEDS_MAX = -2141907422;
|
||||
constexpr int32_t ALREADY_EXISTS = -2141907437;
|
||||
constexpr int32_t INVALID_CONTEXT = -2141907447;
|
||||
constexpr int32_t INVALID_ARGUMENT = -2141907452;
|
||||
} // namespace NpTrophy
|
||||
} // namespace Err
|
||||
|
||||
|
@ -33,7 +33,7 @@ EXPORT SYSV_ABI int sceNpTrophyCreateContext(SceNpTrophyContext* context, int32_
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int sceNpTrophyDestroyContext(SceNpTrophyContext context) {
|
||||
return Ok;
|
||||
return accessTrophies().destroyContext(context) ? Ok : Err::NpTrophy::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int sceNpTrophyRegisterContext(SceNpTrophyContext context, SceNpTrophyHandle handle, uint64_t options) {
|
||||
@ -46,37 +46,68 @@ EXPORT SYSV_ABI int sceNpTrophyUnlockTrophy(SceNpTrophyContext context, SceNpTro
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int sceNpTrophyGetTrophyUnlockState(SceNpTrophyContext context, SceNpTrophyHandle handle, SceNpTrophyFlagArray* flags, uint32_t* count) {
|
||||
if (flags != nullptr) {
|
||||
flags->flagBits[0] = 0;
|
||||
flags->flagBits[1] = 0;
|
||||
flags->flagBits[2] = 0;
|
||||
flags->flagBits[3] = 0;
|
||||
}
|
||||
*count = 2;
|
||||
|
||||
return Ok;
|
||||
return accessTrophies().getProgress(context, flags->flagBits, count);
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int sceNpTrophyGetGameInfo(SceNpTrophyContext context, SceNpTrophyHandle handle, SceNpTrophyGameDetails* details, SceNpTrophyGameData* data) {
|
||||
if (details != nullptr) {
|
||||
details->numGroups = 0;
|
||||
details->numTrophies = 1;
|
||||
details->numPlatinum = 0;
|
||||
details->numGold = 0;
|
||||
details->numSilver = 0;
|
||||
details->numBronze = 1;
|
||||
strcpy_s(details->title, "gameName");
|
||||
strcpy_s(details->description, "gameDesc");
|
||||
EXPORT SYSV_ABI int sceNpTrophyGetGameInfo(SceNpTrophyContext context, SceNpTrophyHandle handle, SceNpTrophyGameDetails* details, SceNpTrophyGameData* gdata) {
|
||||
LOG_USE_MODULE(libSceNpTrophy);
|
||||
SceNpTrophyFlagArray unlock_progr = {0};
|
||||
uint32_t unlock_count = 0;
|
||||
uint32_t trophy_count = 0;
|
||||
|
||||
if (!accessTrophies().getProgress(context, unlock_progr.flagBits, &unlock_count)) return Err::NpTrophy::INVALID_CONTEXT;
|
||||
|
||||
ITrophies::trp_context ctx = {
|
||||
.lightweight = false,
|
||||
|
||||
.entry =
|
||||
{
|
||||
.func = [details, gdata, unlock_progr](ITrophies::trp_ent_cb::data_t* data) -> bool {
|
||||
bool unlocked = SCE_NP_TROPHY_FLAG_ISSET(data->id, (&unlock_progr));
|
||||
|
||||
switch (data->type) {
|
||||
case 'b': // Bronze trophy
|
||||
if (details) ++details->numBronze;
|
||||
if (gdata) ++gdata->unlockedBronze;
|
||||
break;
|
||||
case 's': // Silver trophy
|
||||
if (details) ++details->numSilver;
|
||||
if (gdata) ++gdata->unlockedSilver;
|
||||
break;
|
||||
case 'g': // Gold trophy
|
||||
if (details) ++details->numGold;
|
||||
if (gdata) ++gdata->unlockedGold;
|
||||
break;
|
||||
case 'p': // Platinum trophy
|
||||
if (details) ++details->numPlatinum;
|
||||
if (gdata) ++gdata->unlockedPlatinum;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
.itrop =
|
||||
{
|
||||
.func = [details](ITrophies::trp_inf_cb::data_t* data) -> bool {
|
||||
if (details) data->title_name.copy(details->title, sizeof(details->title));
|
||||
if (details) data->title_detail.copy(details->description, sizeof(details->description));
|
||||
if (details) details->numTrophies = data->trophy_count;
|
||||
if (details) details->numGroups = data->group_count;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
ITrophies::ErrCodes ec;
|
||||
|
||||
if ((ec = accessTrophies().parseTRP(&ctx)) != ITrophies::ErrCodes::SUCCESS) {
|
||||
LOG_ERR(L"Failed to parse trophy data: %S", accessTrophies().getError(ec));
|
||||
return ec == ITrophies::ErrCodes::MAX_TROPHY_REACHED ? Err::NpTrophy::EXCEEDS_MAX : Err::NpTrophy::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (data != nullptr) {
|
||||
data->unlockedTrophies = 0;
|
||||
data->unlockedPlatinum = 0;
|
||||
data->unlockedGold = 0;
|
||||
data->unlockedSilver = 0;
|
||||
data->unlockedBronze = 0;
|
||||
data->progressPercentage = 0;
|
||||
}
|
||||
if (gdata) gdata->progressPercentage = (unlock_count / (float)trophy_count) * 100;
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
@ -136,7 +167,7 @@ EXPORT SYSV_ABI int sceNpTrophyGetGameIcon(SceNpTrophyContext context, SceNpTrop
|
||||
::memcpy(buffer, data->pngdata, data->pngsize);
|
||||
*size = data->pngsize;
|
||||
}
|
||||
delete data->pngdata;
|
||||
::free(data->pngdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -167,7 +198,7 @@ EXPORT SYSV_ABI int sceNpTrophyGetTrophyIcon(SceNpTrophyContext context, SceNpTr
|
||||
::memcpy(buffer, data->pngdata, data->pngsize);
|
||||
*size = data->pngsize;
|
||||
}
|
||||
delete data->pngdata;
|
||||
::free(data->pngdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user