mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-28 02:26:07 +00:00
support for unlocking trophies (#854)
* add pugixml * trophy_viewer: support for trophy unlocking * nptrophy: UnlockTrophy(), DestroyContext() * initial imgui popup * queue to handle multiple trophies at once * extract trophy info on game start + various fixes * platinum trophy support + extract trophy data on startup * format * nptrophy: GetTrophyUnlockState * implement vinicius' reviews
This commit is contained in:
parent
c5b8e492f6
commit
74c2888aaa
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -90,3 +90,6 @@
|
||||||
url = https://github.com/shadps4-emu/ext-imgui.git
|
url = https://github.com/shadps4-emu/ext-imgui.git
|
||||||
shallow = true
|
shallow = true
|
||||||
branch = docking
|
branch = docking
|
||||||
|
[submodule "externals/pugixml"]
|
||||||
|
path = externals/pugixml
|
||||||
|
url = https://github.com/zeux/pugixml.git
|
||||||
|
|
|
@ -108,6 +108,7 @@ find_package(xbyak 7.07 CONFIG)
|
||||||
find_package(xxHash 0.8.2 MODULE)
|
find_package(xxHash 0.8.2 MODULE)
|
||||||
find_package(zlib-ng 2.1.7 MODULE)
|
find_package(zlib-ng 2.1.7 MODULE)
|
||||||
find_package(Zydis 5.0.0 CONFIG)
|
find_package(Zydis 5.0.0 CONFIG)
|
||||||
|
find_package(pugixml 1.14 CONFIG)
|
||||||
|
|
||||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
|
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
|
||||||
find_package(cryptopp 8.9.0 MODULE)
|
find_package(cryptopp 8.9.0 MODULE)
|
||||||
|
@ -313,6 +314,8 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
||||||
src/core/libraries/np_score/np_score.h
|
src/core/libraries/np_score/np_score.h
|
||||||
src/core/libraries/np_trophy/np_trophy.cpp
|
src/core/libraries/np_trophy/np_trophy.cpp
|
||||||
src/core/libraries/np_trophy/np_trophy.h
|
src/core/libraries/np_trophy/np_trophy.h
|
||||||
|
src/core/libraries/np_trophy/trophy_ui.cpp
|
||||||
|
src/core/libraries/np_trophy/trophy_ui.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||||
|
@ -689,7 +692,7 @@ endif()
|
||||||
create_target_directory_groups(shadps4)
|
create_target_directory_groups(shadps4)
|
||||||
|
|
||||||
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui)
|
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui)
|
||||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3)
|
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
|
||||||
|
|
||||||
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
||||||
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
|
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
|
||||||
|
|
5
externals/CMakeLists.txt
vendored
5
externals/CMakeLists.txt
vendored
|
@ -178,3 +178,8 @@ option(TRACY_NO_SAMPLING "" ON)
|
||||||
option(TRACY_ONLY_LOCALHOST "" ON)
|
option(TRACY_ONLY_LOCALHOST "" ON)
|
||||||
option(TRACY_NO_CONTEXT_SWITCH "" ON)
|
option(TRACY_NO_CONTEXT_SWITCH "" ON)
|
||||||
add_subdirectory(tracy)
|
add_subdirectory(tracy)
|
||||||
|
|
||||||
|
# pugixml
|
||||||
|
if (NOT TARGET pugixml::pugixml)
|
||||||
|
add_subdirectory(pugixml)
|
||||||
|
endif()
|
1
externals/pugixml
vendored
Submodule
1
externals/pugixml
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 30cc354fe37114ec7a0a4ed2192951690357c2ed
|
|
@ -440,11 +440,47 @@ constexpr int ORBIS_USER_SERVICE_ERROR_BUFFER_TOO_SHORT = 0x8096000A;
|
||||||
constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003;
|
constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003;
|
||||||
|
|
||||||
// NpTrophy library
|
// NpTrophy library
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_UNKNOWN = 0x80551600;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_NOT_INITIALIZED = 0x80551601;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_ALREADY_INITIALIZED = 0x80551602;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_OUT_OF_MEMORY = 0x80551603;
|
||||||
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT = 0x80551604;
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT = 0x80551604;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INSUFFICIENT_BUFFER = 0x80551605;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_EXCEEDS_MAX = 0x80551606;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_ABORT = 0x80551607;
|
||||||
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE = 0x80551608;
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE = 0x80551608;
|
||||||
constexpr int ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX = 0x80551624;
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT = 0x80551609;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_TROPHY_ID = 0x8055160A;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_GROUP_ID = 0x8055160B;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_TROPHY_ALREADY_UNLOCKED = 0x8055160C;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_PLATINUM_CANNOT_UNLOCK = 0x8055160D;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_ACCOUNTID_NOT_MATCH = 0x8055160E;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_NOT_REGISTERED = 0x8055160F;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_ALREADY_REGISTERED = 0x80551610;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_BROKEN_DATA = 0x80551611;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INSUFFICIENT_SPACE = 0x80551612;
|
||||||
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS = 0x80551613;
|
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS = 0x80551613;
|
||||||
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX = 0x80551622;
|
constexpr int ORBIS_NP_TROPHY_ERROR_ICON_FILE_NOT_FOUND = 0x80551614;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_TRP_FILE_FORMAT = 0x80551616;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_UNSUPPORTED_TRP_FILE = 0x80551617;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_TROPHY_CONF_FORMAT = 0x80551618;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_UNSUPPORTED_TROPHY_CONF = 0x80551619;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_TROPHY_NOT_UNLOCKED = 0x8055161A;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_USER_NOT_FOUND = 0x8055161C;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_USER_NOT_LOGGED_IN = 0x8055161D;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_USER_LOGOUT = 0x8055161E;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_USE_TRP_FOR_DEVELOPMENT = 0x8055161F;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_NP_SERVICE_LABEL = 0x80551621;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_NOT_SUPPORTED = 0x80551622;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX = 0x80551623;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX = 0x80551624;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_USER_ID = 0x80551625;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_TITLE_CONF_NOT_INSTALLED = 0x80551626;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_BROKEN_TITLE_CONF = 0x80551627;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_INCONSISTENT_TITLE_CONF = 0x80551628;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_TITLE_BACKGROUND = 0x80551629;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_SCREENSHOT_DISABLED = 0x8055162B;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_ERROR_SCREENSHOT_DISPLAY_BUFFER_NOT_IN_USE = 0x8055162D;
|
||||||
|
|
||||||
// AvPlayer library
|
// AvPlayer library
|
||||||
constexpr int ORBIS_AVPLAYER_ERROR_INVALID_PARAMS = 0x806A0001;
|
constexpr int ORBIS_AVPLAYER_ERROR_INVALID_PARAMS = 0x806A0001;
|
||||||
|
|
|
@ -4,13 +4,20 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/path_util.h"
|
||||||
#include "common/slot_vector.h"
|
#include "common/slot_vector.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
#include "externals/pugixml/src/pugixml.hpp"
|
||||||
#include "np_trophy.h"
|
#include "np_trophy.h"
|
||||||
|
#include "trophy_ui.h"
|
||||||
|
|
||||||
namespace Libraries::NpTrophy {
|
namespace Libraries::NpTrophy {
|
||||||
|
|
||||||
|
static TrophyUI g_trophy_ui;
|
||||||
|
|
||||||
|
std::string game_serial;
|
||||||
|
|
||||||
static constexpr auto MaxTrophyHandles = 4u;
|
static constexpr auto MaxTrophyHandles = 4u;
|
||||||
static constexpr auto MaxTrophyContexts = 8u;
|
static constexpr auto MaxTrophyContexts = 8u;
|
||||||
|
|
||||||
|
@ -24,11 +31,50 @@ struct ContextKeyHash {
|
||||||
struct TrophyContext {
|
struct TrophyContext {
|
||||||
u32 context_id;
|
u32 context_id;
|
||||||
};
|
};
|
||||||
static Common::SlotVector<u32> trophy_handles{};
|
static Common::SlotVector<OrbisNpTrophyHandle> trophy_handles{};
|
||||||
static Common::SlotVector<ContextKey> trophy_contexts{};
|
static Common::SlotVector<ContextKey> trophy_contexts{};
|
||||||
static std::unordered_map<ContextKey, TrophyContext, ContextKeyHash> contexts_internal{};
|
static std::unordered_map<ContextKey, TrophyContext, ContextKeyHash> contexts_internal{};
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyAbortHandle() {
|
void ORBIS_NP_TROPHY_FLAG_ZERO(OrbisNpTrophyFlagArray* p) {
|
||||||
|
for (int i = 0; i < ORBIS_NP_TROPHY_NUM_MAX; i++) {
|
||||||
|
uint32_t array_index = i / 32;
|
||||||
|
uint32_t bit_position = i % 32;
|
||||||
|
|
||||||
|
p->flag_bits[array_index] &= ~(1U << bit_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_SET(int32_t trophyId, OrbisNpTrophyFlagArray* p) {
|
||||||
|
uint32_t array_index = trophyId / 32;
|
||||||
|
uint32_t bit_position = trophyId % 32;
|
||||||
|
|
||||||
|
p->flag_bits[array_index] |= (1U << bit_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_SET_ALL(OrbisNpTrophyFlagArray* p) {
|
||||||
|
for (int i = 0; i < ORBIS_NP_TROPHY_NUM_MAX; i++) {
|
||||||
|
uint32_t array_index = i / 32;
|
||||||
|
uint32_t bit_position = i % 32;
|
||||||
|
|
||||||
|
p->flag_bits[array_index] |= (1U << bit_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_CLR(int32_t trophyId, OrbisNpTrophyFlagArray* p) {
|
||||||
|
uint32_t array_index = trophyId / 32;
|
||||||
|
uint32_t bit_position = trophyId % 32;
|
||||||
|
|
||||||
|
p->flag_bits[array_index] &= ~(1U << bit_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ORBIS_NP_TROPHY_FLAG_ISSET(int32_t trophyId, OrbisNpTrophyFlagArray* p) {
|
||||||
|
uint32_t array_index = trophyId / 32;
|
||||||
|
uint32_t bit_position = trophyId % 32;
|
||||||
|
|
||||||
|
return (p->flag_bits[array_index] & (1U << bit_position)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceNpTrophyAbortHandle(OrbisNpTrophyHandle handle) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -83,8 +129,8 @@ int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
|
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(OrbisNpTrophyContext* context, int32_t user_id,
|
||||||
u64 options) {
|
uint32_t service_label, uint64_t options) {
|
||||||
ASSERT(options == 0ull);
|
ASSERT(options == 0ull);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
||||||
|
@ -107,7 +153,7 @@ s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) {
|
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(OrbisNpTrophyHandle* handle) {
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
@ -122,55 +168,120 @@ s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
|
int PS4_SYSV_ABI sceNpTrophyDestroyContext(OrbisNpTrophyContext context) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_INFO(Lib_NpTrophy, "Destroyed Context {}", context);
|
||||||
|
|
||||||
|
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
||||||
|
|
||||||
|
Common::SlotId contextId;
|
||||||
|
contextId.index = context;
|
||||||
|
|
||||||
|
ContextKey contextkey = trophy_contexts[contextId];
|
||||||
|
trophy_contexts.erase(contextId);
|
||||||
|
contexts_internal.erase(contextkey);
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle) {
|
s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(OrbisNpTrophyHandle handle) {
|
||||||
if (!trophy_handles.is_allocated({handle})) {
|
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
if (!trophy_handles.is_allocated({static_cast<u32>(handle)})) {
|
||||||
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
trophy_handles.erase({handle});
|
trophy_handles.erase({static_cast<u32>(handle)});
|
||||||
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
|
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGameIcon() {
|
int PS4_SYSV_ABI sceNpTrophyGetGameIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
void* buffer, size_t* size) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGameInfo() {
|
int PS4_SYSV_ABI sceNpTrophyGetGameInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyGameDetails* details,
|
||||||
|
OrbisNpTrophyGameData* data) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon() {
|
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyGroupId groupId, void* buffer, size_t* size) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo() {
|
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyGroupId groupId,
|
||||||
|
OrbisNpTrophyGroupDetails* details,
|
||||||
|
OrbisNpTrophyGroupData* data) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon() {
|
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyId trophyId, void* buffer, size_t* size) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo() {
|
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyId trophyId, OrbisNpTrophyDetails* details,
|
||||||
|
OrbisNpTrophyData* data) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count) {
|
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
OrbisNpTrophyHandle handle,
|
||||||
*flags = 0u;
|
OrbisNpTrophyFlagArray* flags, u32* count) {
|
||||||
*count = 0;
|
LOG_INFO(Lib_NpTrophy, "GetTrophyUnlockState called");
|
||||||
|
|
||||||
|
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
||||||
|
|
||||||
|
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
if (flags == nullptr || count == nullptr)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
ORBIS_NP_TROPHY_FLAG_ZERO(flags);
|
||||||
|
|
||||||
|
const auto trophyDir =
|
||||||
|
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles";
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
pugi::xml_parse_result result =
|
||||||
|
doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str());
|
||||||
|
|
||||||
|
int numTrophies = 0;
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
auto trophyconf = doc.child("trophyconf");
|
||||||
|
for (pugi::xml_node_iterator it = trophyconf.children().begin();
|
||||||
|
it != trophyconf.children().end(); ++it) {
|
||||||
|
|
||||||
|
std::string currentTrophyId = it->attribute("id").value();
|
||||||
|
std::string currentTrophyUnlockState = it->attribute("unlockstate").value();
|
||||||
|
|
||||||
|
if (std::string(it->name()) == "trophy") {
|
||||||
|
numTrophies++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTrophyUnlockState == "unlocked") {
|
||||||
|
ORBIS_NP_TROPHY_FLAG_SET(std::stoi(currentTrophyId), flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description());
|
||||||
|
|
||||||
|
*count = numTrophies;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,8 +350,16 @@ int PS4_SYSV_ABI sceNpTrophyNumInfoGetTotal() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyRegisterContext() {
|
int PS4_SYSV_ABI sceNpTrophyRegisterContext(OrbisNpTrophyContext context,
|
||||||
|
OrbisNpTrophyHandle handle, uint64_t options) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
|
|
||||||
|
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
||||||
|
|
||||||
|
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +373,8 @@ int PS4_SYSV_ABI sceNpTrophySetInfoGetTrophyNum() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyShowTrophyList() {
|
int PS4_SYSV_ABI sceNpTrophyShowTrophyList(OrbisNpTrophyContext context,
|
||||||
|
OrbisNpTrophyHandle handle) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -474,8 +594,132 @@ int PS4_SYSV_ABI sceNpTrophySystemSetDbgParamInt() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyUnlockTrophy() {
|
int PS4_SYSV_ABI sceNpTrophyUnlockTrophy(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
OrbisNpTrophyId trophyId, OrbisNpTrophyId* platinumId) {
|
||||||
|
LOG_INFO(Lib_NpTrophy, "Unlocking trophy id {}", trophyId);
|
||||||
|
|
||||||
|
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
||||||
|
|
||||||
|
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||||
|
|
||||||
|
if (trophyId >= 127)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
|
||||||
|
|
||||||
|
if (platinumId == nullptr)
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
const auto trophyDir =
|
||||||
|
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles";
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
pugi::xml_parse_result result =
|
||||||
|
doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str());
|
||||||
|
|
||||||
|
*platinumId = ORBIS_NP_TROPHY_INVALID_TROPHY_ID;
|
||||||
|
|
||||||
|
int numTrophies = 0;
|
||||||
|
int numTrophiesUnlocked = 0;
|
||||||
|
|
||||||
|
pugi::xml_node_iterator platinumIt;
|
||||||
|
int platinumTrophyGroup = -1;
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
auto trophyconf = doc.child("trophyconf");
|
||||||
|
for (pugi::xml_node_iterator it = trophyconf.children().begin();
|
||||||
|
it != trophyconf.children().end(); ++it) {
|
||||||
|
|
||||||
|
std::string currentTrophyId = it->attribute("id").value();
|
||||||
|
std::string currentTrophyName = it->child("name").text().as_string();
|
||||||
|
std::string currentTrophyDescription = it->child("detail").text().as_string();
|
||||||
|
std::string currentTrophyType = it->attribute("ttype").value();
|
||||||
|
std::string currentTrophyUnlockState = it->attribute("unlockstate").value();
|
||||||
|
|
||||||
|
if (currentTrophyType == "P") {
|
||||||
|
platinumIt = it;
|
||||||
|
|
||||||
|
if (std::string(platinumIt->attribute("gid").value()).empty()) {
|
||||||
|
platinumTrophyGroup = -1;
|
||||||
|
} else {
|
||||||
|
platinumTrophyGroup =
|
||||||
|
std::stoi(std::string(platinumIt->attribute("gid").value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trophyId == std::stoi(currentTrophyId)) {
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_PLATINUM_CANNOT_UNLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::string(it->name()) == "trophy") {
|
||||||
|
if (platinumTrophyGroup == -1) {
|
||||||
|
if (std::string(it->attribute("gid").value()).empty()) {
|
||||||
|
numTrophies++;
|
||||||
|
if (currentTrophyUnlockState == "unlocked") {
|
||||||
|
numTrophiesUnlocked++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!std::string(it->attribute("gid").value()).empty()) {
|
||||||
|
if (std::stoi(std::string(it->attribute("gid").value())) ==
|
||||||
|
platinumTrophyGroup) {
|
||||||
|
numTrophies++;
|
||||||
|
if (currentTrophyUnlockState == "unlocked") {
|
||||||
|
numTrophiesUnlocked++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::stoi(currentTrophyId) == trophyId) {
|
||||||
|
LOG_INFO(Lib_NpTrophy, "Found trophy to unlock {} : {}",
|
||||||
|
it->child("name").text().as_string(),
|
||||||
|
it->child("detail").text().as_string());
|
||||||
|
if (currentTrophyUnlockState == "unlocked") {
|
||||||
|
LOG_INFO(Lib_NpTrophy, "Trophy already unlocked");
|
||||||
|
return ORBIS_NP_TROPHY_ERROR_TROPHY_ALREADY_UNLOCKED;
|
||||||
|
} else {
|
||||||
|
if (std::string(it->attribute("unlockstate").value()).empty()) {
|
||||||
|
it->append_attribute("unlockstate") = "unlocked";
|
||||||
|
} else {
|
||||||
|
it->attribute("unlockstate").set_value("unlocked");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_trophy_ui.AddTrophyToQueue(trophyId, currentTrophyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::string(platinumIt->attribute("unlockstate").value()).empty()) {
|
||||||
|
if ((numTrophies - 2) == numTrophiesUnlocked) {
|
||||||
|
|
||||||
|
platinumIt->append_attribute("unlockstate") = "unlocked";
|
||||||
|
|
||||||
|
std::string platinumTrophyId = platinumIt->attribute("id").value();
|
||||||
|
std::string platinumTrophyName = platinumIt->child("name").text().as_string();
|
||||||
|
|
||||||
|
*platinumId = std::stoi(platinumTrophyId);
|
||||||
|
g_trophy_ui.AddTrophyToQueue(*platinumId, platinumTrophyName);
|
||||||
|
}
|
||||||
|
} else if (std::string(platinumIt->attribute("unlockstate").value()) == "locked") {
|
||||||
|
if ((numTrophies - 2) == numTrophiesUnlocked) {
|
||||||
|
|
||||||
|
platinumIt->attribute("unlockstate").set_value("unlocked");
|
||||||
|
|
||||||
|
std::string platinumTrophyId = platinumIt->attribute("id").value();
|
||||||
|
std::string platinumTrophyName = platinumIt->child("name").text().as_string();
|
||||||
|
|
||||||
|
*platinumId = std::stoi(platinumTrophyId);
|
||||||
|
g_trophy_ui.AddTrophyToQueue(*platinumId, platinumTrophyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.save_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str());
|
||||||
|
|
||||||
|
} else
|
||||||
|
LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description());
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/rtc/rtc.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
|
@ -11,7 +12,116 @@ class SymbolsResolver;
|
||||||
|
|
||||||
namespace Libraries::NpTrophy {
|
namespace Libraries::NpTrophy {
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpTrophyAbortHandle();
|
extern std::string game_serial;
|
||||||
|
|
||||||
|
constexpr int ORBIS_NP_TROPHY_FLAG_SETSIZE = 128;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_FLAG_BITS_SHIFT = 5;
|
||||||
|
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GAME_TITLE_MAX_SIZE = 128;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE = 1024;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GROUP_TITLE_MAX_SIZE = 128;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GROUP_DESCR_MAX_SIZE = 1024;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_NAME_MAX_SIZE = 128;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_DESCR_MAX_SIZE = 1024;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_NUM_MAX = 128;
|
||||||
|
|
||||||
|
constexpr int ORBIS_NP_TROPHY_INVALID_HANDLE = -1;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_INVALID_CONTEXT = -1;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_INVALID_TROPHY_ID = -1;
|
||||||
|
|
||||||
|
typedef int32_t OrbisNpTrophyHandle;
|
||||||
|
typedef int32_t OrbisNpTrophyContext;
|
||||||
|
typedef int32_t OrbisNpTrophyId;
|
||||||
|
typedef uint32_t OrbisNpTrophyFlagMask;
|
||||||
|
|
||||||
|
struct OrbisNpTrophyFlagArray {
|
||||||
|
OrbisNpTrophyFlagMask
|
||||||
|
flag_bits[ORBIS_NP_TROPHY_FLAG_SETSIZE >> ORBIS_NP_TROPHY_FLAG_BITS_SHIFT];
|
||||||
|
};
|
||||||
|
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_ZERO(OrbisNpTrophyFlagArray* p);
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_SET(int32_t trophyId, OrbisNpTrophyFlagArray* p);
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_SET_ALL(OrbisNpTrophyFlagArray* p);
|
||||||
|
void ORBIS_NP_TROPHY_FLAG_CLR(int32_t trophyId, OrbisNpTrophyFlagArray* p);
|
||||||
|
bool ORBIS_NP_TROPHY_FLAG_ISSET(int32_t trophyId, OrbisNpTrophyFlagArray* p);
|
||||||
|
|
||||||
|
struct OrbisNpTrophyData {
|
||||||
|
size_t size;
|
||||||
|
OrbisNpTrophyId trophyId;
|
||||||
|
bool unlocked;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
Rtc::OrbisRtcTick timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int32_t OrbisNpTrophyGrade;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GRADE_UNKNOWN = 0;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GRADE_PLATINUM = 1;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GRADE_GOLD = 2;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GRADE_SILVER = 3;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_GRADE_BRONZE = 4;
|
||||||
|
|
||||||
|
typedef int32_t OrbisNpTrophyGroupId;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_BASE_GAME_GROUP_ID = -1;
|
||||||
|
constexpr int ORBIS_NP_TROPHY_INVALID_GROUP_ID = -2;
|
||||||
|
|
||||||
|
struct OrbisNpTrophyDetails {
|
||||||
|
size_t size;
|
||||||
|
OrbisNpTrophyId trophyId;
|
||||||
|
OrbisNpTrophyGrade trophyGrade;
|
||||||
|
OrbisNpTrophyGroupId groupId;
|
||||||
|
bool hidden;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
char name[ORBIS_NP_TROPHY_NAME_MAX_SIZE];
|
||||||
|
char description[ORBIS_NP_TROPHY_DESCR_MAX_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisNpTrophyGameData {
|
||||||
|
size_t size;
|
||||||
|
uint32_t unlockedTrophies;
|
||||||
|
uint32_t unlockedPlatinum;
|
||||||
|
uint32_t unlockedGold;
|
||||||
|
uint32_t unlockedSilver;
|
||||||
|
uint32_t unlockedBronze;
|
||||||
|
uint32_t progressPercentage;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisNpTrophyGameDetails {
|
||||||
|
size_t size;
|
||||||
|
uint32_t numGroups;
|
||||||
|
uint32_t numTrophies;
|
||||||
|
uint32_t numPlatinum;
|
||||||
|
uint32_t numGold;
|
||||||
|
uint32_t numSilver;
|
||||||
|
uint32_t numBronze;
|
||||||
|
char title[ORBIS_NP_TROPHY_GAME_TITLE_MAX_SIZE];
|
||||||
|
char description[ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisNpTrophyGroupData {
|
||||||
|
size_t size;
|
||||||
|
OrbisNpTrophyGroupId groupId;
|
||||||
|
uint32_t unlockedTrophies;
|
||||||
|
uint32_t unlockedPlatinum;
|
||||||
|
uint32_t unlockedGold;
|
||||||
|
uint32_t unlockedSilver;
|
||||||
|
uint32_t unlockedBronze;
|
||||||
|
uint32_t progressPercentage;
|
||||||
|
uint8_t reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisNpTrophyGroupDetails {
|
||||||
|
size_t size;
|
||||||
|
OrbisNpTrophyGroupId groupId;
|
||||||
|
uint32_t numTrophies;
|
||||||
|
uint32_t numPlatinum;
|
||||||
|
uint32_t numGold;
|
||||||
|
uint32_t numSilver;
|
||||||
|
uint32_t numBronze;
|
||||||
|
char title[ORBIS_NP_TROPHY_GROUP_TITLE_MAX_SIZE];
|
||||||
|
char description[ORBIS_NP_TROPHY_GROUP_DESCR_MAX_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceNpTrophyAbortHandle(OrbisNpTrophyHandle handle);
|
||||||
int PS4_SYSV_ABI sceNpTrophyCaptureScreenshot();
|
int PS4_SYSV_ABI sceNpTrophyCaptureScreenshot();
|
||||||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyDetails();
|
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyDetails();
|
||||||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyFlagArray();
|
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyFlagArray();
|
||||||
|
@ -22,18 +132,30 @@ int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetInfoInGroup();
|
||||||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion();
|
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion();
|
||||||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails();
|
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails();
|
||||||
int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature();
|
int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature();
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
|
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(OrbisNpTrophyContext* context, int32_t user_id,
|
||||||
u64 options);
|
uint32_t service_label, uint64_t options);
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle);
|
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(OrbisNpTrophyHandle* handle);
|
||||||
int PS4_SYSV_ABI sceNpTrophyDestroyContext();
|
int PS4_SYSV_ABI sceNpTrophyDestroyContext(OrbisNpTrophyContext context);
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle);
|
s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(OrbisNpTrophyHandle handle);
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGameIcon();
|
int PS4_SYSV_ABI sceNpTrophyGetGameIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGameInfo();
|
void* buffer, size_t* size);
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon();
|
int PS4_SYSV_ABI sceNpTrophyGetGameInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo();
|
OrbisNpTrophyGameDetails* details,
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon();
|
OrbisNpTrophyGameData* data);
|
||||||
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo();
|
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count);
|
OrbisNpTrophyGroupId groupId, void* buffer, size_t* size);
|
||||||
|
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyGroupId groupId,
|
||||||
|
OrbisNpTrophyGroupDetails* details,
|
||||||
|
OrbisNpTrophyGroupData* data);
|
||||||
|
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyId trophyId, void* buffer, size_t* size);
|
||||||
|
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyId trophyId, OrbisNpTrophyDetails* details,
|
||||||
|
OrbisNpTrophyData* data);
|
||||||
|
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
||||||
|
OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyFlagArray* flags, u32* count);
|
||||||
int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum();
|
int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum();
|
||||||
int PS4_SYSV_ABI sceNpTrophyIntAbortHandle();
|
int PS4_SYSV_ABI sceNpTrophyIntAbortHandle();
|
||||||
int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();
|
int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();
|
||||||
|
@ -47,10 +169,12 @@ int PS4_SYSV_ABI sceNpTrophyIntGetTrpIconByUri();
|
||||||
int PS4_SYSV_ABI sceNpTrophyIntNetSyncTitle();
|
int PS4_SYSV_ABI sceNpTrophyIntNetSyncTitle();
|
||||||
int PS4_SYSV_ABI sceNpTrophyIntNetSyncTitles();
|
int PS4_SYSV_ABI sceNpTrophyIntNetSyncTitles();
|
||||||
int PS4_SYSV_ABI sceNpTrophyNumInfoGetTotal();
|
int PS4_SYSV_ABI sceNpTrophyNumInfoGetTotal();
|
||||||
int PS4_SYSV_ABI sceNpTrophyRegisterContext();
|
int PS4_SYSV_ABI sceNpTrophyRegisterContext(OrbisNpTrophyContext context,
|
||||||
|
OrbisNpTrophyHandle handle, uint64_t options);
|
||||||
int PS4_SYSV_ABI sceNpTrophySetInfoGetTrophyFlagArray();
|
int PS4_SYSV_ABI sceNpTrophySetInfoGetTrophyFlagArray();
|
||||||
int PS4_SYSV_ABI sceNpTrophySetInfoGetTrophyNum();
|
int PS4_SYSV_ABI sceNpTrophySetInfoGetTrophyNum();
|
||||||
int PS4_SYSV_ABI sceNpTrophyShowTrophyList();
|
int PS4_SYSV_ABI sceNpTrophyShowTrophyList(OrbisNpTrophyContext context,
|
||||||
|
OrbisNpTrophyHandle handle);
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemAbortHandle();
|
int PS4_SYSV_ABI sceNpTrophySystemAbortHandle();
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemBuildGroupIconUri();
|
int PS4_SYSV_ABI sceNpTrophySystemBuildGroupIconUri();
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemBuildNetTrophyIconUri();
|
int PS4_SYSV_ABI sceNpTrophySystemBuildNetTrophyIconUri();
|
||||||
|
@ -94,7 +218,8 @@ int PS4_SYSV_ABI sceNpTrophySystemRemoveTitleData();
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemRemoveUserData();
|
int PS4_SYSV_ABI sceNpTrophySystemRemoveUserData();
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemSetDbgParam();
|
int PS4_SYSV_ABI sceNpTrophySystemSetDbgParam();
|
||||||
int PS4_SYSV_ABI sceNpTrophySystemSetDbgParamInt();
|
int PS4_SYSV_ABI sceNpTrophySystemSetDbgParamInt();
|
||||||
int PS4_SYSV_ABI sceNpTrophyUnlockTrophy();
|
int PS4_SYSV_ABI sceNpTrophyUnlockTrophy(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle,
|
||||||
|
OrbisNpTrophyId trophyId, OrbisNpTrophyId* platinumId);
|
||||||
int PS4_SYSV_ABI Func_149656DA81D41C59();
|
int PS4_SYSV_ABI Func_149656DA81D41C59();
|
||||||
int PS4_SYSV_ABI Func_9F80071876FFA5F6();
|
int PS4_SYSV_ABI Func_9F80071876FFA5F6();
|
||||||
int PS4_SYSV_ABI Func_F8EF6F5350A91990();
|
int PS4_SYSV_ABI Func_F8EF6F5350A91990();
|
||||||
|
|
74
src/core/libraries/np_trophy/trophy_ui.cpp
Normal file
74
src/core/libraries/np_trophy/trophy_ui.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
#include "trophy_ui.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
using namespace Libraries::NpTrophy;
|
||||||
|
|
||||||
|
TrophyUI::TrophyUI() {
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TrophyUI::~TrophyUI() {
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Libraries::NpTrophy::TrophyUI::AddTrophyToQueue(int trophyId, std::string trophyName) {
|
||||||
|
TrophyInfo newInfo;
|
||||||
|
newInfo.trophyId = trophyId;
|
||||||
|
newInfo.trophyName = trophyName;
|
||||||
|
trophyQueue.push_back(newInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrophyUI::Finish() {
|
||||||
|
RemoveLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool displayingTrophy;
|
||||||
|
std::chrono::steady_clock::time_point trophyStartedTime;
|
||||||
|
|
||||||
|
void TrophyUI::Draw() {
|
||||||
|
const auto& io = GetIO();
|
||||||
|
|
||||||
|
const ImVec2 window_size{
|
||||||
|
std::min(io.DisplaySize.x, 200.f),
|
||||||
|
std::min(io.DisplaySize.y, 75.f),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (trophyQueue.size() != 0) {
|
||||||
|
if (!displayingTrophy) {
|
||||||
|
displayingTrophy = true;
|
||||||
|
trophyStartedTime = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point timeNow = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::seconds duration =
|
||||||
|
std::chrono::duration_cast<std::chrono::seconds>(timeNow - trophyStartedTime);
|
||||||
|
|
||||||
|
if (duration.count() >= 5) {
|
||||||
|
trophyQueue.erase(trophyQueue.begin());
|
||||||
|
displayingTrophy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trophyQueue.size() != 0) {
|
||||||
|
SetNextWindowSize(window_size);
|
||||||
|
SetNextWindowCollapsed(false);
|
||||||
|
SetNextWindowPos(ImVec2(io.DisplaySize.x - 200, 50));
|
||||||
|
KeepNavHighlight();
|
||||||
|
|
||||||
|
TrophyInfo currentTrophyInfo = trophyQueue[0];
|
||||||
|
if (Begin("Trophy Window", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoInputs)) {
|
||||||
|
Text("Trophy earned!");
|
||||||
|
TextWrapped(currentTrophyInfo.trophyName.c_str());
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/core/libraries/np_trophy/trophy_ui.h
Normal file
40
src/core/libraries/np_trophy/trophy_ui.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/fixed_value.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/np_trophy/np_trophy.h"
|
||||||
|
#include "imgui/imgui_layer.h"
|
||||||
|
|
||||||
|
namespace Libraries::NpTrophy {
|
||||||
|
|
||||||
|
struct TrophyInfo {
|
||||||
|
int trophyId = -1;
|
||||||
|
std::string trophyName;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TrophyUI final : public ImGui::Layer {
|
||||||
|
std::vector<TrophyInfo> trophyQueue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TrophyUI();
|
||||||
|
~TrophyUI() override;
|
||||||
|
|
||||||
|
void AddTrophyToQueue(int trophyId, std::string trophyName);
|
||||||
|
|
||||||
|
void Finish();
|
||||||
|
|
||||||
|
void Draw() override;
|
||||||
|
|
||||||
|
bool ShouldGrabGamepad() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Libraries::NpTrophy
|
|
@ -19,12 +19,14 @@
|
||||||
#include "core/file_format/playgo_chunk.h"
|
#include "core/file_format/playgo_chunk.h"
|
||||||
#include "core/file_format/psf.h"
|
#include "core/file_format/psf.h"
|
||||||
#include "core/file_format/splash.h"
|
#include "core/file_format/splash.h"
|
||||||
|
#include "core/file_format/trp.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
#include "core/libraries/kernel/thread_management.h"
|
#include "core/libraries/kernel/thread_management.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "core/libraries/ngs2/ngs2.h"
|
#include "core/libraries/ngs2/ngs2.h"
|
||||||
|
#include "core/libraries/np_trophy/np_trophy.h"
|
||||||
#include "core/libraries/rtc/rtc.h"
|
#include "core/libraries/rtc/rtc.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -98,6 +100,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
||||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||||
param_sfo->open(sce_sys_folder.string() + "/param.sfo", {});
|
param_sfo->open(sce_sys_folder.string() + "/param.sfo", {});
|
||||||
id = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9);
|
id = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9);
|
||||||
|
Libraries::NpTrophy::game_serial = id;
|
||||||
|
const auto trophyDir =
|
||||||
|
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
|
||||||
|
if (!std::filesystem::exists(trophyDir)) {
|
||||||
|
TRP trp;
|
||||||
|
if (!trp.Extract(file.parent_path())) {
|
||||||
|
LOG_ERROR(Loader, "Couldn't extract trophies");
|
||||||
|
}
|
||||||
|
}
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
MemoryPatcher::g_game_serial = id;
|
MemoryPatcher::g_game_serial = id;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,7 +9,8 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo
|
||||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
tabWidget = new QTabWidget(this);
|
tabWidget = new QTabWidget(this);
|
||||||
gameTrpPath_ = gameTrpPath;
|
gameTrpPath_ = gameTrpPath;
|
||||||
headers << "Trophy"
|
headers << "Unlocked"
|
||||||
|
<< "Trophy"
|
||||||
<< "Name"
|
<< "Name"
|
||||||
<< "Description"
|
<< "Description"
|
||||||
<< "ID"
|
<< "ID"
|
||||||
|
@ -61,6 +62,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
|
||||||
|
|
||||||
QStringList trpId;
|
QStringList trpId;
|
||||||
QStringList trpHidden;
|
QStringList trpHidden;
|
||||||
|
QStringList trpUnlocked;
|
||||||
QStringList trpType;
|
QStringList trpType;
|
||||||
QStringList trpPid;
|
QStringList trpPid;
|
||||||
QStringList trophyNames;
|
QStringList trophyNames;
|
||||||
|
@ -81,6 +83,15 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
|
||||||
trpHidden.append(reader.attributes().value("hidden").toString());
|
trpHidden.append(reader.attributes().value("hidden").toString());
|
||||||
trpType.append(reader.attributes().value("ttype").toString());
|
trpType.append(reader.attributes().value("ttype").toString());
|
||||||
trpPid.append(reader.attributes().value("pid").toString());
|
trpPid.append(reader.attributes().value("pid").toString());
|
||||||
|
if (reader.attributes().hasAttribute("unlockstate")) {
|
||||||
|
if (reader.attributes().value("unlockstate").toString() == "unlocked") {
|
||||||
|
trpUnlocked.append("unlocked");
|
||||||
|
} else {
|
||||||
|
trpUnlocked.append("locked");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trpUnlocked.append("locked");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.name().toString() == "name" && !trpId.isEmpty()) {
|
if (reader.name().toString() == "name" && !trpId.isEmpty()) {
|
||||||
|
@ -93,7 +104,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
|
||||||
}
|
}
|
||||||
QTableWidget* tableWidget = new QTableWidget(this);
|
QTableWidget* tableWidget = new QTableWidget(this);
|
||||||
tableWidget->setShowGrid(false);
|
tableWidget->setShowGrid(false);
|
||||||
tableWidget->setColumnCount(7);
|
tableWidget->setColumnCount(8);
|
||||||
tableWidget->setHorizontalHeaderLabels(headers);
|
tableWidget->setHorizontalHeaderLabels(headers);
|
||||||
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
@ -105,21 +116,22 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
|
||||||
QTableWidgetItem* item = new QTableWidgetItem();
|
QTableWidgetItem* item = new QTableWidgetItem();
|
||||||
item->setData(Qt::DecorationRole, icon);
|
item->setData(Qt::DecorationRole, icon);
|
||||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
tableWidget->setItem(row, 0, item);
|
tableWidget->setItem(row, 1, item);
|
||||||
if (!trophyNames.isEmpty() && !trophyDetails.isEmpty()) {
|
if (!trophyNames.isEmpty() && !trophyDetails.isEmpty()) {
|
||||||
SetTableItem(tableWidget, row, 1, trophyNames[row]);
|
SetTableItem(tableWidget, row, 0, trpUnlocked[row]);
|
||||||
SetTableItem(tableWidget, row, 2, trophyDetails[row]);
|
SetTableItem(tableWidget, row, 2, trophyNames[row]);
|
||||||
SetTableItem(tableWidget, row, 3, trpId[row]);
|
SetTableItem(tableWidget, row, 3, trophyDetails[row]);
|
||||||
SetTableItem(tableWidget, row, 4, trpHidden[row]);
|
SetTableItem(tableWidget, row, 4, trpId[row]);
|
||||||
SetTableItem(tableWidget, row, 5, GetTrpType(trpType[row].at(0)));
|
SetTableItem(tableWidget, row, 5, trpHidden[row]);
|
||||||
SetTableItem(tableWidget, row, 6, trpPid[row]);
|
SetTableItem(tableWidget, row, 6, GetTrpType(trpType[row].at(0)));
|
||||||
|
SetTableItem(tableWidget, row, 7, trpPid[row]);
|
||||||
}
|
}
|
||||||
tableWidget->verticalHeader()->resizeSection(row, icon.height());
|
tableWidget->verticalHeader()->resizeSection(row, icon.height());
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
int width = 16;
|
int width = 16;
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
width += tableWidget->horizontalHeader()->sectionSize(i);
|
width += tableWidget->horizontalHeader()->sectionSize(i);
|
||||||
}
|
}
|
||||||
tableWidget->resize(width, 720);
|
tableWidget->resize(width, 720);
|
||||||
|
|
Loading…
Reference in a new issue