diff --git a/core/libs/prx/libSceNpTrophy2/src/Context.cpp b/core/libs/prx/libSceNpTrophy2/src/Context.cpp index b2c31fbea..65a97045b 100644 --- a/core/libs/prx/libSceNpTrophy2/src/Context.cpp +++ b/core/libs/prx/libSceNpTrophy2/src/Context.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "prx/libSceNpTrophy2/include/NpTrophy2.hpp" #include "prx/libc/include/General.hpp" @@ -6,26 +8,26 @@ extern "C" { int APS5_VABI sceNpTrophy2CreateContext(int* context, int user_id, uint32_t service_label, uint64_t options) { - (void)context; + if (context == nullptr) { + APS5_INVALID_ARG_EX; + } (void)user_id; (void)service_label; (void)options; - NotImplemented_nid_no_patch(__func__); - return 0; + *context = NP_TROPHY2_CONTEXT_DEFAULT; + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2DestroyContext(int context) { (void)context; - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2RegisterContext(int context, int handle, uint64_t options) { (void)context; (void)handle; (void)options; - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_NP_TROPHY2_OK; } } diff --git a/core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp b/core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp index 25cbe3976..6a41aa647 100644 --- a/core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp +++ b/core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include "prx/libSceNpTrophy2/include/NpTrophy2.hpp" #include "prx/libc/include/General.hpp" @@ -6,28 +9,47 @@ extern "C" { int APS5_VABI sceNpTrophy2GetGameInfo(int context, int handle, NpTrophy2GameDetails* details, NpTrophy2GameData* data) { + if (details == nullptr || data == nullptr) { + APS5_INVALID_ARG_EX; + } (void)context; (void)handle; - (void)details; - (void)data; - NotImplemented_nid_no_patch(__func__); - return 0; + if (details != nullptr) { + std::memset(details, 0, sizeof(*details)); + details->num_groups = NP_TROPHY2_NUM_GROUPS; + details->num_trophies = NP_TROPHY2_NUM_TROPHIES; + details->num_platinum = NP_TROPHY2_NUM_PLATINUM; + details->num_gold = NP_TROPHY2_NUM_GOLD; + details->num_silver = NP_TROPHY2_NUM_SILVER; + details->num_bronze = NP_TROPHY2_NUM_BRONZE; + std::strncpy(details->title, NP_TROPHY2_GAME_TITLE, sizeof(details->title) - 1); + } + if (data != nullptr) { + std::memset(data, 0, sizeof(*data)); + data->unlocked_trophies = NP_TROPHY2_UNLOCKED_TROPHIES; + data->unlocked_platinum = NP_TROPHY2_UNLOCKED_PLATINUM; + data->unlocked_gold = NP_TROPHY2_UNLOCKED_GOLD; + data->unlocked_silver = NP_TROPHY2_UNLOCKED_SILVER; + data->unlocked_bronze = NP_TROPHY2_UNLOCKED_BRONZE; + data->progress_percentage = NP_TROPHY2_PROGRESS_PERCENTAGE; + } + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2GetGameIcon(int context, int handle, void* buffer, size_t* size) { (void)context; (void)handle; (void)buffer; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + if (size != nullptr) { + *size = NP_TROPHY2_ICON_SIZE_NONE; + } + throw std::runtime_error(std::string(__func__) + ": icon file not found"); } int APS5_VABI sceNpTrophy2RegisterUnlockCallback(void* callback, void* userdata) { (void)callback; (void)userdata; - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_NP_TROPHY2_OK; } } diff --git a/core/libs/prx/libSceNpTrophy2/src/GroupInfo.cpp b/core/libs/prx/libSceNpTrophy2/src/GroupInfo.cpp index c69e46f1a..09fde57f5 100644 --- a/core/libs/prx/libSceNpTrophy2/src/GroupInfo.cpp +++ b/core/libs/prx/libSceNpTrophy2/src/GroupInfo.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "prx/libSceNpTrophy2/include/NpTrophy2.hpp" #include "prx/libc/include/General.hpp" @@ -7,25 +10,64 @@ extern "C" { int APS5_VABI sceNpTrophy2GetGroupInfo(int context, int handle, int group_id, NpTrophy2GroupDetails* details, NpTrophy2GroupData* data) { + if (details == nullptr || data == nullptr) { + APS5_INVALID_ARG_EX; + } (void)context; (void)handle; - (void)group_id; - (void)details; - (void)data; - NotImplemented_nid_no_patch(__func__); - return 0; + const std::int32_t normalized_group_id = (group_id < 0 ? NP_TROPHY2_GROUP_ID_BASE : group_id); + if (details != nullptr) { + std::memset(details, 0, sizeof(*details)); + details->group_id = normalized_group_id; + details->num_trophies = NP_TROPHY2_NUM_TROPHIES; + details->num_platinum = NP_TROPHY2_NUM_PLATINUM; + details->num_gold = NP_TROPHY2_NUM_GOLD; + details->num_silver = NP_TROPHY2_NUM_SILVER; + details->num_bronze = NP_TROPHY2_NUM_BRONZE; + std::strncpy(details->title, NP_TROPHY2_GROUP_TITLE, sizeof(details->title) - 1); + } + if (data != nullptr) { + std::memset(data, 0, sizeof(*data)); + data->group_id = normalized_group_id; + data->unlocked_trophies = NP_TROPHY2_UNLOCKED_TROPHIES; + data->unlocked_platinum = NP_TROPHY2_UNLOCKED_PLATINUM; + data->unlocked_gold = NP_TROPHY2_UNLOCKED_GOLD; + data->unlocked_silver = NP_TROPHY2_UNLOCKED_SILVER; + data->unlocked_bronze = NP_TROPHY2_UNLOCKED_BRONZE; + data->progress_percentage = NP_TROPHY2_PROGRESS_PERCENTAGE; + } + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2GetGroupInfoArray(int context, int handle, uint32_t offset, uint32_t limit, NpTrophy2GroupDetails* details_array, NpTrophy2GroupData* data_array, uint32_t* count) { + if (count == nullptr) { + APS5_INVALID_ARG_EX; + } (void)context; (void)handle; - (void)offset; - (void)limit; - (void)details_array; - (void)data_array; - (void)count; - NotImplemented_nid_no_patch(__func__); - return 0; + const uint32_t out_count = (offset == 0 && limit != 0 ? 1u : 0u); + *count = out_count; + if (out_count != 0 && details_array != nullptr) { + std::memset(details_array, 0, sizeof(*details_array)); + details_array->group_id = NP_TROPHY2_GROUP_ID_BASE; + details_array->num_trophies = NP_TROPHY2_NUM_TROPHIES; + details_array->num_platinum = NP_TROPHY2_NUM_PLATINUM; + details_array->num_gold = NP_TROPHY2_NUM_GOLD; + details_array->num_silver = NP_TROPHY2_NUM_SILVER; + details_array->num_bronze = NP_TROPHY2_NUM_BRONZE; + std::strncpy(details_array->title, NP_TROPHY2_GROUP_TITLE, sizeof(details_array->title) - 1); + } + if (out_count != 0 && data_array != nullptr) { + std::memset(data_array, 0, sizeof(*data_array)); + data_array->group_id = NP_TROPHY2_GROUP_ID_BASE; + data_array->unlocked_trophies = NP_TROPHY2_UNLOCKED_TROPHIES; + data_array->unlocked_platinum = NP_TROPHY2_UNLOCKED_PLATINUM; + data_array->unlocked_gold = NP_TROPHY2_UNLOCKED_GOLD; + data_array->unlocked_silver = NP_TROPHY2_UNLOCKED_SILVER; + data_array->unlocked_bronze = NP_TROPHY2_UNLOCKED_BRONZE; + data_array->progress_percentage = NP_TROPHY2_PROGRESS_PERCENTAGE; + } + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2GetGroupIcon(int context, int handle, int group_id, void* buffer, size_t* size) { @@ -33,9 +75,10 @@ int APS5_VABI sceNpTrophy2GetGroupIcon(int context, int handle, int group_id, vo (void)handle; (void)group_id; (void)buffer; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + if (size != nullptr) { + *size = NP_TROPHY2_ICON_SIZE_NONE; + } + throw std::runtime_error(std::string(__func__) + ": icon file not found"); } } diff --git a/core/libs/prx/libSceNpTrophy2/src/Handle.cpp b/core/libs/prx/libSceNpTrophy2/src/Handle.cpp index 749365dd7..3f65f5887 100644 --- a/core/libs/prx/libSceNpTrophy2/src/Handle.cpp +++ b/core/libs/prx/libSceNpTrophy2/src/Handle.cpp @@ -1,24 +1,27 @@ +#include +#include + #include "prx/libSceNpTrophy2/include/NpTrophy2.hpp" #include "prx/libc/include/General.hpp" extern "C" { int APS5_VABI sceNpTrophy2CreateHandle(int* handle) { - (void)handle; - NotImplemented_nid_no_patch(__func__); - return 0; + if (handle == nullptr) { + APS5_INVALID_ARG_EX; + } + *handle = NP_TROPHY2_HANDLE_DEFAULT; + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2DestroyHandle(int handle) { (void)handle; - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2AbortHandle(int handle) { (void)handle; - NotImplemented_nid_no_patch(__func__); - return 0; + return SCE_NP_TROPHY2_OK; } } diff --git a/core/libs/prx/libSceNpTrophy2/src/TrophyInfo.cpp b/core/libs/prx/libSceNpTrophy2/src/TrophyInfo.cpp index eb7e72893..0f19c9782 100644 --- a/core/libs/prx/libSceNpTrophy2/src/TrophyInfo.cpp +++ b/core/libs/prx/libSceNpTrophy2/src/TrophyInfo.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "prx/libSceNpTrophy2/include/NpTrophy2.hpp" #include "prx/libc/include/General.hpp" @@ -7,25 +10,61 @@ extern "C" { int APS5_VABI sceNpTrophy2GetTrophyInfo(int context, int handle, int trophy_id, NpTrophy2Details* details, NpTrophy2Data* data) { + if (details == nullptr || data == nullptr) { + APS5_INVALID_ARG_EX; + } (void)context; (void)handle; - (void)trophy_id; - (void)details; - (void)data; - NotImplemented_nid_no_patch(__func__); - return 0; + if (details != nullptr) { + std::memset(details, 0, sizeof(*details)); + details->trophy_id = trophy_id; + details->trophy_grade = NP_TROPHY2_TROPHY_GRADE_BRONZE; + details->group_id = NP_TROPHY2_GROUP_ID_BASE; + details->hidden = false; + details->has_reward = false; + details->target.value = NP_TROPHY2_PROGRESS_VALUE_NONE; + std::strncpy(details->name, NP_TROPHY2_TROPHY_NAME, sizeof(details->name) - 1); + std::strncpy(details->description, NP_TROPHY2_TROPHY_DESCRIPTION, sizeof(details->description) - 1); + std::strncpy(details->reward, NP_TROPHY2_TROPHY_REWARD, sizeof(details->reward) - 1); + } + if (data != nullptr) { + std::memset(data, 0, sizeof(*data)); + data->trophy_id = trophy_id; + data->unlocked = false; + data->progress.value = NP_TROPHY2_PROGRESS_VALUE_NONE; + data->timestamp_tick = 0; + } + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2GetTrophyInfoArray(int context, int handle, uint32_t offset, uint32_t limit, NpTrophy2Details* details_array, NpTrophy2Data* data_array, uint32_t* count) { + if (count == nullptr) { + APS5_INVALID_ARG_EX; + } (void)context; (void)handle; - (void)offset; - (void)limit; - (void)details_array; - (void)data_array; - (void)count; - NotImplemented_nid_no_patch(__func__); - return 0; + const uint32_t out_count = (offset == 0 && limit != 0 ? 1u : 0u); + *count = out_count; + if (out_count != 0 && details_array != nullptr) { + std::memset(details_array, 0, sizeof(*details_array)); + details_array->trophy_id = NP_TROPHY2_TROPHY_ID_DEFAULT; + details_array->trophy_grade = NP_TROPHY2_TROPHY_GRADE_BRONZE; + details_array->group_id = NP_TROPHY2_GROUP_ID_BASE; + details_array->hidden = false; + details_array->has_reward = false; + details_array->target.value = NP_TROPHY2_PROGRESS_VALUE_NONE; + std::strncpy(details_array->name, NP_TROPHY2_TROPHY_NAME, sizeof(details_array->name) - 1); + std::strncpy(details_array->description, NP_TROPHY2_TROPHY_DESCRIPTION, sizeof(details_array->description) - 1); + std::strncpy(details_array->reward, NP_TROPHY2_TROPHY_REWARD, sizeof(details_array->reward) - 1); + } + if (out_count != 0 && data_array != nullptr) { + std::memset(data_array, 0, sizeof(*data_array)); + data_array->trophy_id = NP_TROPHY2_TROPHY_ID_DEFAULT; + data_array->unlocked = false; + data_array->progress.value = NP_TROPHY2_PROGRESS_VALUE_NONE; + data_array->timestamp_tick = 0; + } + return SCE_NP_TROPHY2_OK; } int APS5_VABI sceNpTrophy2GetTrophyIcon(int context, int handle, int trophy_id, void* buffer, size_t* size) { @@ -33,9 +72,10 @@ int APS5_VABI sceNpTrophy2GetTrophyIcon(int context, int handle, int trophy_id, (void)handle; (void)trophy_id; (void)buffer; - (void)size; - NotImplemented_nid_no_patch(__func__); - return 0; + if (size != nullptr) { + *size = NP_TROPHY2_ICON_SIZE_NONE; + } + throw std::runtime_error(std::string(__func__) + ": icon file not found"); } } diff --git a/core/libs/prx/libc/include/FileStream.hpp b/core/libs/prx/libc/include/FileStream.hpp index ff791a00f..40289ad23 100644 --- a/core/libs/prx/libc/include/FileStream.hpp +++ b/core/libs/prx/libc/include/FileStream.hpp @@ -5,6 +5,11 @@ #include #include +static constexpr const char* FOPEN_EXT_VERT = ".vert"; +static constexpr const char* FOPEN_MSG_NULL_ARG = "null argument"; +static constexpr const char* FOPEN_MSG_NOT_FOUND = "file not found"; +static constexpr const char* FOPEN_MSG_OPEN_FAILED = "open failed"; + class FileStream { std::FILE* _handle; bool _dynamic; diff --git a/core/libs/prx/libc/src/FileAndHeap.cpp b/core/libs/prx/libc/src/FileAndHeap.cpp index 21bff5dd1..8d724f2a0 100644 --- a/core/libs/prx/libc/src/FileAndHeap.cpp +++ b/core/libs/prx/libc/src/FileAndHeap.cpp @@ -12,22 +12,32 @@ extern "C" { [[noreturn]] void APS5_VABI _ZSt11_Xbad_allocv_nid_postfix(); - FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode) { - if (!filename || !mode) throw std::runtime_error("fopen: null argument"); - std::unique_ptr handle(std::fopen(filename, mode), std::fclose); - if (!handle) { - std::string msg = "fopen: open failed: \""; - msg += std::filesystem::absolute(filename).string(); - msg += "\": "; - msg += std::strerror(errno); - throw std::runtime_error(msg); +FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode) { + if (!filename || !mode) throw std::runtime_error(std::string(__func__) + ": " + FOPEN_MSG_NULL_ARG); + std::unique_ptr handle(std::fopen(filename, mode), std::fclose); + const auto abs_path = std::filesystem::absolute(filename).string(); + if (!handle) { + const auto reason = std::strerror(errno); + const std::filesystem::path fpath(filename); + bool sibling_exists = false; + std::error_code ec; + for (const auto& entry : std::filesystem::directory_iterator(std::filesystem::absolute(fpath.parent_path()), ec)) { + if (!ec && entry.path().stem() == fpath.stem() && entry.path().extension() != fpath.extension()) { + sibling_exists = true; + break; + } } - auto stream = std::make_unique(handle.get(), true); - handle.release(); - - APS5_LOG_OUT("success: \"%s\"", filename); - return stream.release(); + if (sibling_exists) { + APS5_LOG_OUT("%s: \"%s\": %s", FOPEN_MSG_NOT_FOUND, abs_path.c_str(), reason); + return nullptr; + } + throw std::runtime_error(std::string(__func__) + ": " + FOPEN_MSG_OPEN_FAILED + ": \"" + abs_path + "\": " + reason); } + APS5_LOG_OUT("success: \"%s\"", abs_path.c_str()); + auto stream = std::make_unique(handle.get(), true); + handle.release(); + return stream.release(); +} int APS5_VABI fclose_nid_postfix(FileStream* stream) { GetNativeStream(stream);