Implement old matching API

This commit is contained in:
RipleyTom 2024-05-14 00:12:50 +02:00 committed by Ani
parent cf65571be7
commit 3d9c8a670e
28 changed files with 3620 additions and 466 deletions

@ -1 +1 @@
Subproject commit 0100f6a5779831fa7a651e4b67ef389a8752bd9b
Subproject commit 595bf0007ab1929570c7671f091313c8fc20644e

View File

@ -443,8 +443,10 @@ target_link_libraries(rpcs3_emu PRIVATE
target_sources(rpcs3_emu PRIVATE
NP/fb_helpers.cpp
NP/np_cache.cpp
NP/np_gui_cache.cpp
NP/np_contexts.cpp
NP/np_dnshook.cpp
NP/np_requests_gui.cpp
NP/np_handler.cpp
NP/np_helpers.cpp
NP/np_notifications.cpp

View File

@ -1,6 +1,8 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellSysutilAvc.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/IdManager.h"
LOG_CHANNEL(cellSysutil);
@ -29,6 +31,79 @@ void fmt_class_string<CellAvcError>::format(std::string& out, u64 arg)
});
}
// Callback handle tag type
struct avc_cb_handle_t{};
struct avc_settings
{
avc_settings() = default;
avc_settings(const avc_settings&) = delete;
avc_settings& operator=(const avc_settings&) = delete;
SAVESTATE_INIT_POS(53);
shared_mutex mutex_cb;
vm::ptr<CellSysutilAvcCallback> avc_cb{};
vm::ptr<void> avc_cb_arg{};
atomic_t<u32> req_id_cnt = 0;
static bool saveable(bool /*is_writing*/) noexcept
{
return GET_SERIALIZATION_VERSION(cellSysutil) != 0;
}
avc_settings(utils::serial& ar) noexcept
{
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(cellSysutil);
if (version == 0)
{
return;
}
save(ar);
}
void save(utils::serial& ar)
{
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellSysutil);
ar(avc_cb, avc_cb_arg);
}
void register_cb_call(CellSysutilAvcRequestId req_id, CellSysutilAvcEvent event_id, CellSysUtilAvcEventParam param)
{
// This is equivalent to the dispatcher code
sysutil_register_cb_with_id<avc_cb_handle_t>([=, this](ppu_thread& cb_ppu) -> s32
{
vm::ptr<CellSysutilAvcCallback> avc_cb{};
vm::ptr<void> avc_cb_arg{};
{
std::lock_guard lock(this->mutex_cb);
avc_cb = this->avc_cb;
avc_cb_arg = this->avc_cb_arg;
}
if (avc_cb)
{
// TODO: lots of checks before calling the cb
if (event_id == CELL_AVC_EVENT_UNLOAD_SUCCEEDED)
{
std::lock_guard lock(this->mutex_cb);
this->avc_cb = {};
this->avc_cb_arg = {};
}
avc_cb(cb_ppu, req_id, event_id, param, avc_cb_arg);
}
return 0;
});
}
};
error_code cellSysutilAvcByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
{
cellSysutil.todo("cellSysutilAvcByeRequest(request_id=*0x%x)", request_id);
@ -36,6 +111,11 @@ error_code cellSysutilAvcByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_BYE_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
@ -152,6 +232,11 @@ error_code cellSysutilAvcJoinRequest(u32 ctx_id, vm::cptr<SceNpRoomId> room_id,
if (!room_id || !request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_JOIN_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
@ -181,6 +266,22 @@ error_code cellSysutilAvcLoadAsync(vm::ptr<CellSysutilAvcCallback> func, vm::ptr
if (videoQuality != CELL_SYSUTIL_AVC_VIDEO_QUALITY_DEFAULT || voiceQuality != CELL_SYSUTIL_AVC_VOICE_QUALITY_DEFAULT)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
{
std::lock_guard lock(settings.mutex_cb);
if (settings.avc_cb)
return CELL_AVC_ERROR_ALREADY_INITIALIZED;
settings.avc_cb = func;
settings.avc_cb_arg = userdata;
}
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_LOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}
@ -239,6 +340,11 @@ error_code cellSysutilAvcUnloadAsync(vm::ptr<CellSysutilAvcRequestId> request_id
if (!request_id)
return CELL_AVC_ERROR_INVALID_ARGUMENT;
auto& settings = g_fxo->get<avc_settings>();
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
*request_id = req_id;
settings.register_cb_call(req_id, CELL_AVC_EVENT_UNLOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
return CELL_OK;
}

View File

@ -1946,7 +1946,7 @@ error_code sceNpBasicAddPlayersHistoryAsync(vm::cptr<SceNpId> npids, u32 count,
error_code sceNpBasicGetPlayersHistoryEntryCount(u32 options, vm::ptr<u32> count)
{
sceNp.todo("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
sceNp.warning("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
if (options > SCE_NP_BASIC_PLAYERS_HISTORY_OPTIONS_ALL)
{
@ -3176,7 +3176,7 @@ error_code sceNpLookupInit()
error_code sceNpLookupTerm()
{
sceNp.todo("sceNpLookupTerm()");
sceNp.warning("sceNpLookupTerm()");
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@ -4450,141 +4450,166 @@ error_code check_text(vm::cptr<char> text)
error_code sceNpMatchingCreateCtx(vm::ptr<SceNpId> npId, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg, vm::ptr<u32> ctx_id)
{
sceNp.todo("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
sceNp.warning("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
}
if (false) // TODO
if (!nph.is_NP_init)
{
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
}
if (false) // TODO
// assumed checks done on vsh
if (!npId || !handler || !ctx_id)
{
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
}
const s32 id = create_matching_context(npId, handler, arg);
if (!id)
{
return SCE_NP_MATCHING_ERROR_CTX_MAX;
}
nph.set_current_gui_ctx_id(id);
*ctx_id = static_cast<u32>(id);
return CELL_OK;
}
error_code sceNpMatchingDestroyCtx(u32 ctx_id)
{
sceNp.todo("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
sceNp.warning("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO
if (!destroy_matching_context(ctx_id))
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
nph.set_current_gui_ctx_id(0);
return CELL_OK;
}
error_code sceNpMatchingGetResult(u32 ctx_id, u32 req_id, vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
sceNp.todo("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
sceNp.warning("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!size)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return nph.get_matching_result(ctx_id, req_id, buf, size, event);
const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
if (buf)
{
// TODO: copy data to buf
}
else
{
constexpr u32 required_size = 0; // TODO
*size = required_size;
}
if (event)
{
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
}
return CELL_OK;
// const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
// if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
// return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
}
error_code sceNpMatchingGetResultGUI(vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
sceNp.todo("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
sceNp.warning("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!size)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (buf)
return nph.get_result_gui(buf, size, event);
}
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (limit)
{
// TODO: copy data to buf
}
else
{
constexpr u32 required_size = 0; // TODO
*size = required_size;
static u64 last_call = 0;
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
return SCE_NP_MATCHING_ERROR_BUSY;
last_call = get_system_time();
}
if (event)
{
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
}
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
auto res = nph.set_room_info_gui(ctx_id, lobby_id, room_id, attr);
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingSetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO: some timeout with 30000000 us ?
return SCE_NP_MATCHING_ERROR_BUSY;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
}
error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (limit)
{
static u64 last_call = 0;
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
return SCE_NP_MATCHING_ERROR_BUSY;
last_call = get_system_time();
}
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
@ -4592,131 +4617,98 @@ error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lob
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.get_room_info_gui(ctx_id, lobby_id, room_id, attr);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO: some timeout with 30000000 us ?
return SCE_NP_MATCHING_ERROR_BUSY;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
}
error_code sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
sceNp.warning("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id || !attr)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return CELL_OK;
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingSetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, s32 flag, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
sceNp.warning("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id || (flag < SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN || flag > SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH))
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.set_room_search_flag_gui(ctx_id, lobby_id, room_id, flag);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
sceNp.warning("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!lobby_id || !room_id || !req_id)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.get_room_search_flag_gui(ctx_id, lobby_id, room_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
sceNp.todo("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!buflen)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
return nph.get_room_member_list_local_gui(ctx_id, room_id, buflen, buf);
}
return CELL_OK;
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
sceNp.warning("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
}
// FUN_00014bdc
@ -4788,41 +4780,42 @@ error_code check_room_list_params([[maybe_unused]] u32 ctx_id, vm::ptr<SceNpComm
return check_attr_id_and_duplicate(attribute);
}
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit)
{
sceNp.todo("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
// TODO: add limiter
// This check is used in all sceNpMatchingGetRoomList functions
error_code err = check_room_list_params(ctx_id, communicationId, range, cond, attr, handler, 1, 0);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
return nph.get_room_list_gui(ctx_id, communicationId, range, cond, attr, handler, arg, limit);
}
// TODO: set callback: handler + arg
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.warning("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
err = CELL_OK; // GetRoomListLimit
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return CELL_OK;
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, true);
}
error_code sceNpMatchingKickRoomMember(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingKickRoomMember(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@ -4841,10 +4834,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
{
sceNp.todo("sceNpMatchingKickRoomMemberWithOpt(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, opt=*0x%x, opt_len=%d, req_id=*0x%x)", ctx_id, room_id, user_id, opt, opt_len, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@ -4865,10 +4860,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num, s32 timeout,
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
sceNp.warning("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler || available_num < 2 || timeout < 1)
@ -4908,15 +4905,7 @@ error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
}
}
// TODO: set callback: handler + arg
error_code err = CELL_OK; // QuickMatch
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.quickmatch_gui(ctx_id, communicationId, cond, available_num, timeout, handler, arg);
}
error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> dsts, s32 num, s32 slot_type,
@ -4925,7 +4914,9 @@ error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room
sceNp.todo("sceNpMatchingSendInvitationGUI(ctx_id=%d, room_id=*0x%x, communicationId=*0x%x, dsts=*0x%x, num=%d, slot_type=%d, subject=%s, body=%s, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id,
room_id, communicationId, dsts, num, slot_type, subject, body, container, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!room_id || !communicationId || !subject || !body) // TODO: || (in_stack_0000007c != 0)
@ -4969,7 +4960,9 @@ error_code sceNpMatchingAcceptInvitationGUI(u32 ctx_id, vm::cptr<SceNpCommunicat
{
sceNp.todo("sceNpMatchingAcceptInvitationGUI(ctx_id=%d, communicationId=*0x%x, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, container, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler)
@ -5058,12 +5051,14 @@ error_code check_attr_create_room(vm::cptr<SceNpMatchingAttr> attribute)
return SCE_NP_MATCHING_ERROR_ATTR_NOT_SPECIFIED;
}
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (false) // TODO
if (nph.is_NP2_Match2_init)
{
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
}
if (!communicationId || !handler)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
@ -5073,69 +5068,66 @@ error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
// TODO: set callback: handler + arg
err = CELL_OK; // create_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.create_room_gui(ctx_id, communicationId, attr, handler, arg);
}
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
sceNp.warning("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
if (false) // TODO
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
}
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!room_id || !handler)
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
return nph.join_room_gui(ctx_id, room_id, handler, arg);
}
// TODO: set callback: handler + arg
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.warning("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
error_code err = CELL_OK; // join_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return matching_join_room(ctx_id, room_id, handler, arg);
}
error_code sceNpMatchingLeaveRoom(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
sceNp.warning("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
auto res = nph.leave_room_gui(ctx_id, room_id);
if (false) // TODO
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (res < 0)
return res;
*req_id = res;
return CELL_OK;
}
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attribute,
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr,
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
sceNp.todo("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attribute, handler, arg);
sceNp.warning("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attr, handler, arg);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (!communicationId || !handler)
@ -5183,32 +5175,23 @@ error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicatio
}
}
error_code err = check_attr_id_and_duplicate(attribute);
error_code err = check_attr_id_and_duplicate(attr);
if (err != CELL_OK)
return err;
if (false) // TODO
return SCE_NP_MATCHING_ERROR_BUSY;
// TODO: set callback: handler + arg
//err = search_join_room
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
{
// TODO ?
}
return err;
return nph.searchjoin_gui(ctx_id, communicationId, cond, attr, handler, arg);
}
error_code sceNpMatchingGrantOwnership(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
{
sceNp.todo("sceNpMatchingGrantOwnership(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
if (false) // TODO
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (nph.is_NP2_Match2_init)
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
if (false) // TODO
if (!nph.is_NP_init)
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
if (!room_id || !user_id || !req_id)
@ -6230,7 +6213,7 @@ error_code sceNpScoreGetRankingByNpIdPcIdAsync(s32 transId, SceNpScoreBoardId bo
error_code sceNpScoreAbortTransaction(s32 transId)
{
sceNp.todo("sceNpScoreAbortTransaction(transId=%d)", transId);
sceNp.warning("sceNpScoreAbortTransaction(transId=%d)", transId);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();

View File

@ -677,6 +677,17 @@ enum
SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM = 4,
};
enum
{
SCE_NP_MATCHING_ATTR_ID_MIN = 1,
SCE_NP_MATCHING_ATTR_ID_MAX = 16,
SCE_NP_MATCHING_ATTR_ID_FOR_SEARCH_CONDITION_MAX = 8,
SCE_NP_MATCHING_ATTR_ID_FOR_GRLGLIMIT_SRCH_COND_MAX = 8,
SCE_NP_MATCHING_ATTR_BIN_BIG_SIZE_ID_MAX = 2,
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_SMALL = 64,
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_BIG = 256,
};
enum
{
SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT = 1,
@ -686,6 +697,7 @@ enum
SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PRIVATE_NUM = 5,
SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE = 6,
SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG = 7,
SCE_NP_MATCHING_ROOM_ATTR_ID_MAX = 8,
};
enum
@ -706,6 +718,13 @@ enum
SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH = 1,
};
enum
{
SCE_NP_MATCHING_COND_MAX = 9,
SCE_NP_MATCHING_GRLG_LIMIT_COND_MAX = 9,
SCE_NP_MATCHING_COMP_OP_INEQUALITY_MAX = 9,
};
enum
{
SCE_NP_MATCHING_CONDITION_SEARCH_EQ = 0,
@ -714,6 +733,7 @@ enum
SCE_NP_MATCHING_CONDITION_SEARCH_LE = 3,
SCE_NP_MATCHING_CONDITION_SEARCH_GT = 4,
SCE_NP_MATCHING_CONDITION_SEARCH_GE = 5,
SCE_NP_MATCHING_CONDITION_SEARCH_MAX = 6,
};
enum
@ -724,6 +744,19 @@ enum
enum
{
SCE_NP_MATCHING_INVITATION_DESTINATION_MAX = 12,
SCE_NP_MATCHING_INVITATION_SUBJECT_MAX_CHARS = 16,
SCE_NP_MATCHING_INVITATION_BODY_MAX_CHARS = 128,
SCE_NP_MATCHING_KICK_OPT_MAX_LENGTH = 16,
SCE_NP_MATCHING_ROOM_MAX_SLOT = 16,
SCE_NP_MATCHING_CTX_MAX = 8,
};
enum
{
SCE_NP_MATCHING_SEND_INVITATION_MEMSIZE = 16 * 1024 * 1024,
SCE_NP_MATCHING_ACCEPT_INVITATION_MEMSIZE = 16 * 1024 * 1024,
};
// Basic presence options
@ -1170,7 +1203,7 @@ enum
SCE_NP_MATCHING_GUI_EVENT_ACCEPT_INVITATION = 0x0007,
SCE_NP_MATCHING_GUI_EVENT_COMMON_LOAD = 0x0008,
SCE_NP_MATCHING_GUI_EVENT_COMMON_UNLOAD = 0x0009,
SCE_NP_MATCHING_GUI_EVENT_RESERVED3 = 0x000a,
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST = 0x000a,
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST_LIMIT = 0x000b
};
@ -1697,6 +1730,59 @@ struct SceNpScoreRecordOptParam
vm::bptr<CellRtcTick> reserved;
};
// Old GUI API structures
struct SceNpMatchingRoomMember
{
vm::bptr<SceNpMatchingRoomMember> next;
SceNpUserInfo user_info;
be_t<s32> owner;
};
struct SceNpMatchingRoomStatus
{
SceNpRoomId id;
vm::bptr<SceNpMatchingRoomMember> members;
be_t<s32> num;
vm::bptr<SceNpId> kick_actor;
vm::bptr<void> opt;
be_t<s32> opt_len;
};
struct SceNpMatchingJoinedRoomInfo
{
SceNpLobbyId lobbyid;
SceNpMatchingRoomStatus room_status;
};
struct SceNpMatchingRange
{
be_t<u32> start;
be_t<u32> results;
be_t<u32> total;
};
struct SceNpMatchingRoom
{
vm::bptr<SceNpMatchingRoom> next;
SceNpRoomId id;
vm::bptr<SceNpMatchingAttr> attr;
};
struct SceNpMatchingRoomList
{
SceNpLobbyId lobbyid;
SceNpMatchingRange range;
vm::bptr<SceNpMatchingRoom> head;
};
struct SceNpMatchingSearchJoinRoomInfo
{
SceNpLobbyId lobbyid;
SceNpMatchingRoomStatus room_status;
vm::bptr<SceNpMatchingAttr> attr;
};
// NP callback functions
using SceNpCustomMenuEventHandler = s32(s32 retCode, u32 index, vm::cptr<SceNpId> npid, SceNpCustomMenuSelectedType type, vm::ptr<void> arg);
using SceNpBasicEventHandler = s32(s32 event, s32 retCode, u32 reqId, vm::ptr<void> arg);
@ -1756,3 +1842,12 @@ public:
protected:
std::shared_ptr<rpcn::rpcn_client> m_rpcn;
};
// Generic functions, also used in SceNpMatchingInt.cpp
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit);
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf);

View File

@ -576,9 +576,9 @@ error_code sceNpMatching2ContextStart(SceNpMatching2ContextId ctxId)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
return 0;
});
}
@ -1106,9 +1106,9 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
return 0;
});
}
@ -1709,9 +1709,9 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
return 0;
});
}

View File

@ -220,9 +220,9 @@ error_code sceNpCommerce2EmptyStoreCheckStart(u32 ctx_id, s32 store_check_type,
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, context_callback_param);
return 0;
});
}
@ -276,9 +276,9 @@ error_code sceNpCommerce2CreateSessionStart(u32 ctx_id)
if (ctx->context_callback)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, context_callback_param);
return 0;
});
}

View File

@ -1,10 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "sceNp.h"
LOG_CHANNEL(sceNpMatchingInt);
@ -14,48 +10,55 @@ error_code sceNpMatchingCancelRequest()
return CELL_OK;
}
error_code sceNpMatchingGetRoomMemberList()
error_code sceNpMatchingGetRoomMemberList(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomMemberList(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
}
error_code sceNpMatchingJoinRoomWithoutGUI()
error_code sceNpMatchingJoinRoomWithoutGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingJoinRoomWithoutGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
return matching_join_room(ctx_id, room_id, handler, arg);
}
// Parameter "unknown" added to distinguish this function
// from the one in sceNp.cpp which has the same name
error_code sceNpMatchingJoinRoomGUI(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
return matching_join_room(ctx_id, room_id, handler, arg);
}
error_code sceNpMatchingSetRoomInfoNoLimit(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingGetRoomListWithoutGUI()
error_code sceNpMatchingGetRoomListWithoutGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomListWithoutGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
}
error_code sceNpMatchingGetRoomListGUI()
error_code sceNpMatchingGetRoomListGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingGetRoomListGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
}
error_code sceNpMatchingGetRoomInfoNoLimit(vm::ptr<void> unknown)
error_code OLD_sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("OLD_sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
}
error_code sceNpMatchingCancelRequestGUI()
@ -70,22 +73,27 @@ error_code sceNpMatchingSendRoomMessage()
return CELL_OK;
}
error_code sceNpMatchingCreateRoomWithoutGUI()
error_code sceNpMatchingCreateRoomWithoutGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
sceNpMatchingInt.warning("sceNpMatchingCreateRoomWithoutGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
}
// This module has some conflicting function names with sceNp module, hence the REG_FNID
DECLARE(ppu_module_manager::sceNpMatchingInt)("sceNpMatchingInt", []()
{
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequest);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomMemberList);
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomWithoutGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
REG_FNID(sceNpMatchingInt, "sceNpMatchingJoinRoomGUI", OLD_sceNpMatchingJoinRoomGUI);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
REG_FNID(sceNpMatchingInt, "sceNpMatchingSetRoomInfoNoLimit", OLD_sceNpMatchingSetRoomInfoNoLimit);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListWithoutGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
// REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
REG_FNID(sceNpMatchingInt, "sceNpMatchingGetRoomInfoNoLimit", OLD_sceNpMatchingGetRoomInfoNoLimit);
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequestGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingSendRoomMessage);
REG_FUNC(sceNpMatchingInt, sceNpMatchingCreateRoomWithoutGUI);

View File

@ -1,12 +1,13 @@
#include "stdafx.h"
#include "np_handler.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "fb_helpers.h"
LOG_CHANNEL(rpcn_log, "rpcn");
namespace np
{
void np_handler::BinAttr_to_SceNpMatching2BinAttr(event_data& edata, const BinAttr* bin_attr, SceNpMatching2BinAttr* binattr_info)
void BinAttr_to_SceNpMatching2BinAttr(event_data& edata, const BinAttr* bin_attr, SceNpMatching2BinAttr* binattr_info)
{
binattr_info->id = bin_attr->id();
binattr_info->size = bin_attr->data()->size();
@ -17,7 +18,7 @@ namespace np
}
}
void np_handler::BinAttrs_to_SceNpMatching2BinAttrs(event_data& edata, const flatbuffers::Vector<flatbuffers::Offset<BinAttr>>* fb_attr, SceNpMatching2BinAttr* binattr_info)
void BinAttrs_to_SceNpMatching2BinAttrs(event_data& edata, const flatbuffers::Vector<flatbuffers::Offset<BinAttr>>* fb_attr, SceNpMatching2BinAttr* binattr_info)
{
for (flatbuffers::uoffset_t i = 0; i < fb_attr->size(); i++)
{
@ -28,20 +29,20 @@ namespace np
}
}
void np_handler::RoomMemberBinAttrInternal_to_SceNpMatching2RoomMemberBinAttrInternal(event_data& edata, const RoomMemberBinAttrInternal* fb_attr, SceNpMatching2RoomMemberBinAttrInternal* binattr_info)
void RoomMemberBinAttrInternal_to_SceNpMatching2RoomMemberBinAttrInternal(event_data& edata, const RoomMemberBinAttrInternal* fb_attr, SceNpMatching2RoomMemberBinAttrInternal* binattr_info)
{
binattr_info->updateDate.tick = fb_attr->updateDate();
BinAttr_to_SceNpMatching2BinAttr(edata, fb_attr->data(), &binattr_info->data);
}
void np_handler::RoomBinAttrInternal_to_SceNpMatching2RoomBinAttrInternal(event_data& edata, const BinAttrInternal* fb_attr, SceNpMatching2RoomBinAttrInternal* binattr_info)
void RoomBinAttrInternal_to_SceNpMatching2RoomBinAttrInternal(event_data& edata, const BinAttrInternal* fb_attr, SceNpMatching2RoomBinAttrInternal* binattr_info)
{
binattr_info->updateDate.tick = fb_attr->updateDate();
binattr_info->updateMemberId = fb_attr->updateMemberId();
BinAttr_to_SceNpMatching2BinAttr(edata, fb_attr->data(), &binattr_info->data);
}
void np_handler::RoomGroup_to_SceNpMatching2RoomGroup(const RoomGroup* fb_group, SceNpMatching2RoomGroup* sce_group)
void RoomGroup_to_SceNpMatching2RoomGroup(const RoomGroup* fb_group, SceNpMatching2RoomGroup* sce_group)
{
sce_group->groupId = fb_group->groupId();
sce_group->withPassword = fb_group->withPassword();
@ -57,7 +58,7 @@ namespace np
sce_group->curGroupMemberNum = fb_group->curGroupMemberNum();
}
void np_handler::RoomGroups_to_SceNpMatching2RoomGroups(const flatbuffers::Vector<flatbuffers::Offset<RoomGroup>>* fb_groups, SceNpMatching2RoomGroup* sce_groups)
void RoomGroups_to_SceNpMatching2RoomGroups(const flatbuffers::Vector<flatbuffers::Offset<RoomGroup>>* fb_groups, SceNpMatching2RoomGroup* sce_groups)
{
for (flatbuffers::uoffset_t i = 0; i < fb_groups->size(); i++)
{
@ -67,7 +68,25 @@ namespace np
}
}
void np_handler::UserInfo2_to_SceNpUserInfo2(event_data& edata, const UserInfo2* user, SceNpUserInfo2* user_info, bool include_onlinename, bool include_avatarurl)
void UserInfo_to_SceNpUserInfo(const UserInfo* user, SceNpUserInfo* user_info)
{
if (const auto npid = user->npId(); npid)
{
std::memcpy(user_info->userId.handle.data, npid->c_str(), std::min<usz>(16, npid->size()));
}
if (const auto online_name = user->onlineName(); online_name)
{
std::memcpy(user_info->name.data, online_name->c_str(), std::min<usz>(48, online_name->size()));
}
if (const auto avatar_url = user->avatarUrl(); avatar_url)
{
std::memcpy(user_info->icon.data, avatar_url->c_str(), std::min<usz>(127, avatar_url->size()));
}
}
void UserInfo_to_SceNpUserInfo2(event_data& edata, const UserInfo* user, SceNpUserInfo2* user_info, bool include_onlinename, bool include_avatarurl)
{
if (user->npId())
std::memcpy(user_info->npId.handle.data, user->npId()->c_str(), std::min<usz>(16, user->npId()->size()));
@ -84,7 +103,7 @@ namespace np
}
}
void np_handler::RoomDataExternal_to_SceNpMatching2RoomDataExternal(event_data& edata, const RoomDataExternal* room, SceNpMatching2RoomDataExternal* room_info, bool include_onlinename, bool include_avatarurl)
void RoomDataExternal_to_SceNpMatching2RoomDataExternal(event_data& edata, const RoomDataExternal* room, SceNpMatching2RoomDataExternal* room_info, bool include_onlinename, bool include_avatarurl)
{
room_info->serverId = room->serverId();
room_info->worldId = room->worldId();
@ -116,7 +135,7 @@ namespace np
if (auto owner = room->owner())
{
auto* ptr_owner = edata.allocate<SceNpUserInfo2>(sizeof(SceNpUserInfo2), room_info->owner);
UserInfo2_to_SceNpUserInfo2(edata, owner, ptr_owner, include_onlinename, include_avatarurl);
UserInfo_to_SceNpUserInfo2(edata, owner, ptr_owner, include_onlinename, include_avatarurl);
}
if (room->roomGroup() && room->roomGroup()->size() != 0)
@ -155,30 +174,24 @@ namespace np
}
}
void np_handler::SearchRoomResponse_to_SceNpMatching2SearchRoomResponse(event_data& edata, const SearchRoomResponse* resp, SceNpMatching2SearchRoomResponse* search_resp)
void SearchRoomResponse_to_SceNpMatching2SearchRoomResponse(event_data& edata, const SearchRoomResponse* resp, SceNpMatching2SearchRoomResponse* search_resp)
{
search_resp->range.size = resp->size();
search_resp->range.size = resp->rooms() ? resp->rooms()->size() : 0;
search_resp->range.startIndex = resp->startIndex();
search_resp->range.total = resp->total();
if (resp->rooms() && resp->rooms()->size() != 0)
SceNpMatching2RoomDataExternal* prev_room = nullptr;
for (flatbuffers::uoffset_t i = 0; i < search_resp->range.size; i++)
{
SceNpMatching2RoomDataExternal* prev_room = nullptr;
for (flatbuffers::uoffset_t i = 0; i < resp->rooms()->size(); i++)
{
auto* fb_room = resp->rooms()->Get(i);
SceNpMatching2RoomDataExternal* cur_room;
cur_room = (i > 0) ? edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), prev_room->next) :
edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), search_resp->roomDataExternal);
RoomDataExternal_to_SceNpMatching2RoomDataExternal(edata, fb_room, cur_room, true, true);
prev_room = cur_room;
}
auto* fb_room = resp->rooms()->Get(i);
SceNpMatching2RoomDataExternal* cur_room;
cur_room = edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), (i > 0) ? prev_room->next : search_resp->roomDataExternal);
RoomDataExternal_to_SceNpMatching2RoomDataExternal(edata, fb_room, cur_room, true, true);
prev_room = cur_room;
}
}
void np_handler::GetRoomDataExternalListResponse_to_SceNpMatching2GetRoomDataExternalListResponse(event_data& edata, const GetRoomDataExternalListResponse* resp, SceNpMatching2GetRoomDataExternalListResponse* get_resp, bool include_onlinename, bool include_avatarurl)
void GetRoomDataExternalListResponse_to_SceNpMatching2GetRoomDataExternalListResponse(event_data& edata, const GetRoomDataExternalListResponse* resp, SceNpMatching2GetRoomDataExternalListResponse* get_resp, bool include_onlinename, bool include_avatarurl)
{
get_resp->roomDataExternalNum = resp->rooms() ? resp->rooms()->size() : 0;
@ -188,15 +201,14 @@ namespace np
auto* fb_room = resp->rooms()->Get(i);
SceNpMatching2RoomDataExternal* cur_room;
cur_room = (i > 0) ? edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), prev_room->next) :
edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), get_resp->roomDataExternal);
cur_room = edata.allocate<SceNpMatching2RoomDataExternal>(sizeof(SceNpMatching2RoomDataExternal), (i > 0) ? prev_room->next : get_resp->roomDataExternal);
RoomDataExternal_to_SceNpMatching2RoomDataExternal(edata, fb_room, cur_room, include_onlinename, include_avatarurl);
prev_room = cur_room;
}
}
u16 np_handler::RoomDataInternal_to_SceNpMatching2RoomDataInternal(event_data& edata, const RoomDataInternal* resp, SceNpMatching2RoomDataInternal* room_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl)
u16 RoomDataInternal_to_SceNpMatching2RoomDataInternal(event_data& edata, const RoomDataInternal* resp, SceNpMatching2RoomDataInternal* room_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl)
{
u16 member_id = 0;
room_info->serverId = resp->serverId();
@ -279,9 +291,9 @@ namespace np
return member_id;
}
void np_handler::RoomMemberDataInternal_to_SceNpMatching2RoomMemberDataInternal(event_data& edata, const RoomMemberDataInternal* member_data, const SceNpMatching2RoomDataInternal* room_info, SceNpMatching2RoomMemberDataInternal* sce_member_data, bool include_onlinename, bool include_avatarurl)
void RoomMemberDataInternal_to_SceNpMatching2RoomMemberDataInternal(event_data& edata, const RoomMemberDataInternal* member_data, const SceNpMatching2RoomDataInternal* room_info, SceNpMatching2RoomMemberDataInternal* sce_member_data, bool include_onlinename, bool include_avatarurl)
{
UserInfo2_to_SceNpUserInfo2(edata, member_data->userInfo(), &sce_member_data->userInfo, include_onlinename, include_avatarurl);
UserInfo_to_SceNpUserInfo2(edata, member_data->userInfo(), &sce_member_data->userInfo, include_onlinename, include_avatarurl);
sce_member_data->joinDate.tick = member_data->joinDate();
sce_member_data->memberId = member_data->memberId();
sce_member_data->teamId = member_data->teamId();
@ -325,7 +337,7 @@ namespace np
}
}
void np_handler::RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(event_data& edata, const RoomMemberUpdateInfo* update_info, SceNpMatching2RoomMemberUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl)
void RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(event_data& edata, const RoomMemberUpdateInfo* update_info, SceNpMatching2RoomMemberUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl)
{
sce_update_info->eventCause = 0;
if (update_info->optData())
@ -347,7 +359,7 @@ namespace np
}
}
void np_handler::RoomUpdateInfo_to_SceNpMatching2RoomUpdateInfo(const RoomUpdateInfo* update_info, SceNpMatching2RoomUpdateInfo* sce_update_info)
void RoomUpdateInfo_to_SceNpMatching2RoomUpdateInfo(const RoomUpdateInfo* update_info, SceNpMatching2RoomUpdateInfo* sce_update_info)
{
sce_update_info->errorCode = 0;
sce_update_info->eventCause = 0;
@ -361,7 +373,7 @@ namespace np
}
}
void np_handler::RoomDataInternalUpdateInfo_to_SceNpMatching2RoomDataInternalUpdateInfo(event_data& edata, const RoomDataInternalUpdateInfo* update_info, SceNpMatching2RoomDataInternalUpdateInfo* sce_update_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl)
void RoomDataInternalUpdateInfo_to_SceNpMatching2RoomDataInternalUpdateInfo(event_data& edata, const RoomDataInternalUpdateInfo* update_info, SceNpMatching2RoomDataInternalUpdateInfo* sce_update_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl)
{
auto* sce_room_data = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), sce_update_info->newRoomDataInternal);
RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, update_info->newRoomDataInternal(), sce_room_data, npid, include_onlinename, include_avatarurl);
@ -417,7 +429,7 @@ namespace np
}
}
void np_handler::RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(event_data& edata, const RoomMemberDataInternalUpdateInfo* update_info, SceNpMatching2RoomMemberDataInternalUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl)
void RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(event_data& edata, const RoomMemberDataInternalUpdateInfo* update_info, SceNpMatching2RoomMemberDataInternalUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl)
{
auto* sce_room_member_data = edata.allocate<SceNpMatching2RoomMemberDataInternal>(sizeof(SceNpMatching2RoomMemberDataInternal), sce_update_info->newRoomMemberDataInternal);
RoomMemberDataInternal_to_SceNpMatching2RoomMemberDataInternal(edata, update_info->newRoomMemberDataInternal(), nullptr, sce_room_member_data, include_onlinename, include_avatarurl);
@ -461,7 +473,7 @@ namespace np
}
}
void np_handler::GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(const GetPingInfoResponse* resp, SceNpMatching2SignalingGetPingInfoResponse* sce_resp)
void GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(const GetPingInfoResponse* resp, SceNpMatching2SignalingGetPingInfoResponse* sce_resp)
{
sce_resp->serverId = resp->serverId();
sce_resp->worldId = resp->worldId();
@ -469,7 +481,7 @@ namespace np
sce_resp->rtt = resp->rtt();
}
void np_handler::RoomMessageInfo_to_SceNpMatching2RoomMessageInfo(event_data& edata, const RoomMessageInfo* mi, SceNpMatching2RoomMessageInfo* sce_mi, bool include_onlinename, bool include_avatarurl)
void RoomMessageInfo_to_SceNpMatching2RoomMessageInfo(event_data& edata, const RoomMessageInfo* mi, SceNpMatching2RoomMessageInfo* sce_mi, bool include_onlinename, bool include_avatarurl)
{
sce_mi->filtered = mi->filtered();
sce_mi->castType = mi->castType();
@ -500,7 +512,7 @@ namespace np
if (auto src_member = mi->srcMember())
{
auto* ptr_sce_userinfo = edata.allocate<SceNpUserInfo2>(sizeof(SceNpUserInfo2), sce_mi->srcMember);
UserInfo2_to_SceNpUserInfo2(edata, src_member, ptr_sce_userinfo, include_onlinename, include_avatarurl);
UserInfo_to_SceNpUserInfo2(edata, src_member, ptr_sce_userinfo, include_onlinename, include_avatarurl);
}
if (auto msg = mi->msg())
@ -513,4 +525,127 @@ namespace np
}
}
}
void MatchingRoomStatus_to_SceNpMatchingRoomStatus(event_data& edata, const MatchingRoomStatus* resp, SceNpMatchingRoomStatus* room_status)
{
const auto* vec_id = resp->id();
ensure(vec_id && vec_id->size() == 28, "Invalid room id in MatchingRoomStatus");
for (flatbuffers::uoffset_t i = 0; i < 28; i++)
{
room_status->id.opt[i] = vec_id->Get(i);
}
// In some events the member list can be empty
if (const auto* members = resp->members(); members && members->size())
{
room_status->num = members->size();
SceNpMatchingRoomMember* prev_member{};
for (flatbuffers::uoffset_t i = 0; i < members->size(); i++)
{
auto* cur_member = edata.allocate<SceNpMatchingRoomMember>(sizeof(SceNpMatchingRoomMember), (i > 0) ? prev_member->next : room_status->members);
const auto* member = members->Get(i);
ensure(member && member->info(), "Invalid member in MatchingRoomStatus list");
cur_member->owner = member->owner() ? 1 : 0;
UserInfo_to_SceNpUserInfo(member->info(), &cur_member->user_info);
prev_member = cur_member;
}
}
if (const auto* kick_npid = resp->kick_actor(); kick_npid)
{
auto* npid = edata.allocate<SceNpId>(sizeof(SceNpId), room_status->kick_actor);
std::memcpy(npid->handle.data, kick_npid->c_str(), std::min<usz>(16, kick_npid->size()));
}
if (const auto* opt = resp->opt(); opt && opt->size())
{
room_status->opt_len = opt->size();
u8* opt_data = static_cast<u8*>(edata.allocate<void>(opt->size(), room_status->opt));
for (flatbuffers::uoffset_t i = 0; i < opt->size(); i++)
{
opt_data[i] = opt->Get(i);
}
}
}
void MatchingRoomStatus_to_SceNpMatchingJoinedRoomInfo(event_data& edata, const MatchingRoomStatus* resp, SceNpMatchingJoinedRoomInfo* room_info)
{
// The use of SceNpLobbyId is unclear as it is never specified by the client except in further operations, so we always set it to a series of 0 and a 1
room_info->lobbyid.opt[27] = 1;
MatchingRoomStatus_to_SceNpMatchingRoomStatus(edata, resp, &room_info->room_status);
}
void MatchingAttr_to_SceNpMatchingAttr(event_data& edata, const flatbuffers::Vector<flatbuffers::Offset<MatchingAttr>>* attr_list, vm::bptr<SceNpMatchingAttr>& first_attr)
{
if (attr_list)
{
SceNpMatchingAttr* cur_attr = nullptr;
for (flatbuffers::uoffset_t i_attr = 0; i_attr < attr_list->size(); i_attr++)
{
const auto* attr = attr_list->Get(i_attr);
cur_attr = edata.allocate<SceNpMatchingAttr>(sizeof(SceNpMatchingAttr), cur_attr ? cur_attr->next : first_attr);
ensure(attr);
cur_attr->type = attr->attr_type();
cur_attr->id = attr->attr_id();
if (attr->data())
{
if (attr->data()->size())
{
cur_attr->value.data.size = attr->data()->size();
u8* data_ptr = static_cast<u8*>(edata.allocate<void>(attr->data()->size(), cur_attr->value.data.ptr));
memcpy(data_ptr, attr->data()->data(), attr->data()->size());
}
}
else
{
cur_attr->value.num = attr->num();
}
}
}
}
void MatchingRoom_to_SceNpMatchingRoom(event_data& edata, const MatchingRoom* resp, SceNpMatchingRoom* room)
{
ensure(room && resp->id() && resp->id()->size() == sizeof(SceNpRoomId::opt));
memcpy(room->id.opt, resp->id()->data(), sizeof(SceNpRoomId::opt));
MatchingAttr_to_SceNpMatchingAttr(edata, resp->attr(), room->attr);
}
void MatchingRoomList_to_SceNpMatchingRoomList(event_data& edata, const MatchingRoomList* resp, SceNpMatchingRoomList* room_list)
{
// The use of SceNpLobbyId is unclear as it is never specified by the client except in further operations, so we always set it to a series of 0 and a 1
room_list->lobbyid.opt[27] = 1;
room_list->range.start = resp->start();
room_list->range.total = resp->total();
if (auto rooms = resp->rooms(); rooms)
{
room_list->range.results = rooms->size();
SceNpMatchingRoom* cur_room = nullptr;
for (flatbuffers::uoffset_t i = 0; i < rooms->size(); i++)
{
const auto* room = rooms->Get(i);
cur_room = edata.allocate<SceNpMatchingRoom>(sizeof(SceNpMatchingRoom), cur_room ? cur_room->next : room_list->head);
MatchingRoom_to_SceNpMatchingRoom(edata, room, cur_room);
}
}
}
void MatchingSearchJoinRoomInfo_to_SceNpMatchingSearchJoinRoomInfo(event_data& edata, const MatchingSearchJoinRoomInfo* resp, SceNpMatchingSearchJoinRoomInfo* room_info)
{
ensure(resp->room());
room_info->lobbyid.opt[27] = 1;
MatchingRoomStatus_to_SceNpMatchingRoomStatus(edata, resp->room(), &room_info->room_status);
MatchingAttr_to_SceNpMatchingAttr(edata, resp->attr(), room_info->attr);
}
} // namespace np

29
rpcs3/Emu/NP/fb_helpers.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
namespace np
{
void BinAttr_to_SceNpMatching2BinAttr(event_data& edata, const BinAttr* bin_attr, SceNpMatching2BinAttr* binattr_info);
void BinAttrs_to_SceNpMatching2BinAttrs(event_data& edata, const flatbuffers::Vector<flatbuffers::Offset<BinAttr>>* fb_attr, SceNpMatching2BinAttr* binattr_info);
void RoomMemberBinAttrInternal_to_SceNpMatching2RoomMemberBinAttrInternal(event_data& edata, const RoomMemberBinAttrInternal* fb_attr, SceNpMatching2RoomMemberBinAttrInternal* binattr_info);
void RoomBinAttrInternal_to_SceNpMatching2RoomBinAttrInternal(event_data& edata, const BinAttrInternal* fb_attr, SceNpMatching2RoomBinAttrInternal* binattr_info);
void RoomGroup_to_SceNpMatching2RoomGroup(const RoomGroup* fb_group, SceNpMatching2RoomGroup* sce_group);
void RoomGroups_to_SceNpMatching2RoomGroups(const flatbuffers::Vector<flatbuffers::Offset<RoomGroup>>* fb_groups, SceNpMatching2RoomGroup* sce_groups);
void UserInfo_to_SceNpUserInfo(const UserInfo* user, SceNpUserInfo* user_info);
void UserInfo_to_SceNpUserInfo2(event_data& edata, const UserInfo* user, SceNpUserInfo2* user_info, bool include_onlinename, bool include_avatarurl);
void RoomDataExternal_to_SceNpMatching2RoomDataExternal(event_data& edata, const RoomDataExternal* room, SceNpMatching2RoomDataExternal* room_info, bool include_onlinename, bool include_avatarurl);
void SearchRoomResponse_to_SceNpMatching2SearchRoomResponse(event_data& edata, const SearchRoomResponse* resp, SceNpMatching2SearchRoomResponse* search_resp);
void GetRoomDataExternalListResponse_to_SceNpMatching2GetRoomDataExternalListResponse(event_data& edata, const GetRoomDataExternalListResponse* resp, SceNpMatching2GetRoomDataExternalListResponse* get_resp, bool include_onlinename, bool include_avatarurl);
u16 RoomDataInternal_to_SceNpMatching2RoomDataInternal(event_data& edata, const RoomDataInternal* resp, SceNpMatching2RoomDataInternal* room_resp, const SceNpId& npid, bool include_onlinename, bool include_avatarurl);
void RoomMemberDataInternal_to_SceNpMatching2RoomMemberDataInternal(event_data& edata, const RoomMemberDataInternal* member_data, const SceNpMatching2RoomDataInternal* room_info, SceNpMatching2RoomMemberDataInternal* sce_member_data, bool include_onlinename, bool include_avatarurl);
void RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(event_data& edata, const RoomMemberUpdateInfo* resp, SceNpMatching2RoomMemberUpdateInfo* room_info, bool include_onlinename, bool include_avatarurl);
void RoomUpdateInfo_to_SceNpMatching2RoomUpdateInfo(const RoomUpdateInfo* update_info, SceNpMatching2RoomUpdateInfo* sce_update_info);
void GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(const GetPingInfoResponse* resp, SceNpMatching2SignalingGetPingInfoResponse* sce_resp);
void RoomMessageInfo_to_SceNpMatching2RoomMessageInfo(event_data& edata, const RoomMessageInfo* mi, SceNpMatching2RoomMessageInfo* sce_mi, bool include_onlinename, bool include_avatarurl);
void RoomDataInternalUpdateInfo_to_SceNpMatching2RoomDataInternalUpdateInfo(event_data& edata, const RoomDataInternalUpdateInfo* update_info, SceNpMatching2RoomDataInternalUpdateInfo* sce_update_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl);
void RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(event_data& edata, const RoomMemberDataInternalUpdateInfo* update_info, SceNpMatching2RoomMemberDataInternalUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl);
void MatchingRoomStatus_to_SceNpMatchingRoomStatus(event_data& edata, const MatchingRoomStatus* resp, SceNpMatchingRoomStatus* room_status);
void MatchingRoomStatus_to_SceNpMatchingJoinedRoomInfo(event_data& edata, const MatchingRoomStatus* resp, SceNpMatchingJoinedRoomInfo* room_info);
void MatchingRoom_to_SceNpMatchingRoom(event_data& edata, const MatchingRoom* resp, SceNpMatchingRoom* room);
void MatchingRoomList_to_SceNpMatchingRoomList(event_data& edata, const MatchingRoomList* resp, SceNpMatchingRoomList* room_list);
void MatchingSearchJoinRoomInfo_to_SceNpMatchingSearchJoinRoomInfo(event_data& edata, const MatchingSearchJoinRoomInfo* resp, SceNpMatchingSearchJoinRoomInfo* room_info);
} // namespace np

View File

@ -32,14 +32,14 @@ table GroupConfig {
withPassword:bool;
}
table UserInfo2 {
table UserInfo {
npId:string;
onlineName:string;
avatarUrl:string;
}
table RoomMemberDataInternal {
userInfo:UserInfo2;
userInfo:UserInfo;
joinDate:uint64;
memberId:uint16;
teamId:uint8;
@ -84,7 +84,7 @@ table RoomDataExternal {
openPrivateSlotNum:uint16;
curMemberNum:uint16;
passwordSlotMask:uint64;
owner:UserInfo2;
owner:UserInfo;
roomGroup:[RoomGroup];
flagAttr:uint32;
roomSearchableIntAttrExternal:[IntAttr];
@ -128,7 +128,6 @@ table SearchRoomRequest {
table SearchRoomResponse {
startIndex:uint32;
total:uint32;
size:uint32;
rooms:[RoomDataExternal];
}
@ -262,7 +261,7 @@ table RoomMessageInfo {
filtered:bool;
castType:uint8;
dst:[uint16];
srcMember:UserInfo2;
srcMember:UserInfo;
msg:[uint8];
}
@ -483,3 +482,79 @@ table SetPresenceRequest {
comment:string;
data:[uint8];
}
table MatchingSearchCondition {
attr_type:uint32;
attr_id:uint32;
comp_op:uint32;
comp_value:uint32;
}
table MatchingAttr {
attr_type:uint32;
attr_id:uint32;
num:uint32;
data:[uint8];
}
table CreateRoomGUIRequest {
total_slots:uint32;
private_slots:uint32;
privilege_grant:bool;
stealth:bool;
game_attrs:[MatchingAttr];
}
table GUIUserInfo {
info:UserInfo;
owner:bool;
}
table MatchingRoomStatus {
id:[uint8];
members:[GUIUserInfo];
kick_actor:string;
opt:[uint8];
}
table GetRoomListGUIRequest {
range_start:uint32;
range_max:uint32;
conds:[MatchingSearchCondition];
attrs:[MatchingAttr];
}
table MatchingRoom {
id:[uint8];
attr:[MatchingAttr];
}
table MatchingRoomList {
start:uint32;
total:uint32;
rooms:[MatchingRoom];
}
table MatchingGuiRoomId {
id:[uint8];
}
table SetRoomSearchFlagGUI {
roomid:[uint8];
stealth:bool;
}
table QuickMatchGUIRequest {
conds:[MatchingSearchCondition];
available_num:uint32;
}
table SearchJoinRoomGUIRequest {
conds:[MatchingSearchCondition];
attrs:[MatchingAttr];
}
table MatchingSearchJoinRoomInfo {
room:MatchingRoomStatus;
attr:[MatchingAttr];
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
#include "stdafx.h"
#include "np_contexts.h"
#include "Emu/Cell/PPUCallback.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/Modules/cellSysutil.h"
LOG_CHANNEL(sceNp2);
@ -201,13 +203,13 @@ s32 create_commerce2_context(u32 version, vm::cptr<SceNpId> npid, vm::ptr<SceNpC
{
return static_cast<s32>(idm::make<commerce2_ctx>(version, npid, handler, arg));
}
bool destroy_commerce2_context(s32 ctx_id)
bool destroy_commerce2_context(u32 ctx_id)
{
return idm::remove<commerce2_ctx>(static_cast<u32>(ctx_id));
}
std::shared_ptr<commerce2_ctx> get_commerce2_context(u16 ctx_id)
{
return idm::get_unlocked<commerce2_ctx>(ctx_id);
return idm::get<commerce2_ctx>(ctx_id);
}
signaling_ctx::signaling_ctx(vm::ptr<SceNpId> npid, vm::ptr<SceNpSignalingHandler> handler, vm::ptr<void> arg)
@ -220,11 +222,55 @@ s32 create_signaling_context(vm::ptr<SceNpId> npid, vm::ptr<SceNpSignalingHandle
{
return static_cast<s32>(idm::make<signaling_ctx>(npid, handler, arg));
}
bool destroy_signaling_context(s32 ctx_id)
bool destroy_signaling_context(u32 ctx_id)
{
return idm::remove<signaling_ctx>(static_cast<u32>(ctx_id));
}
std::shared_ptr<signaling_ctx> get_signaling_context(u32 ctx_id)
{
return idm::get_unlocked<signaling_ctx>(ctx_id);
return idm::get<signaling_ctx>(ctx_id);
}
matching_ctx::matching_ctx(vm::ptr<SceNpId> npId, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg)
{
memcpy(&this->npid, npId.get_ptr(), sizeof(SceNpId));
this->handler = handler;
this->arg = arg;
}
void matching_ctx::queue_callback(u32 req_id, s32 event, s32 error_code)
{
if (handler)
{
sysutil_register_cb([=, handler = this->handler, ctx_id = this->ctx_id, arg = this->arg](ppu_thread& cb_ppu) -> s32
{
handler(cb_ppu, ctx_id, req_id, event, error_code, arg);
return 0;
});
}
}
void matching_ctx::queue_gui_callback(s32 event, s32 error_code)
{
if (gui_handler)
{
sysutil_register_cb([=, gui_handler = this->gui_handler, ctx_id = this->ctx_id, gui_arg = this->gui_arg](ppu_thread& cb_ppu) -> s32
{
gui_handler(cb_ppu, ctx_id, event, error_code, gui_arg);
return 0;
});
}
}
s32 create_matching_context(vm::ptr<SceNpId> npId, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg)
{
const u32 ctx_id = idm::make<matching_ctx>(npId, handler, arg);
auto ctx = get_matching_context(ctx_id);
ctx->ctx_id = ctx_id;
return static_cast<s32>(ctx_id);
}
std::shared_ptr<matching_ctx> get_matching_context(u32 ctx_id)
{
return idm::get<matching_ctx>(ctx_id);
}
bool destroy_matching_context(u32 ctx_id)
{
return idm::remove<matching_ctx>(static_cast<u32>(ctx_id));
}

View File

@ -4,6 +4,7 @@
#include <condition_variable>
#include <thread>
#include <variant>
#include <queue>
#include "Utilities/mutex.h"
@ -13,6 +14,8 @@
#include "Emu/Cell/Modules/sceNp2.h"
#include "Emu/Cell/Modules/sceNpCommerce2.h"
#include "Emu/Cell/Modules/sceNpTus.h"
#include "Emu/NP/np_event_data.h"
#include "Utilities/Thread.h"
// Used By Score and Tus
struct generic_async_transaction_context
@ -259,7 +262,7 @@ struct commerce2_ctx
};
s32 create_commerce2_context(u32 version, vm::cptr<SceNpId> npid, vm::ptr<SceNpCommerce2Handler> handler, vm::ptr<void> arg);
std::shared_ptr<commerce2_ctx> get_commerce2_context(u16 ctx_id);
bool destroy_commerce2_context(s32 ctx_id);
bool destroy_commerce2_context(u32 ctx_id);
struct signaling_ctx
{
@ -280,4 +283,37 @@ struct signaling_ctx
};
s32 create_signaling_context(vm::ptr<SceNpId> npid, vm::ptr<SceNpSignalingHandler> handler, vm::ptr<void> arg);
std::shared_ptr<signaling_ctx> get_signaling_context(u32 ctx_id);
bool destroy_signaling_context(s32 ctx_id);
bool destroy_signaling_context(u32 ctx_id);
struct matching_ctx
{
matching_ctx(vm::ptr<SceNpId> npid, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg);
void queue_callback(u32 req_id, s32 event, s32 error_code);
void queue_gui_callback(s32 event, s32 error_code);
static const u32 id_base = 0x9001;
static const u32 id_step = 1;
static const u32 id_count = 1;
SAVESTATE_INIT_POS(32);
SceNpId npid{};
vm::ptr<SceNpMatchingHandler> handler{};
vm::ptr<void> arg{};
atomic_t<u32> busy = 0;
u32 ctx_id = 0;
vm::ptr<SceNpMatchingGUIHandler> gui_handler{};
vm::ptr<void> gui_arg{};
// Used by QuickMatchGUI
u64 timeout = 0;
std::unique_ptr<named_thread<std::function<void(SceNpRoomId)>>> thread;
atomic_t<u32> wakey = 0;
// To keep track of which callback to use for sceNpMatchingGetRoomListWithoutGUI / sceNpMatchingGetRoomListGUI / sceNpMatchingGetRoomListLimitGUI
atomic_t<bool> get_room_limit_version = false;
};
s32 create_matching_context(vm::ptr<SceNpId> npid, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg);
std::shared_ptr<matching_ctx> get_matching_context(u32 ctx_id);
bool destroy_matching_context(u32 ctx_id);

View File

@ -14,6 +14,10 @@ namespace np
m_data_ptr.set(vm_addr);
}
event_data()
{
}
u8* data()
{
return m_data_ptr.get_ptr();
@ -99,8 +103,8 @@ namespace np
}
private:
vm::bptr<u8> m_data_ptr;
u32 m_max_size, m_cur_size;
vm::bptr<u8> m_data_ptr{};
u32 m_max_size = 0, m_cur_size = 0;
std::vector<u32> m_relocs;
};
} // namespace np

View File

@ -0,0 +1,113 @@
#include "stdafx.h"
#include "util/asm.hpp"
#include "np_gui_cache.h"
LOG_CHANNEL(np_gui_cache);
namespace np
{
void gui_cache_manager::add_room(const SceNpRoomId& room_id)
{
std::lock_guard lock(mutex);
const auto [room, inserted] = rooms.insert_or_assign(room_id, gui_room_cache{});
if (!inserted)
np_gui_cache.error("Cache mismatch: tried to insert room but it already existed");
}
void gui_cache_manager::del_room(const SceNpRoomId& room_id)
{
std::lock_guard lock(mutex);
if (rooms.erase(room_id) != 1)
np_gui_cache.error("Cache mismatch: tried to delete a room that wasn't in the cache");
}
void gui_cache_manager::add_member(const SceNpRoomId& room_id, const SceNpMatchingRoomMember* user_info, bool new_member)
{
std::lock_guard lock(mutex);
if (!rooms.contains(room_id))
{
np_gui_cache.error("Cache mismatch: tried to add a member to a non-existing room");
return;
}
auto& room = ::at32(rooms, room_id);
const auto [_, inserted] = room.members.insert_or_assign(user_info->user_info.userId, gui_room_member{.info = user_info->user_info, .owner = !!user_info->owner});
if (new_member)
{
if (!inserted)
np_gui_cache.error("Cache mismatch: tried to add a member but it was already in the room");
}
else
{
if (inserted)
np_gui_cache.error("Cache mismatch: tried to update a member but it wasn't already in the room");
}
}
void gui_cache_manager::del_member(const SceNpRoomId& room_id, const SceNpMatchingRoomMember* user_info)
{
std::lock_guard lock(mutex);
if (!rooms.contains(room_id))
{
np_gui_cache.error("Cache mismatch: tried to remove a member from a non-existing room");
return;
}
auto& room = ::at32(rooms, room_id);
if (room.members.erase(user_info->user_info.userId) != 1)
np_gui_cache.error("Cache mismatch: tried to remove a member but it wasn't in the room");
}
error_code gui_cache_manager::get_room_member_list(const SceNpRoomId& room_id, u32 buf_len, vm::ptr<void> data)
{
std::lock_guard lock(mutex);
if (!rooms.contains(room_id))
return SCE_NP_MATCHING_ERROR_ROOM_NOT_FOUND;
const auto& room = ::at32(rooms, room_id);
const u32 room_size = ::narrow<u32>(utils::align(sizeof(SceNpMatchingRoomStatus), 8) + (utils::align(sizeof(SceNpMatchingRoomMember), 8) * room.members.size()));
if (!data)
return not_an_error(room_size);
if (buf_len < room_size)
return SCE_NP_MATCHING_ERROR_INSUFFICIENT_BUFFER;
std::memset(data.get_ptr(), 0, buf_len);
vm::ptr<SceNpMatchingRoomStatus> room_status = vm::cast(data.addr());
std::memcpy(&room_status->id, &room_id, sizeof(SceNpRoomId));
room_status->num = ::narrow<s32>(room.members.size());
if (!room.members.empty())
{
vm::ptr<SceNpMatchingRoomMember> cur_member_ptr{};
for (const auto& [_, member] : room.members)
{
if (!cur_member_ptr)
{
room_status->members = vm::cast(data.addr() + utils::align(sizeof(SceNpMatchingRoomStatus), 8));
cur_member_ptr = room_status->members;
}
else
{
cur_member_ptr->next = vm::cast(cur_member_ptr.addr() + utils::align(sizeof(SceNpMatchingRoomMember), 8));
cur_member_ptr = cur_member_ptr->next;
}
cur_member_ptr->owner = member.owner ? 1 : 0;
std::memcpy(&cur_member_ptr->user_info, &member.info, sizeof(SceNpUserInfo));
}
}
return CELL_OK;
}
} // namespace np

View File

@ -0,0 +1,58 @@
#pragma once
#include <map>
#include <optional>
#include "Utilities/mutex.h"
#include "Emu/Cell/Modules/sceNp.h"
#include "Emu/Cell/Modules/sceNp2.h"
template <>
struct std::less<SceNpRoomId>
{
bool operator()(const SceNpRoomId& a, const SceNpRoomId& b) const
{
return (std::memcmp(a.opt, b.opt, sizeof(a.opt)) < 0);
}
};
template <>
struct std::less<SceNpId>
{
bool operator()(const SceNpId& a, const SceNpId& b) const
{
return (std::memcmp(a.handle.data, b.handle.data, sizeof(a.handle.data)) < 0);
}
};
namespace np
{
struct gui_room_member
{
SceNpUserInfo info;
bool owner;
};
struct gui_room_cache
{
std::map<SceNpId, gui_room_member> members;
};
class gui_cache_manager
{
public:
gui_cache_manager() = default;
void add_room(const SceNpRoomId& room_id);
void del_room(const SceNpRoomId& room_id);
void add_member(const SceNpRoomId& room_id, const SceNpMatchingRoomMember* user_info, bool new_member);
void del_member(const SceNpRoomId& room_id, const SceNpMatchingRoomMember* user_info);
error_code get_room_member_list(const SceNpRoomId& room_id, u32 buf_len, vm::ptr<void> data);
private:
shared_mutex mutex;
std::map<SceNpRoomId, gui_room_cache> rooms;
};
} // namespace np

View File

@ -1122,7 +1122,17 @@ namespace np
case rpcn::CommandType::TusGetMultiUserDataStatus: reply_tus_get_multiuser_data_status(req_id, data); break;
case rpcn::CommandType::TusGetFriendsDataStatus: reply_tus_get_friends_data_status(req_id, data); break;
case rpcn::CommandType::TusDeleteMultiSlotData: reply_tus_delete_multislot_data(req_id, data); break;
default: rpcn_log.error("Unknown reply(%d) received!", command); break;
case rpcn::CommandType::CreateRoomGUI: reply_create_room_gui(req_id, data); break;
case rpcn::CommandType::JoinRoomGUI: reply_join_room_gui(req_id, data); break;
case rpcn::CommandType::LeaveRoomGUI: reply_leave_room_gui(req_id, data); break;
case rpcn::CommandType::GetRoomListGUI: reply_get_room_list_gui(req_id, data); break;
case rpcn::CommandType::SetRoomSearchFlagGUI: reply_set_room_search_flag_gui(req_id, data); break;
case rpcn::CommandType::GetRoomSearchFlagGUI: reply_get_room_search_flag_gui(req_id, data); break;
case rpcn::CommandType::SetRoomInfoGUI: reply_set_room_info_gui(req_id, data); break;
case rpcn::CommandType::GetRoomInfoGUI: reply_get_room_info_gui(req_id, data); break;
case rpcn::CommandType::QuickMatchGUI: reply_quickmatch_gui(req_id, data); break;
case rpcn::CommandType::SearchJoinRoomGUI: reply_searchjoin_gui(req_id, data); break;
default: fmt::throw_exception("Unknown reply(%d) received!", command); break;
}
}
@ -1139,7 +1149,13 @@ namespace np
case rpcn::NotificationType::SignalP2PConnect: notif_p2p_connect(notif.second); break;
case rpcn::NotificationType::RoomMessageReceived: notif_room_message_received(notif.second); break;
case rpcn::NotificationType::SignalingInfo: notif_signaling_info(notif.second); break;
default: rpcn_log.error("Unknown notification(%d) received!", notif.first); break;
case rpcn::NotificationType::MemberJoinedRoomGUI: notif_member_joined_room_gui(notif.second); break;
case rpcn::NotificationType::MemberLeftRoomGUI: notif_member_left_room_gui(notif.second); break;
case rpcn::NotificationType::RoomDisappearedGUI: notif_room_disappeared_gui(notif.second); break;
case rpcn::NotificationType::RoomOwnerChangedGUI: notif_room_owner_changed_gui(notif.second); break;
case rpcn::NotificationType::UserKickedGUI: notif_user_kicked_gui(notif.second); break;
case rpcn::NotificationType::QuickMatchCompleteGUI: notif_quickmatch_complete_gui(notif.second); break;
default: fmt::throw_exception("Unknown notification(%d) received!", notif.first); break;
}
}
@ -1625,4 +1641,50 @@ namespace np
return {include_onlinename, include_avatarurl};
}
void np_handler::add_gui_request(u32 req_id, u32 ctx_id)
{
std::lock_guard lock(gui_requests.mutex);
ensure(gui_requests.list.insert({req_id, ctx_id}).second);
}
void np_handler::remove_gui_request(u32 req_id)
{
std::lock_guard lock(gui_requests.mutex);
if (gui_requests.list.erase(req_id) != 1)
{
rpcn_log.error("Failed to erase gui request %d", req_id);
}
}
u32 np_handler::take_gui_request(u32 req_id)
{
std::lock_guard lock(gui_requests.mutex);
if (!gui_requests.list.contains(req_id))
{
return 0;
}
const u32 ctx_id = ::at32(gui_requests.list, req_id);
gui_requests.list.erase(req_id);
return ctx_id;
}
std::shared_ptr<matching_ctx> np_handler::take_pending_gui_request(u32 req_id)
{
const u32 ctx_id = take_gui_request(req_id);
if (!ctx_id)
return {};
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return {};
return ctx;
}
} // namespace np

View File

@ -14,17 +14,30 @@
#include "Emu/NP/signaling_handler.h"
#include "Emu/NP/np_allocator.h"
#include "Emu/NP/np_cache.h"
#include "Emu/NP/np_gui_cache.h"
#include "Emu/NP/np_event_data.h"
#include "Emu/NP/np_contexts.h"
#include "Emu/NP/upnp_handler.h"
namespace np
{
constexpr usz MAX_SceNpMatchingAttr_list_SIZE = ((SCE_NP_MATCHING_ATTR_ID_MAX * 2) * sizeof(SceNpMatchingAttr))
+ (SCE_NP_MATCHING_ATTR_BIN_BIG_SIZE_ID_MAX * SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_BIG) +
+ ((SCE_NP_MATCHING_ATTR_ID_MAX - SCE_NP_MATCHING_ATTR_BIN_BIG_SIZE_ID_MAX) * SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_SMALL);
constexpr usz MAX_MEMBERS_PER_ROOM = 64;
constexpr usz MAX_ROOMS_PER_GET_ROOM_LIST = 20;
constexpr usz MAX_SceNpMatchingRoomStatus_SIZE = sizeof(SceNpMatchingRoomStatus) + (MAX_MEMBERS_PER_ROOM * sizeof(SceNpMatchingRoomMember)) + sizeof(SceNpId);
constexpr usz MAX_SceNpMatchingJoinedRoomInfo_SIZE = sizeof(SceNpMatchingJoinedRoomInfo) + (MAX_MEMBERS_PER_ROOM * sizeof(SceNpMatchingRoomMember)) + sizeof(SceNpId);
constexpr usz MAX_SceNpMatchingRoomList_SIZE = sizeof(SceNpMatchingRoomList) + MAX_ROOMS_PER_GET_ROOM_LIST * (sizeof(SceNpMatchingRoom) + MAX_SceNpMatchingAttr_list_SIZE);
constexpr usz MAX_SceNpMatchingRoom_SIZE = sizeof(SceNpMatchingRoom) + MAX_SceNpMatchingAttr_list_SIZE;
constexpr usz MAX_SceNpMatchingSearchJoinRoomInfo_SIZE = sizeof(SceNpMatchingSearchJoinRoomInfo) + MAX_SceNpMatchingAttr_list_SIZE;
enum class REQUEST_ID_HIGH : u16
{
MISC = 0x3333,
SCORE = 0x3334,
TUS = 0x3335,
GUI = 0x3336,
};
struct ticket_data
@ -175,6 +188,22 @@ namespace np
u32 get_match2_event(SceNpMatching2EventKey event_key, u32 dest_addr, u32 size);
// Old GUI Matching requests
error_code get_matching_result(u32 ctx_id, u32 req_id, vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event);
error_code get_result_gui(vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event);
error_code create_room_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code join_room_gui(u32 ctx_id, vm::ptr<SceNpRoomId> roomid, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code leave_room_gui(u32 ctx_id, vm::cptr<SceNpRoomId> roomid);
error_code get_room_list_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit);
error_code set_room_search_flag_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, s32 flag);
error_code get_room_search_flag_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id);
error_code set_room_info_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr);
error_code get_room_info_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr);
error_code quickmatch_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num, s32 timeout, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
error_code searchjoin_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
void set_current_gui_ctx_id(u32 id);
// Score requests
void transaction_async_handler(std::unique_lock<shared_mutex> lock, const std::shared_ptr<generic_async_transaction_context>& trans_ctx, u32 req_id, bool async);
void get_board_infos(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, vm::ptr<SceNpScoreBoardInfo> boardInfo, bool async);
@ -207,6 +236,9 @@ namespace np
std::pair<error_code, std::vector<SceNpMatching2RoomMemberId>> local_get_room_memberids(SceNpMatching2RoomId room_id, s32 sort_method);
error_code local_get_room_member_data(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id, const std::vector<SceNpMatching2AttributeId>& binattrs_list, SceNpMatching2RoomMemberDataInternal* ptr_member, u32 addr_data, u32 size_data, u32 ctx_id);
// Local GUI functions
error_code get_room_member_list_local_gui(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf);
// Friend stuff
u32 get_num_friends();
u32 get_num_blocks();
@ -271,6 +303,15 @@ namespace np
void notif_signaling_info(std::vector<u8>& data);
void notif_room_message_received(std::vector<u8>& data);
void generic_gui_notification_handler(std::vector<u8>& data, std::string_view name, s32 notification_type);
void notif_member_joined_room_gui(std::vector<u8>& data);
void notif_member_left_room_gui(std::vector<u8>& data);
void notif_room_disappeared_gui(std::vector<u8>& data);
void notif_room_owner_changed_gui(std::vector<u8>& data);
void notif_user_kicked_gui(std::vector<u8>& data);
void notif_quickmatch_complete_gui(std::vector<u8>& data);
// Reply handlers
bool reply_get_world_list(u32 req_id, std::vector<u8>& reply_data);
bool reply_create_join_room(u32 req_id, std::vector<u8>& reply_data);
@ -308,27 +349,19 @@ namespace np
bool reply_tus_get_multiuser_data_status(u32 req_id, std::vector<u8>& reply_data);
bool reply_tus_get_friends_data_status(u32 req_id, std::vector<u8>& reply_data);
bool reply_tus_delete_multislot_data(u32 req_id, std::vector<u8>& reply_data);
bool reply_create_room_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_join_room_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_leave_room_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_get_room_list_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_set_room_search_flag_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_get_room_search_flag_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_set_room_info_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_get_room_info_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_quickmatch_gui(u32 req_id, std::vector<u8>& reply_data);
bool reply_searchjoin_gui(u32 req_id, std::vector<u8>& reply_data);
// Helper functions(fb=>np2)
// Helper functions
std::pair<bool, bool> get_match2_context_options(u32 ctx_id);
void BinAttr_to_SceNpMatching2BinAttr(event_data& edata, const BinAttr* bin_attr, SceNpMatching2BinAttr* binattr_info);
void BinAttrs_to_SceNpMatching2BinAttrs(event_data& edata, const flatbuffers::Vector<flatbuffers::Offset<BinAttr>>* fb_attr, SceNpMatching2BinAttr* binattr_info);
void RoomMemberBinAttrInternal_to_SceNpMatching2RoomMemberBinAttrInternal(event_data& edata, const RoomMemberBinAttrInternal* fb_attr, SceNpMatching2RoomMemberBinAttrInternal* binattr_info);
void RoomBinAttrInternal_to_SceNpMatching2RoomBinAttrInternal(event_data& edata, const BinAttrInternal* fb_attr, SceNpMatching2RoomBinAttrInternal* binattr_info);
void RoomGroup_to_SceNpMatching2RoomGroup(const RoomGroup* fb_group, SceNpMatching2RoomGroup* sce_group);
void RoomGroups_to_SceNpMatching2RoomGroups(const flatbuffers::Vector<flatbuffers::Offset<RoomGroup>>* fb_groups, SceNpMatching2RoomGroup* sce_groups);
void UserInfo2_to_SceNpUserInfo2(event_data& edata, const UserInfo2* user, SceNpUserInfo2* user_info, bool include_onlinename, bool include_avatarurl);
void RoomDataExternal_to_SceNpMatching2RoomDataExternal(event_data& edata, const RoomDataExternal* room, SceNpMatching2RoomDataExternal* room_info, bool include_onlinename, bool include_avatarurl);
void SearchRoomResponse_to_SceNpMatching2SearchRoomResponse(event_data& edata, const SearchRoomResponse* resp, SceNpMatching2SearchRoomResponse* search_resp);
void GetRoomDataExternalListResponse_to_SceNpMatching2GetRoomDataExternalListResponse(event_data& edata, const GetRoomDataExternalListResponse* resp, SceNpMatching2GetRoomDataExternalListResponse* get_resp, bool include_onlinename, bool include_avatarurl);
u16 RoomDataInternal_to_SceNpMatching2RoomDataInternal(event_data& edata, const RoomDataInternal* resp, SceNpMatching2RoomDataInternal* room_resp, const SceNpId& npid, bool include_onlinename, bool include_avatarurl);
void RoomMemberDataInternal_to_SceNpMatching2RoomMemberDataInternal(event_data& edata, const RoomMemberDataInternal* member_data, const SceNpMatching2RoomDataInternal* room_info, SceNpMatching2RoomMemberDataInternal* sce_member_data, bool include_onlinename, bool include_avatarurl);
void RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(event_data& edata, const RoomMemberUpdateInfo* resp, SceNpMatching2RoomMemberUpdateInfo* room_info, bool include_onlinename, bool include_avatarurl);
void RoomUpdateInfo_to_SceNpMatching2RoomUpdateInfo(const RoomUpdateInfo* update_info, SceNpMatching2RoomUpdateInfo* sce_update_info);
void GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(const GetPingInfoResponse* resp, SceNpMatching2SignalingGetPingInfoResponse* sce_resp);
void RoomMessageInfo_to_SceNpMatching2RoomMessageInfo(event_data& edata, const RoomMessageInfo* mi, SceNpMatching2RoomMessageInfo* sce_mi, bool include_onlinename, bool include_avatarurl);
void RoomDataInternalUpdateInfo_to_SceNpMatching2RoomDataInternalUpdateInfo(event_data& edata, const RoomDataInternalUpdateInfo* update_info, SceNpMatching2RoomDataInternalUpdateInfo* sce_update_info, const SceNpId& npid, bool include_onlinename, bool include_avatarurl);
void RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(event_data& edata, const RoomMemberDataInternalUpdateInfo* update_info, SceNpMatching2RoomMemberDataInternalUpdateInfo* sce_update_info, bool include_onlinename, bool include_avatarurl);
bool handle_GetScoreResponse(u32 req_id, std::vector<u8>& reply_data, bool simple_result = false);
bool handle_tus_no_data(u32 req_id, std::vector<u8>& reply_data);
bool handle_TusVarResponse(u32 req_id, std::vector<u8>& reply_data);
@ -346,7 +379,7 @@ namespace np
{
if (cb)
{
sysutil_register_cb([=, *this](ppu_thread& cb_ppu) -> s32
sysutil_register_cb([=, ctx_id = this->ctx_id, event_type = this->event_type, cb = this->cb, cb_arg = this->cb_arg](ppu_thread& cb_ppu) -> s32
{
cb(cb_ppu, ctx_id, req_id, event_type, event_key, error_code, data_size, cb_arg);
return 0;
@ -403,6 +436,7 @@ namespace np
// Cache related
std::optional<SceNpMatching2SessionPassword> cached_cj_password;
cache_manager np_cache;
gui_cache_manager gui_cache;
// Messages related
std::optional<u64> selected_invite_id{};
@ -432,6 +466,31 @@ namespace np
}
event_data& allocate_req_result(u32 event_key, u32 max_size, u32 initial_size);
// GUI result
struct
{
shared_mutex mutex;
s32 event = 0;
event_data data;
} gui_result;
void set_gui_result(s32 event, event_data data);
// GUI notifications
struct gui_notification
{
s32 event = 0;
event_data edata;
};
struct
{
shared_mutex mutex;
std::map<std::pair<u32, u32>, gui_notification> list; // (ctx_id, req_id), notif
u32 counter_req_id = 1;
u32 current_gui_ctx_id = 0;
} gui_notifications;
// Async transaction threads
shared_mutex mutex_async_transactions;
std::unordered_map<u32, std::shared_ptr<generic_async_transaction_context>> async_transactions; // (req_id, transaction_ctx)
@ -459,5 +518,19 @@ namespace np
shared_mutex mutex_history;
std::map<std::string, player_history> players_history; // npid / history
struct
{
shared_mutex mutex;
std::map<u32, u32> list; // req_id / ctx_id
} gui_requests;
void add_gui_request(u32 req_id, u32 ctx_id);
void remove_gui_request(u32 req_id);
u32 take_gui_request(u32 req_id);
std::shared_ptr<matching_ctx> take_pending_gui_request(u32 req_id);
shared_mutex mutex_quickmatching;
std::map<SceNpRoomId, u32> pending_quickmatching;
};
} // namespace np

View File

@ -5,6 +5,7 @@
#include "Emu/NP/np_handler.h"
#include "Emu/NP/np_helpers.h"
#include "Emu/NP/np_structs_extra.h"
#include "Emu/NP/fb_helpers.h"
LOG_CHANNEL(rpcn_log, "rpcn");
@ -14,7 +15,7 @@ namespace np
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
auto* update_info = noti.get_flatbuffer<RoomMemberUpdateInfo>();
const auto* update_info = noti.get_flatbuffer<RoomMemberUpdateInfo>();
if (noti.is_error())
{
@ -50,7 +51,7 @@ namespace np
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
auto* update_info = noti.get_flatbuffer<RoomMemberUpdateInfo>();
const auto* update_info = noti.get_flatbuffer<RoomMemberUpdateInfo>();
if (noti.is_error())
{
@ -86,7 +87,7 @@ namespace np
{
vec_stream noti(data);
u64 room_id = noti.get<u64>();
auto* update_info = noti.get_flatbuffer<RoomUpdateInfo>();
const auto* update_info = noti.get_flatbuffer<RoomUpdateInfo>();
if (noti.is_error())
{
@ -120,7 +121,7 @@ namespace np
{
vec_stream noti(data);
SceNpMatching2RoomId room_id = noti.get<u64>();
auto* update_info = noti.get_flatbuffer<RoomDataInternalUpdateInfo>();
const auto* update_info = noti.get_flatbuffer<RoomDataInternalUpdateInfo>();
if (noti.is_error())
{
@ -156,7 +157,7 @@ namespace np
{
vec_stream noti(data);
SceNpMatching2RoomId room_id = noti.get<u64>();
auto* update_info = noti.get_flatbuffer<RoomMemberDataInternalUpdateInfo>();
const auto* update_info = noti.get_flatbuffer<RoomMemberDataInternalUpdateInfo>();
if (noti.is_error())
{
@ -193,7 +194,7 @@ namespace np
vec_stream noti(data);
u64 room_id = noti.get<u64>();
u16 member_id = noti.get<u16>();
auto* message_info = noti.get_flatbuffer<RoomMessageInfo>();
const auto* message_info = noti.get_flatbuffer<RoomMessageInfo>();
if (noti.is_error())
{
@ -266,4 +267,135 @@ namespace np
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.send_information_packets(addr_p2p, port_p2p, npid_p2p);
}
void np_handler::generic_gui_notification_handler(std::vector<u8>& data, std::string_view name, s32 notification_type)
{
vec_stream noti(data);
const auto* update_info = noti.get_flatbuffer<MatchingRoomStatus>();
if (noti.is_error())
{
rpcn_log.error("Received faulty %s notification", name);
return;
}
std::lock_guard lock(gui_notifications.mutex);
if (!gui_notifications.current_gui_ctx_id)
return;
// Should the callback signaled depend on the room id and should we track if the context is the one that created/joined/left/etc the room?
auto ctx = get_matching_context(gui_notifications.current_gui_ctx_id);
ensure(ctx);
const u32 req_id = gui_notifications.counter_req_id++;
event_data edata(np_memory.allocate(MAX_SceNpMatchingRoomStatus_SIZE), sizeof(SceNpMatchingRoomStatus), MAX_SceNpMatchingRoomStatus_SIZE);
auto* room_status = reinterpret_cast<SceNpMatchingRoomStatus*>(edata.data());
MatchingRoomStatus_to_SceNpMatchingRoomStatus(edata, update_info, room_status);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingRoomStatus(room_status);
switch (notification_type)
{
case SCE_NP_MATCHING_EVENT_ROOM_UPDATE_NEW_MEMBER:
gui_cache.add_member(room_status->id, room_status->members.get_ptr(), true);
break;
case SCE_NP_MATCHING_EVENT_ROOM_UPDATE_MEMBER_LEAVE:
gui_cache.del_member(room_status->id, room_status->members.get_ptr());
break;
case SCE_NP_MATCHING_EVENT_ROOM_DISAPPEARED:
gui_cache.del_room(room_status->id);
break;
case SCE_NP_MATCHING_EVENT_ROOM_UPDATE_OWNER_CHANGE:
gui_cache.add_member(room_status->id, room_status->members.get_ptr(), false);
gui_cache.add_member(room_status->id, room_status->members->next.get_ptr(), false);
break;
case SCE_NP_MATCHING_EVENT_ROOM_KICKED:
gui_cache.del_room(room_status->id);
break;
default:
fmt::throw_exception("Unexpected notification type in generic_gui_notification_handler: 0x%08X", notification_type);
break;
}
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = notification_type, .edata = std::move(edata)});
ctx->queue_callback(req_id, notification_type, 0);
}
void np_handler::notif_member_joined_room_gui(std::vector<u8>& data)
{
return generic_gui_notification_handler(data, "MemberJoinedRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_NEW_MEMBER);
}
void np_handler::notif_member_left_room_gui(std::vector<u8>& data)
{
return generic_gui_notification_handler(data, "MemberLeftRoomGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_MEMBER_LEAVE);
}
void np_handler::notif_room_disappeared_gui(std::vector<u8>& data)
{
return generic_gui_notification_handler(data, "RoomDisappearedGUI", SCE_NP_MATCHING_EVENT_ROOM_DISAPPEARED);
}
void np_handler::notif_room_owner_changed_gui(std::vector<u8>& data)
{
return generic_gui_notification_handler(data, "RoomOwnerChangedGUI", SCE_NP_MATCHING_EVENT_ROOM_UPDATE_OWNER_CHANGE);
}
void np_handler::notif_user_kicked_gui(std::vector<u8>& data)
{
return generic_gui_notification_handler(data, "UserKickedGUI", SCE_NP_MATCHING_EVENT_ROOM_KICKED);
}
void gui_epilog(const std::shared_ptr<matching_ctx>& ctx);
void np_handler::notif_quickmatch_complete_gui(std::vector<u8>& data)
{
vec_stream noti(data);
const auto* update_info = noti.get_flatbuffer<MatchingRoomStatus>();
if (noti.is_error())
{
rpcn_log.error("Received faulty QuickMatchCompleteGUI notification");
return;
}
std::lock_guard lock(mutex_quickmatching);
event_data edata(np_memory.allocate(MAX_SceNpMatchingJoinedRoomInfo_SIZE), sizeof(SceNpMatchingJoinedRoomInfo), MAX_SceNpMatchingJoinedRoomInfo_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingJoinedRoomInfo*>(edata.data());
MatchingRoomStatus_to_SceNpMatchingJoinedRoomInfo(edata, update_info, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingJoinedRoomInfo(room_info);
if (!pending_quickmatching.contains(room_info->room_status.id))
{
np_memory.free(edata.addr());
return;
}
const u32 ctx_id = ::at32(pending_quickmatching, room_info->room_status.id);
ensure(pending_quickmatching.erase(room_info->room_status.id) == 1);
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return;
gui_cache.add_room(room_info->room_status.id);
for (auto cur_member = room_info->room_status.members; cur_member; cur_member = cur_member->next)
{
gui_cache.add_member(room_info->room_status.id, cur_member.get_ptr(), true);
}
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_QUICK_MATCH, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_QUICK_MATCH, 0);
gui_epilog(ctx);
ctx->wakey = 1;
ctx->wakey.notify_one();
}
} // namespace np

View File

@ -9,6 +9,7 @@
#include "np_contexts.h"
#include "np_helpers.h"
#include "np_structs_extra.h"
#include "fb_helpers.h"
LOG_CHANNEL(rpcn_log, "rpcn");
@ -62,7 +63,7 @@ namespace np
u32 np_handler::get_server_status(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id)
{
// TODO: actually implement interaction with server for this?
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo);
u32 event_key = get_event_key();
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetServerInfo, sizeof(SceNpMatching2GetServerInfoResponse));
@ -80,7 +81,7 @@ namespace np
u32 np_handler::create_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext);
const auto cb_info_opt = take_pending_request(req_id);
ensure(cb_info_opt);
@ -91,7 +92,7 @@ namespace np
u32 np_handler::delete_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext);
const auto cb_info_opt = take_pending_request(req_id);
ensure(cb_info_opt);
@ -102,7 +103,7 @@ namespace np
u32 np_handler::get_world_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList);
if (!get_rpcn()->get_world_list(req_id, get_match2_context(ctx_id)->communicationId, server_id))
{
@ -157,7 +158,7 @@ namespace np
u32 np_handler::create_join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2CreateJoinRoomRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom);
extra_nps::print_createjoinroom(req);
@ -181,7 +182,7 @@ namespace np
return true;
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
const auto* resp = reply.get_flatbuffer<RoomDataInternal>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to CreateRoom command");
@ -207,7 +208,7 @@ namespace np
u32 np_handler::join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2JoinRoomRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom);
extra_nps::print_joinroom(req);
@ -248,7 +249,7 @@ namespace np
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
const auto* resp = reply.get_flatbuffer<RoomDataInternal>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to JoinRoom command");
@ -273,7 +274,7 @@ namespace np
u32 np_handler::leave_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2LeaveRoomRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom);
if (!get_rpcn()->leave_room(req_id, get_match2_context(ctx_id)->communicationId, req))
{
@ -306,7 +307,7 @@ namespace np
u32 np_handler::search_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SearchRoomRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom);
extra_nps::print_search_room(req);
@ -327,7 +328,7 @@ namespace np
return true;
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<SearchRoomResponse>();
const auto* resp = reply.get_flatbuffer<SearchRoomResponse>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to SearchRoom command");
@ -348,7 +349,7 @@ namespace np
u32 np_handler::get_roomdata_external_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataExternalListRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList);
extra_nps::print_get_roomdata_external_list_req(req);
@ -369,7 +370,7 @@ namespace np
return true;
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<GetRoomDataExternalListResponse>();
const auto* resp = reply.get_flatbuffer<GetRoomDataExternalListResponse>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomDataExternalList command");
@ -391,7 +392,7 @@ namespace np
u32 np_handler::set_roomdata_external(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataExternalRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal);
extra_nps::print_set_roomdata_ext_req(req);
@ -418,7 +419,7 @@ namespace np
u32 np_handler::get_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataInternalRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal);
if (!get_rpcn()->get_roomdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
{
@ -438,7 +439,7 @@ namespace np
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
const auto* resp = reply.get_flatbuffer<RoomDataInternal>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomDataInternal command");
@ -463,7 +464,7 @@ namespace np
u32 np_handler::set_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataInternalRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal);
extra_nps::print_set_roomdata_int_req(req);
@ -490,7 +491,7 @@ namespace np
u32 np_handler::get_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomMemberDataInternalRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal);
extra_nps::print_get_roommemberdata_int_req(req);
if (!get_rpcn()->get_roommemberdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
@ -526,7 +527,7 @@ namespace np
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<RoomMemberDataInternal>();
const auto* resp = reply.get_flatbuffer<RoomMemberDataInternal>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomMemberDataInternal command");
@ -546,7 +547,7 @@ namespace np
u32 np_handler::set_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomMemberDataInternalRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal);
extra_nps::print_set_roommemberdata_int_req(req);
@ -573,7 +574,7 @@ namespace np
u32 np_handler::set_userinfo(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetUserInfoRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo);
if (!get_rpcn()->set_userinfo(req_id, get_match2_context(ctx_id)->communicationId, req))
{
@ -603,7 +604,7 @@ namespace np
u32 np_handler::get_ping_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SignalingGetPingInfoRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo);
if (!get_rpcn()->ping_room_owner(req_id, get_match2_context(ctx_id)->communicationId, req->roomId))
{
@ -623,7 +624,7 @@ namespace np
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<GetPingInfoResponse>();
const auto* resp = reply.get_flatbuffer<GetPingInfoResponse>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to PingRoomOwner command");
@ -641,7 +642,7 @@ namespace np
u32 np_handler::send_room_message(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SendRoomMessageRequest* req)
{
u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage);
if (!get_rpcn()->send_room_message(req_id, get_match2_context(ctx_id)->communicationId, req))
{
@ -666,7 +667,7 @@ namespace np
void np_handler::req_sign_infos(const std::string& npid, u32 conn_id)
{
u32 req_id = get_req_id(REQUEST_ID_HIGH::MISC);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::MISC);
{
std::lock_guard lock(mutex_pending_sign_infos_requests);
pending_sign_infos_requests[req_id] = conn_id;
@ -719,7 +720,7 @@ namespace np
void np_handler::req_ticket([[maybe_unused]] u32 version, [[maybe_unused]] const SceNpId* npid, const char* service_id, const u8* cookie, u32 cookie_size, [[maybe_unused]] const char* entitlement_id, [[maybe_unused]] u32 consumed_count)
{
u32 req_id = get_req_id(REQUEST_ID_HIGH::MISC);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::MISC);
std::string service_id_str(service_id);
@ -785,7 +786,7 @@ namespace np
}
// Only 2 cases should be timeout or caller setting result
ensure(trans_ctx->result, "transaction_async_handler: trans_ctx->result is no set");
ensure(trans_ctx->result, "transaction_async_handler: trans_ctx->result is not set");
trans_ctx->completion_cond.notify_one();
};
@ -810,7 +811,7 @@ namespace np
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
trans_ctx->tdata = tdata_get_board_infos{.boardInfo = boardInfo};
get_rpcn()->get_board_infos(req_id, trans_ctx->communicationId, boardId);
@ -821,7 +822,7 @@ namespace np
{
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<BoardInfo>();
const auto* resp = reply.get_flatbuffer<BoardInfo>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetBoardInfos command");
@ -859,7 +860,7 @@ namespace np
void np_handler::record_score(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr<SceNpScoreComment> scoreComment, const u8* data, u32 data_size, vm::ptr<SceNpScoreRankNumber> tmpRank, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
std::optional<std::string> str_comment = scoreComment ? std::optional(std::string(reinterpret_cast<const char*>(scoreComment->data))) : std::nullopt;
std::optional<std::vector<u8>> vec_data;
@ -942,7 +943,7 @@ namespace np
if (tdata->game_data.size() == tdata->game_data_size)
{
trans_ctx->result = std::nullopt;
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
get_rpcn()->record_score_data(req_id, trans_ctx->communicationId, trans_ctx->pcId, boardId, score, tdata->game_data);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
}
@ -994,7 +995,7 @@ namespace np
{
trans_ctx->tdata = tdata_get_score_data{.totalSize = totalSize, .recvSize = recvSize, .score_data = score_data};
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
get_rpcn()->get_score_data(req_id, trans_ctx->communicationId, trans_ctx->pcId, boardId, npId);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
return;
@ -1065,7 +1066,7 @@ namespace np
void np_handler::get_score_range(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr<SceNpScoreRankData> rankArray, u32 rankArraySize, vm::ptr<SceNpScoreComment> commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr<void> infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr<CellRtcTick> lastSortDate, vm::ptr<SceNpScoreRankNumber> totalRecord, bool async, bool deprecated)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
trans_ctx->tdata = tdata_get_score_generic{
.rankArray = rankArray,
@ -1126,7 +1127,7 @@ namespace np
}
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<GetScoreResponse>();
const auto* resp = reply.get_flatbuffer<GetScoreResponse>();
if (reply.is_error())
{
@ -1243,7 +1244,7 @@ namespace np
void np_handler::get_score_friend(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr<SceNpScoreRankData> rankArray, u32 rankArraySize, vm::ptr<SceNpScoreComment> commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr<void> infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr<CellRtcTick> lastSortDate, vm::ptr<SceNpScoreRankNumber> totalRecord, bool async, bool deprecated)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
trans_ctx->tdata = tdata_get_score_generic{
.rankArray = rankArray,
.rankArraySize = rankArraySize,
@ -1272,7 +1273,7 @@ namespace np
void np_handler::get_score_npid(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, const std::vector<std::pair<SceNpId, s32>>& npid_vec, vm::ptr<SceNpScorePlayerRankData> rankArray, u32 rankArraySize, vm::ptr<SceNpScoreComment> commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr<void> infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr<CellRtcTick> lastSortDate, vm::ptr<SceNpScoreRankNumber> totalRecord, bool async, bool deprecated)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
trans_ctx->tdata = tdata_get_score_generic{
.rankArray = rankArray,
.rankArraySize = rankArraySize,
@ -1356,7 +1357,7 @@ namespace np
}
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<TusVarResponse>();
const auto* resp = reply.get_flatbuffer<TusVarResponse>();
if (reply.is_error())
{
@ -1482,7 +1483,7 @@ namespace np
}
vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<TusDataStatusResponse>();
const auto* resp = reply.get_flatbuffer<TusDataStatusResponse>();
if (reply.is_error())
{
@ -1531,7 +1532,7 @@ namespace np
void np_handler::tus_set_multislot_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, vm::cptr<s64> variableArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
get_rpcn()->tus_set_multislot_variable(req_id, trans_ctx->communicationId, targetNpId, slotIdArray, variableArray, arrayNum, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
@ -1545,7 +1546,7 @@ namespace np
void np_handler::tus_get_multislot_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, vm::ptr<SceNpTusVariable> variableArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_variables_generic {
.variableArray = variableArray,
@ -1564,7 +1565,7 @@ namespace np
void np_handler::tus_get_multiuser_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, std::vector<SceNpOnlineId> targetNpIdArray, SceNpTusSlotId slotId, vm::ptr<SceNpTusVariable> variableArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_variables_generic {
.variableArray = variableArray,
@ -1583,7 +1584,7 @@ namespace np
void np_handler::tus_get_friends_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr<SceNpTusVariable> variableArray,s32 arrayNum, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_variables_generic {
.variableArray = variableArray,
@ -1602,7 +1603,7 @@ namespace np
void np_handler::tus_add_and_get_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr<SceNpTusVariable> outVariable, vm::ptr<SceNpTusAddAndGetVariableOptParam> option, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_variable_generic {
.outVariable = outVariable,
@ -1620,7 +1621,7 @@ namespace np
void np_handler::tus_try_and_set_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr<SceNpTusVariable> resultVariable, vm::ptr<SceNpTusTryAndSetVariableOptParam> option, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_variable_generic {
.outVariable = resultVariable,
@ -1638,7 +1639,7 @@ namespace np
void np_handler::tus_delete_multislot_variable(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
get_rpcn()->tus_delete_multislot_variable(req_id, trans_ctx->communicationId, targetNpId, slotIdArray, arrayNum, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
@ -1668,7 +1669,7 @@ namespace np
if (tdata->tus_data.size() == tdata->tus_data_size)
{
trans_ctx->result = std::nullopt;
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
get_rpcn()->tus_set_data(req_id, trans_ctx->communicationId, targetNpId, slotId, tdata->tus_data, info, option, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
}
@ -1691,7 +1692,7 @@ namespace np
if (!tdata)
{
trans_ctx->tdata = tdata_tus_get_data{.recvSize = recvSize, .dataStatus = dataStatus, .data = data};
u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
get_rpcn()->tus_get_data(req_id, trans_ctx->communicationId, targetNpId, slotId, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
return;
@ -1798,7 +1799,7 @@ namespace np
void np_handler::tus_get_multislot_data_status(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, vm::ptr<SceNpTusDataStatus> statusArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_datastatus_generic {
.statusArray = statusArray,
@ -1817,7 +1818,7 @@ namespace np
void np_handler::tus_get_multiuser_data_status(std::shared_ptr<tus_transaction_ctx>& trans_ctx, std::vector<SceNpOnlineId> targetNpIdArray, SceNpTusSlotId slotId, vm::ptr<SceNpTusDataStatus> statusArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_datastatus_generic {
.statusArray = statusArray,
@ -1836,7 +1837,7 @@ namespace np
void np_handler::tus_get_friends_data_status(std::shared_ptr<tus_transaction_ctx>& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr<SceNpTusDataStatus> statusArray, s32 arrayNum, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
trans_ctx->tdata = tdata_tus_get_datastatus_generic {
.statusArray = statusArray,
@ -1855,7 +1856,7 @@ namespace np
void np_handler::tus_delete_multislot_data(std::shared_ptr<tus_transaction_ctx>& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, s32 arrayNum, bool vuser, bool async)
{
std::unique_lock lock(trans_ctx->mutex);
u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
get_rpcn()->tus_delete_multislot_data(req_id, trans_ctx->communicationId, targetNpId, slotIdArray, arrayNum, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
@ -1865,8 +1866,4 @@ namespace np
{
return handle_tus_no_data(req_id, reply_data);
}
} // namespace np

View File

@ -0,0 +1,777 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/Memory/vm_ptr.h"
#include "Emu/IdManager.h"
#include "np_handler.h"
#include "np_contexts.h"
#include "np_helpers.h"
#include "np_structs_extra.h"
#include "fb_helpers.h"
LOG_CHANNEL(rpcn_log, "rpcn");
namespace np
{
std::pair<error_code, std::shared_ptr<matching_ctx>> gui_prelude(u32 ctx_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return {SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND, {}};
if (!ctx->busy.compare_and_swap_test(0, 1))
return {SCE_NP_MATCHING_ERROR_CTX_STILL_RUNNING, {}};
ctx->ctx_id = ctx_id;
ctx->gui_handler = handler;
ctx->gui_arg = arg;
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_COMMON_LOAD, 0);
return {CELL_OK, ctx};
}
void gui_epilog(const std::shared_ptr<matching_ctx>& ctx)
{
ensure(ctx->busy.compare_and_swap_test(1, 0), "Matching context wasn't busy in gui_epilog");
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_COMMON_UNLOAD, 0);
}
void np_handler::set_current_gui_ctx_id(u32 id)
{
std::lock_guard lock(gui_notifications.mutex);
gui_notifications.current_gui_ctx_id = id;
if (id == 0)
{
for (const auto& [key, notif_data] : gui_notifications.list)
{
np_memory.free(notif_data.edata.addr());
}
gui_notifications.list.clear();
}
}
void np_handler::set_gui_result(s32 event, np::event_data data)
{
std::lock_guard lock(gui_result.mutex);
if (gui_result.event)
np_memory.free(gui_result.data.addr());
gui_result.data = std::move(data);
gui_result.event = event;
}
error_code np_handler::get_matching_result(u32 ctx_id, u32 req_id, vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
std::lock_guard lock(gui_notifications.mutex);
auto ctx = get_matching_context(ctx_id);
if (!gui_notifications.current_gui_ctx_id || !ctx)
{
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
}
if (!gui_notifications.list.contains(std::make_pair(ctx_id, req_id)))
{
return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
}
const auto key = std::make_pair(ctx_id, req_id);
auto& notif = ::at32(gui_notifications.list, key);
if (event)
{
*event = notif.event;
}
if (!buf)
{
*size = notif.edata.size();
return CELL_OK;
}
const u32 final_size = std::min(static_cast<u32>(*size), notif.edata.size());
notif.edata.apply_relocations(buf.addr());
memcpy(buf.get_ptr(), notif.edata.data(), final_size);
*size = final_size;
np_memory.free(notif.edata.addr());
gui_notifications.list.erase(key);
return CELL_OK;
}
error_code np_handler::get_result_gui(vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
{
std::lock_guard lock(gui_result.mutex);
if (!gui_result.event)
{
return SCE_NP_MATCHING_ERROR_RESULT_NOT_FOUND;
}
if (event)
{
*event = gui_result.event;
}
if (!buf)
{
*size = gui_result.data.size();
return CELL_OK;
}
const u32 final_size = std::min(static_cast<u32>(*size), gui_result.data.size());
gui_result.data.apply_relocations(buf.addr());
memcpy(buf.get_ptr(), gui_result.data.data(), final_size);
*size = final_size;
np_memory.free(gui_result.data.addr());
gui_result.event = 0;
return CELL_OK;
}
error_code np_handler::create_room_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
const auto [error, ctx] = gui_prelude(ctx_id, handler, arg);
if (error)
return error;
for (auto cur_attr = attr; cur_attr; cur_attr = cur_attr->next)
{
extra_nps::print_SceNpMatchingAttr(cur_attr.get_ptr());
}
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
get_rpcn()->createjoin_room_gui(req_id, *communicationId, attr.get_ptr());
return CELL_OK;
}
bool np_handler::reply_create_room_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
ensure(!rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])), "Unexpected error in CreateRoomGUI reply");
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoomStatus>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to CreateRoomGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingJoinedRoomInfo_SIZE), sizeof(SceNpMatchingJoinedRoomInfo), MAX_SceNpMatchingJoinedRoomInfo_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingJoinedRoomInfo*>(edata.data());
MatchingRoomStatus_to_SceNpMatchingJoinedRoomInfo(edata, resp, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
gui_cache.add_room(room_info->room_status.id);
gui_cache.add_member(room_info->room_status.id, room_info->room_status.members.get_ptr(), true);
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM, 0);
gui_epilog(ctx);
return true;
}
error_code np_handler::join_room_gui(u32 ctx_id, vm::ptr<SceNpRoomId> roomid, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto [error, ctx] = gui_prelude(ctx_id, handler, arg);
if (error)
return error;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
get_rpcn()->join_room_gui(req_id, *roomid);
return CELL_OK;
}
bool np_handler::reply_join_room_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
s32 error = -1;
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::RoomMissing:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
case rpcn::ErrorType::RoomFull:
// Might also be SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN or SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED ?
error = SCE_NP_MATCHING_SERVER_ERROR_ROOM_CLOSED;
break;
case rpcn::ErrorType::RoomAlreadyJoined:
error = SCE_NP_MATCHING_SERVER_ERROR_ACCESS_FORBIDDEN;
break;
default:
fmt::throw_exception("Unexpected error in JoinRoomGUI reply: %d", reply_data[0]);
break;
}
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, error);
gui_epilog(ctx);
return true;
}
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoomStatus>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to JoinRoomGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingJoinedRoomInfo_SIZE), sizeof(SceNpMatchingJoinedRoomInfo), MAX_SceNpMatchingJoinedRoomInfo_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingJoinedRoomInfo*>(edata.data());
MatchingRoomStatus_to_SceNpMatchingJoinedRoomInfo(edata, resp, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingJoinedRoomInfo(room_info);
gui_cache.add_room(room_info->room_status.id);
for (auto cur_member = room_info->room_status.members; cur_member; cur_member = cur_member->next)
{
gui_cache.add_member(room_info->room_status.id, cur_member.get_ptr(), true);
}
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_JOIN_ROOM, 0);
gui_epilog(ctx);
return true;
}
error_code np_handler::leave_room_gui(u32 ctx_id, vm::cptr<SceNpRoomId> roomid)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(roomid);
extra_nps::print_SceNpRoomId(*roomid);
get_rpcn()->leave_room_gui(req_id, *roomid);
return not_an_error(req_id);
}
bool np_handler::reply_leave_room_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
s32 error = -1;
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
default:
fmt::throw_exception("Unexpected error in LeaveRoomGUI reply: %d", reply_data[0]);
break;
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, error);
return true;
}
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoomStatus>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to LeaveRoomGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingRoomStatus_SIZE), sizeof(SceNpMatchingRoomStatus), MAX_SceNpMatchingRoomStatus_SIZE);
auto* room_status = reinterpret_cast<SceNpMatchingRoomStatus*>(edata.data());
MatchingRoomStatus_to_SceNpMatchingRoomStatus(edata, resp, room_status);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingRoomStatus(room_status);
gui_cache.del_room(room_status->id);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, .edata = std::move(edata)});
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, 0);
return true;
}
error_code np_handler::get_room_list_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit)
{
auto [error, ctx] = gui_prelude(ctx_id, handler, arg);
if (error)
return error;
for (auto cur_cond = cond; cur_cond; cur_cond = cur_cond->next)
{
extra_nps::print_SceNpMatchingSearchCondition(cur_cond.get_ptr());
}
for (auto cur_attr = attr; cur_attr; cur_attr = cur_attr->next)
{
extra_nps::print_SceNpMatchingAttr(cur_attr.get_ptr());
}
ctx->get_room_limit_version = limit;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(range);
get_rpcn()->get_room_list_gui(req_id, *communicationId, range.get_ptr(), cond, attr);
return CELL_OK;
}
bool np_handler::reply_get_room_list_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
ensure(!rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])), "Unexpected error in GetRoomListGUI reply");
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoomList>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomListGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingRoomList_SIZE), sizeof(SceNpMatchingRoomList), MAX_SceNpMatchingRoomList_SIZE);
auto* room_list = reinterpret_cast<SceNpMatchingRoomList*>(edata.data());
MatchingRoomList_to_SceNpMatchingRoomList(edata, resp, room_list);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingRoomList(room_list);
if (ctx->get_room_limit_version)
{
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST_LIMIT, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST_LIMIT, 0);
}
else
{
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST, 0);
}
gui_epilog(ctx);
return true;
}
error_code np_handler::set_room_search_flag_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> /* lobby_id */, vm::ptr<SceNpRoomId> room_id, s32 flag)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(room_id);
extra_nps::print_SceNpRoomId(*room_id);
get_rpcn()->set_room_search_flag_gui(req_id, *room_id, flag);
return not_an_error(req_id);
}
bool np_handler::reply_set_room_search_flag_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
s32 error = 0;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
case rpcn::ErrorType::Unauthorized:
error = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED;
break;
default:
fmt::throw_exception("Unexpected error in SetRoomSearchFlagGUI reply: %d", reply_data[0]);
break;
}
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_SEARCH_FLAG_DONE, error);
return true;
}
error_code np_handler::get_room_search_flag_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> /* lobby_id */, vm::ptr<SceNpRoomId> room_id)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(room_id);
extra_nps::print_SceNpRoomId(*room_id);
get_rpcn()->get_room_search_flag_gui(req_id, *room_id);
return not_an_error(req_id);
}
bool np_handler::reply_get_room_search_flag_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
s32 error = -1;
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
default:
fmt::throw_exception("Unexpected error in GetRoomSearchFlagGUI reply: %d", reply_data[0]);
break;
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, error);
return true;
}
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoom>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomSearchFlagGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingRoom_SIZE), sizeof(SceNpMatchingRoom), MAX_SceNpMatchingRoom_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingRoom*>(edata.data());
MatchingRoom_to_SceNpMatchingRoom(edata, resp, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingRoom(room_info);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, .edata = std::move(edata)});
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, 0);
return true;
}
error_code np_handler::set_room_info_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> /* lobby_id */, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
for (auto cur_attr = attr; cur_attr; cur_attr = cur_attr->next)
{
extra_nps::print_SceNpMatchingAttr(cur_attr.get_ptr());
}
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(room_id && attr);
// extra_nps::print_SceNpRoomId(*room_id);
get_rpcn()->set_room_info_gui(req_id, *room_id, attr);
return not_an_error(req_id);
}
bool np_handler::reply_set_room_info_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
s32 error = 0;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
case rpcn::ErrorType::Unauthorized:
error = SCE_NP_MATCHING_SERVER_ERROR_NOT_ALLOWED;
break;
default:
fmt::throw_exception("Unexpected error in SetRoomInfoGUI reply: %d", reply_data[0]);
break;
}
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_SET_ROOM_INFO_DONE, error);
return true;
}
error_code np_handler::get_room_info_gui(u32 ctx_id, vm::ptr<SceNpLobbyId> /* lobby_id */, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
ensure(room_id && attr);
// extra_nps::print_SceNpRoomId(*room_id);
get_rpcn()->get_room_info_gui(req_id, *room_id, attr);
return not_an_error(req_id);
}
bool np_handler::reply_get_room_info_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
s32 error = -1;
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_SERVER_ERROR_NO_SUCH_ROOM;
break;
default:
fmt::throw_exception("Unexpected error in GetRoomInfoGUI reply: %d", reply_data[0]);
break;
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, error);
return true;
}
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingRoom>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to GetRoomInfoGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingRoom_SIZE), sizeof(SceNpMatchingRoom), MAX_SceNpMatchingRoom_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingRoom*>(edata.data());
MatchingRoom_to_SceNpMatchingRoom(edata, resp, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingRoom(room_info);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, .edata = std::move(edata)});
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, 0);
return true;
}
error_code np_handler::quickmatch_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num, s32 timeout, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto [error, ctx] = gui_prelude(ctx_id, handler, arg);
if (error)
return error;
ctx->timeout = timeout;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
get_rpcn()->quickmatch_gui(req_id, *communicationId, cond, available_num);
return CELL_OK;
}
bool np_handler::reply_quickmatch_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
ensure(!rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])), "Unexpected error in QuickMatchGUI reply");
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingGuiRoomId>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to QuickMatchGUI command");
SceNpRoomId room_id{};
ensure(resp->id() && resp->id()->size() == sizeof(SceNpRoomId::opt));
std::memcpy(room_id.opt, resp->id()->data(), sizeof(SceNpRoomId::opt));
const auto [_, inserted] = pending_quickmatching.insert_or_assign(room_id, ctx->ctx_id);
ensure(inserted);
// Now that the reply has been received, we start the wait for the notification
ctx->thread = std::make_unique<named_thread<std::function<void(SceNpRoomId)>>>("NP GUI Timeout Worker", [ctx, req_id, this](SceNpRoomId room_id)
{
ctx->wakey.wait(0, static_cast<atomic_wait_timeout>(ctx->timeout * 1'000'000'000));
if (thread_ctrl::state() == thread_state::aborting)
return;
{
std::lock_guard lock(this->mutex_quickmatching);
if (this->pending_quickmatching.erase(room_id) != 1)
return;
}
if (ctx->wakey == 0)
{
// Verify that the context is still valid
if (!idm::check<matching_ctx>(ctx->ctx_id))
return;
rpcn_log.notice("QuickMatch timeout");
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
this->get_rpcn()->leave_room_gui(req_id, room_id);
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_QUICK_MATCH, SCE_NP_MATCHING_ERROR_TIMEOUT);
gui_epilog(ctx);
}
});
ctx->wakey = 0;
auto& thread = *ctx->thread;
thread(room_id);
return true;
}
error_code np_handler::searchjoin_gui(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
{
auto [error, ctx] = gui_prelude(ctx_id, handler, arg);
if (error)
return error;
const u32 req_id = get_req_id(REQUEST_ID_HIGH::GUI);
add_gui_request(req_id, ctx_id);
get_rpcn()->searchjoin_gui(req_id, *communicationId, cond, attr);
return CELL_OK;
}
bool np_handler::reply_searchjoin_gui(u32 req_id, std::vector<u8>& reply_data)
{
auto ctx = take_pending_gui_request(req_id);
if (!ctx)
return true;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
{
s32 error = -1;
switch (static_cast<rpcn::ErrorType>(reply_data[0]))
{
case rpcn::ErrorType::NotFound:
error = SCE_NP_MATCHING_ERROR_SEARCH_JOIN_ROOM_NOT_FOUND;
break;
default:
fmt::throw_exception("Unexpected error in SearchJoinRoomGUI reply: %d", reply_data[0]);
break;
}
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, error);
gui_epilog(ctx);
return true;
}
vec_stream reply(reply_data, 1);
const auto* resp = reply.get_flatbuffer<MatchingSearchJoinRoomInfo>();
if (reply.is_error())
return error_and_disconnect("Malformed reply to SearchJoinRoomGUI command");
event_data edata(np_memory.allocate(MAX_SceNpMatchingSearchJoinRoomInfo_SIZE), sizeof(SceNpMatchingSearchJoinRoomInfo), MAX_SceNpMatchingSearchJoinRoomInfo_SIZE);
auto* room_info = reinterpret_cast<SceNpMatchingSearchJoinRoomInfo*>(edata.data());
MatchingSearchJoinRoomInfo_to_SceNpMatchingSearchJoinRoomInfo(edata, resp, room_info);
np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_SceNpMatchingSearchJoinRoomInfo(room_info);
gui_cache.add_room(room_info->room_status.id);
for (auto cur_member = room_info->room_status.members; cur_member; cur_member = cur_member->next)
{
gui_cache.add_member(room_info->room_status.id, cur_member.get_ptr(), true);
}
set_gui_result(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, std::move(edata));
ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_SEARCH_JOIN, 0);
gui_epilog(ctx);
return true;
}
// Local cache requests
error_code np_handler::get_room_member_list_local_gui(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
{
auto ctx = get_matching_context(ctx_id);
if (!ctx)
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
if (!room_id)
return SCE_NP_MATCHING_ERROR_ROOM_NOT_FOUND;
if (!buf)
{
error_code room_size = gui_cache.get_room_member_list(*room_id, 0, {});
if (room_size < 0)
return room_size;
*buflen = room_size;
return CELL_OK;
}
return gui_cache.get_room_member_list(*room_id, *buflen, buf);
}
} // namespace np

View File

@ -35,7 +35,7 @@ namespace extra_nps
const auto ptr = +bin->ptr;
const u32 size = bin->size;
sceNp2.warning("Id: %d, Size: %d, ptr: 0x%x", bin->id, size, ptr);
sceNp2.warning("Id: %d, Size: %d, ptr: *0x%x", bin->id, size, ptr);
if (ptr && size)
{
@ -438,4 +438,121 @@ namespace extra_nps
sceNp.warning("recordDate: %d", data->recordDate.tick);
}
void print_SceNpMatchingAttr(const SceNpMatchingAttr* data)
{
sceNp.warning("SceNpMatchingAttr:");
sceNp.warning("next: 0x%x", data->next);
sceNp.warning("type: %d", data->type);
sceNp.warning("id: %d", data->id);
if (data->type == SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN || data->type == SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN)
{
sceNp.warning("ptr: *0x%x", data->value.data.ptr);
sceNp.warning("size: %d", data->value.data.size);
sceNp.warning("data:\n%s", fmt::buf_to_hexstring(static_cast<u8 *>(data->value.data.ptr.get_ptr()), data->value.data.size));
}
else
{
sceNp.warning("num: %d(0x%x)", data->value.num, data->value.num);
}
}
void print_SceNpMatchingSearchCondition(const SceNpMatchingSearchCondition* data)
{
sceNp.warning("SceNpMatchingSearchCondition:");
sceNp.warning("target_attr_type: %d", data->target_attr_type);
sceNp.warning("target_attr_id: %d", data->target_attr_id);
sceNp.warning("comp_type: %d", data->comp_type);
sceNp.warning("comp_op: %d", data->comp_op);
sceNp.warning("next: 0x%x", data->next);
print_SceNpMatchingAttr(&data->compared);
}
void print_SceNpMatchingRoom(const SceNpMatchingRoom* data)
{
sceNp.warning("SceNpMatchingRoom:");
sceNp.warning("next: 0x%x", data->next);
print_SceNpRoomId(data->id);
for (auto it = data->attr; it; it = it->next)
{
print_SceNpMatchingAttr(it.get_ptr());
}
}
void print_SceNpMatchingRoomList(const SceNpMatchingRoomList* data)
{
sceNp.warning("SceNpMatchingRoomList:");
sceNp.warning("lobbyid.opt: %s", fmt::buf_to_hexstring(data->lobbyid.opt, sizeof(data->lobbyid.opt), sizeof(data->lobbyid.opt)));
sceNp.warning("start: %d", data->range.start);
sceNp.warning("results: %d", data->range.results);
sceNp.warning("total: %d", data->range.total);
for (auto it = data->head; it; it = it->next)
{
print_SceNpMatchingRoom(it.get_ptr());
}
}
void print_SceNpUserInfo(const SceNpUserInfo* data)
{
sceNp.warning("userId: %s", data->userId.handle.data);
sceNp.warning("name: %s", data->name.data);
sceNp.warning("icon: %s", data->icon.data);
}
void print_SceNpRoomId(const SceNpRoomId& room_id)
{
sceNp.warning("room_id: %s", fmt::buf_to_hexstring(room_id.opt, sizeof(room_id.opt), sizeof(room_id.opt)));
}
void print_SceNpMatchingRoomMember(const SceNpMatchingRoomMember* data)
{
sceNp.warning("SceNpMatchingRoomMember:");
sceNp.warning("next: 0x%x", data->next);
sceNp.warning("owner: %d", data->owner);
print_SceNpUserInfo(&data->user_info);
}
void print_SceNpMatchingRoomStatus(const SceNpMatchingRoomStatus* data)
{
sceNp.warning("SceNpMatchingRoomStatus:");
print_SceNpRoomId(data->id);
sceNp.warning("members: 0x%x", data->members);
sceNp.warning("num: %d", data->num);
for (auto it = data->members; it; it = it->next)
{
print_SceNpMatchingRoomMember(it.get_ptr());
}
sceNp.warning("kick_actor: 0x%x", data->kick_actor);
if (data->kick_actor)
{
sceNp.warning("kick_actor: %s", data->kick_actor->handle.data);
}
sceNp.warning("opt: 0x%x", data->kick_actor);
sceNp.warning("opt_len: %d", data->opt_len);
}
void print_SceNpMatchingJoinedRoomInfo(const SceNpMatchingJoinedRoomInfo* data)
{
sceNp.warning("SceNpMatchingJoinedRoomInfo:");
sceNp.warning("lobbyid.opt: %s", fmt::buf_to_hexstring(data->lobbyid.opt, sizeof(data->lobbyid.opt), sizeof(data->lobbyid.opt)));
print_SceNpMatchingRoomStatus(&data->room_status);
}
void print_SceNpMatchingSearchJoinRoomInfo(const SceNpMatchingSearchJoinRoomInfo* data)
{
sceNp.warning("SceNpMatchingSearchJoinRoomInfo:");
sceNp.warning("lobbyid.opt: %s", fmt::buf_to_hexstring(data->lobbyid.opt, sizeof(data->lobbyid.opt), sizeof(data->lobbyid.opt)));
print_SceNpMatchingRoomStatus(&data->room_status);
for (auto it = data->attr; it; it = it->next)
{
print_SceNpMatchingAttr(it.get_ptr());
}
}
} // namespace extra_nps

View File

@ -30,4 +30,13 @@ namespace extra_nps
void print_SceNpScoreRankData(const SceNpScoreRankData* data);
void print_SceNpScoreRankData_deprecated(const SceNpScoreRankData_deprecated* data);
void print_SceNpRoomId(const SceNpRoomId& room_id);
void print_SceNpMatchingAttr(const SceNpMatchingAttr* data);
void print_SceNpMatchingSearchCondition(const SceNpMatchingSearchCondition* data);
void print_SceNpMatchingRoom(const SceNpMatchingRoom* data);
void print_SceNpMatchingRoomList(const SceNpMatchingRoomList* data);
void print_SceNpMatchingRoomStatus(const SceNpMatchingRoomStatus* data);
void print_SceNpMatchingJoinedRoomInfo(const SceNpMatchingJoinedRoomInfo* data);
void print_SceNpMatchingSearchJoinRoomInfo(const SceNpMatchingSearchJoinRoomInfo* data);
} // namespace extra_nps

View File

@ -84,7 +84,7 @@ namespace rpcn
rpcn_log.notice("online: %s, pr_com_id: %s, pr_title: %s, pr_status: %s, pr_comment: %s, pr_data: %s", online ? "true" : "false", pr_com_id.data, pr_title, pr_status, pr_comment, fmt::buf_to_hexstring(pr_data.data(), pr_data.size()));
}
constexpr u32 RPCN_PROTOCOL_VERSION = 24;
constexpr u32 RPCN_PROTOCOL_VERSION = 25;
constexpr usz RPCN_HEADER_SIZE = 15;
bool is_error(ErrorType err)
@ -1305,7 +1305,7 @@ namespace rpcn
bool rpcn_client::get_server_list(u32 req_id, const SceNpCommunicationId& communication_id, std::vector<u16>& server_list)
{
std::vector<u8> data(COMMUNICATION_ID_SIZE), reply_data;
memcpy(data.data(), communication_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(communication_id, data);
if (!forge_send_reply(CommandType::GetServerList, req_id, data, reply_data))
{
@ -1368,7 +1368,7 @@ namespace rpcn
bool rpcn_client::get_world_list(u32 req_id, const SceNpCommunicationId& communication_id, u16 server_id)
{
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u16));
memcpy(data.data(), communication_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(communication_id, data);
reinterpret_cast<le_t<u16>&>(data[COMMUNICATION_ID_SIZE]) = server_id;
return forge_send(CommandType::GetWorldList, req_id, data);
@ -1795,7 +1795,7 @@ namespace rpcn
{
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u64));
memcpy(data.data(), communication_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(communication_id, data);
write_to_ptr<le_t<u64>>(data, COMMUNICATION_ID_SIZE, room_id);
return forge_send(CommandType::PingRoomOwner, req_id, data);
@ -1889,7 +1889,7 @@ namespace rpcn
bool rpcn_client::get_board_infos(u32 req_id, const SceNpCommunicationId& communication_id, SceNpScoreBoardId board_id)
{
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u32));
memcpy(data.data(), communication_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(communication_id, data);
write_to_ptr<le_t<u32>>(data, COMMUNICATION_ID_SIZE, board_id);
return forge_send(CommandType::GetBoardInfos, req_id, data);
@ -1951,7 +1951,7 @@ namespace rpcn
const usz bufsize = builder.GetSize();
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize + sizeof(u32) + score_data.size());
memcpy(data.data(), communication_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(communication_id, data);
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE]) = static_cast<u32>(bufsize);
memcpy(data.data() + COMMUNICATION_ID_SIZE + sizeof(u32), buf, bufsize);
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize]) = static_cast<u32>(score_data.size());
@ -2192,19 +2192,290 @@ namespace rpcn
return forge_request_with_com_id(builder, pr_com_id, CommandType::SetPresence, rpcn_request_counter.fetch_add(1));
}
bool rpcn_client::createjoin_room_gui(u32 req_id, const SceNpCommunicationId& communication_id, const SceNpMatchingAttr* attr_list)
{
flatbuffers::FlatBufferBuilder builder(1024);
u32 total_slots = 0;
u32 private_slots = 0;
bool privilege_grant = false;
bool stealth = false;
std::vector<flatbuffers::Offset<MatchingAttr>> vec_attrs;
for (const SceNpMatchingAttr* cur_attr = attr_list; cur_attr != nullptr; cur_attr = cur_attr->next ? cur_attr->next.get_ptr() : nullptr)
{
switch (cur_attr->type)
{
case SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM:
{
switch (cur_attr->id)
{
case SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT:
total_slots = cur_attr->value.num;
break;
case SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVATE_SLOT:
private_slots = cur_attr->value.num;
break;
case SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE:
ensure(cur_attr->value.num == SCE_NP_MATCHING_ROOM_PRIVILEGE_TYPE_NO_AUTO_GRANT || cur_attr->value.num == SCE_NP_MATCHING_ROOM_PRIVILEGE_TYPE_AUTO_GRANT, "Invalid SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE value");
privilege_grant = (cur_attr->value.num == SCE_NP_MATCHING_ROOM_PRIVILEGE_TYPE_AUTO_GRANT);
break;
case SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG:
ensure(cur_attr->value.num == SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN || cur_attr->value.num == SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH, "Invalid SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG value");
stealth = (cur_attr->value.num == SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH);
break;
default:
fmt::throw_exception("Invalid basic num attribute id");
break;
}
break;
}
case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN:
{
ensure(cur_attr->id >= 1u && cur_attr->id <= 16u, "Invalid game bin attribute id");
ensure(cur_attr->value.data.size <= 64u || ((cur_attr->id == 1u || cur_attr->id == 2u) && cur_attr->value.data.size <= 256u), "Invalid game bin size");
const std::vector<u8> vec_data(static_cast<const u8*>(cur_attr->value.data.ptr.get_ptr()), static_cast<const u8*>(cur_attr->value.data.ptr.get_ptr()) + cur_attr->value.data.size);
auto attr = CreateMatchingAttrDirect(builder, cur_attr->type, cur_attr->id, 0, &vec_data);
vec_attrs.push_back(attr);
break;
}
case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM:
{
ensure(cur_attr->id >= 1u && cur_attr->id <= 16u, "Invalid game num attribute id");
auto attr = CreateMatchingAttrDirect(builder, cur_attr->type, cur_attr->id, cur_attr->value.num, nullptr);
vec_attrs.push_back(attr);
break;
}
default:
fmt::throw_exception("Invalid attribute type");
}
}
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MatchingAttr>>> final_attrs_vec;
if (!vec_attrs.empty())
{
final_attrs_vec = builder.CreateVector(vec_attrs);
}
auto req_finished = CreateCreateRoomGUIRequest(builder, total_slots, private_slots, privilege_grant, stealth, final_attrs_vec);
builder.Finish(req_finished);
return forge_request_with_com_id(builder, communication_id, CommandType::CreateRoomGUI, req_id);
}
bool rpcn_client::join_room_gui(u32 req_id, const SceNpRoomId& room_id)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
auto req_finished = CreateMatchingGuiRoomIdDirect(builder, &vec_room_id);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::JoinRoomGUI, req_id);
}
bool rpcn_client::leave_room_gui(u32 req_id, const SceNpRoomId& room_id)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
auto req_finished = CreateMatchingGuiRoomIdDirect(builder, &vec_room_id);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::LeaveRoomGUI, req_id);
}
bool rpcn_client::get_room_list_gui(u32 req_id, const SceNpCommunicationId& communication_id, const SceNpMatchingReqRange* range, vm::ptr<SceNpMatchingSearchCondition> cond, vm::ptr<SceNpMatchingAttr> attr)
{
flatbuffers::FlatBufferBuilder builder(1024);
const s32 range_start = range->start;
const u32 range_max = range->max;
std::vector<flatbuffers::Offset<MatchingSearchCondition>> vec_conds;
std::vector<flatbuffers::Offset<MatchingAttr>> vec_attrs;
for (auto cur_cond = cond; cur_cond; cur_cond = cur_cond->next)
{
auto fb_cond = CreateMatchingSearchCondition(builder, cur_cond->target_attr_type, cur_cond->target_attr_id, cur_cond->comp_op, cur_cond->compared.value.num);
vec_conds.push_back(fb_cond);
}
for (auto cur_attr = attr; cur_attr; cur_attr = cur_attr->next)
{
auto fb_attr = CreateMatchingAttr(builder, cur_attr->type, cur_attr->id);
vec_attrs.push_back(fb_attr);
}
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MatchingSearchCondition>>> final_conds_vec;
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MatchingAttr>>> final_attrs_vec;
if (!vec_conds.empty())
{
final_conds_vec = builder.CreateVector(vec_conds);
}
if (!vec_attrs.empty())
{
final_attrs_vec = builder.CreateVector(vec_attrs);
}
auto req_finished = CreateGetRoomListGUIRequest(builder, range_start, range_max, final_conds_vec, final_attrs_vec);
builder.Finish(req_finished);
return forge_request_with_com_id(builder, communication_id, CommandType::GetRoomListGUI, req_id);
}
bool rpcn_client::set_room_search_flag_gui(u32 req_id, const SceNpRoomId& room_id, bool stealth)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
auto req_finished = CreateSetRoomSearchFlagGUIDirect(builder, &vec_room_id, stealth);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::SetRoomSearchFlagGUI, req_id);
}
bool rpcn_client::get_room_search_flag_gui(u32 req_id, const SceNpRoomId& room_id)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
auto req_finished = CreateMatchingGuiRoomIdDirect(builder, &vec_room_id);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::GetRoomSearchFlagGUI, req_id);
}
bool rpcn_client::set_room_info_gui(u32 req_id, const SceNpRoomId& room_id, vm::ptr<SceNpMatchingAttr> attrs)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
std::vector<flatbuffers::Offset<MatchingAttr>> vec_attrs;
for (auto cur_attr = attrs; cur_attr; cur_attr = cur_attr->next)
{
u32 num = 0;
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> fb_vec_data = 0;
switch (cur_attr->type)
{
case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN:
{
const std::vector<u8> vec_data(static_cast<const u8*>(cur_attr->value.data.ptr.get_ptr()), static_cast<const u8*>(cur_attr->value.data.ptr.get_ptr()) + cur_attr->value.data.size);
fb_vec_data = builder.CreateVector(vec_data);
break;
}
case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM:
{
num = cur_attr->value.num;
break;
}
default:
{
fmt::throw_exception("Invalid attr type reached set_room_info_gui");
break;
}
}
auto fb_attr = CreateMatchingAttr(builder, cur_attr->type, cur_attr->id, num, fb_vec_data);
vec_attrs.push_back(fb_attr);
}
auto req_finished = CreateMatchingRoomDirect(builder, &vec_room_id, &vec_attrs);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::SetRoomInfoGUI, req_id);
}
bool rpcn_client::get_room_info_gui(u32 req_id, const SceNpRoomId& room_id, vm::ptr<SceNpMatchingAttr> attrs)
{
flatbuffers::FlatBufferBuilder builder(1024);
const std::vector<u8> vec_room_id(room_id.opt, room_id.opt + sizeof(room_id.opt));
std::vector<flatbuffers::Offset<MatchingAttr>> vec_attrs;
for (auto cur_attr = attrs; cur_attr; cur_attr = cur_attr->next)
{
auto fb_attr = CreateMatchingAttr(builder, cur_attr->type, cur_attr->id);
vec_attrs.push_back(fb_attr);
}
auto req_finished = CreateMatchingRoomDirect(builder, &vec_room_id, &vec_attrs);
builder.Finish(req_finished);
return forge_request_with_data(builder, CommandType::GetRoomInfoGUI, req_id);
}
bool rpcn_client::quickmatch_gui(u32 req_id, const SceNpCommunicationId& com_id, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num)
{
flatbuffers::FlatBufferBuilder builder(1024);
std::vector<flatbuffers::Offset<MatchingSearchCondition>> vec_conds;
for (auto cur_cond = cond; cur_cond; cur_cond = cur_cond->next)
{
auto fb_cond = CreateMatchingSearchCondition(builder, cur_cond->target_attr_type, cur_cond->target_attr_id, cur_cond->comp_op, cur_cond->compared.value.num);
vec_conds.push_back(fb_cond);
}
auto req_finished = CreateQuickMatchGUIRequestDirect(builder, &vec_conds, available_num);
builder.Finish(req_finished);
return forge_request_with_com_id(builder, com_id, CommandType::QuickMatchGUI, req_id);
}
bool rpcn_client::searchjoin_gui(u32 req_id, const SceNpCommunicationId& com_id, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr)
{
flatbuffers::FlatBufferBuilder builder(1024);
std::vector<flatbuffers::Offset<MatchingSearchCondition>> vec_conds;
std::vector<flatbuffers::Offset<MatchingAttr>> vec_attrs;
for (auto cur_cond = cond; cur_cond; cur_cond = cur_cond->next)
{
auto fb_cond = CreateMatchingSearchCondition(builder, cur_cond->target_attr_type, cur_cond->target_attr_id, cur_cond->comp_op, cur_cond->compared.value.num);
vec_conds.push_back(fb_cond);
}
for (auto cur_attr = attr; cur_attr; cur_attr = cur_attr->next)
{
auto fb_attr = CreateMatchingAttr(builder, cur_attr->type, cur_attr->id);
vec_attrs.push_back(fb_attr);
}
auto req_finished = CreateSearchJoinRoomGUIRequestDirect(builder, vec_conds.empty() ? nullptr : &vec_conds, vec_attrs.empty() ? nullptr : &vec_attrs);
builder.Finish(req_finished);
return forge_request_with_com_id(builder, com_id, CommandType::SearchJoinRoomGUI, req_id);
}
void rpcn_client::write_communication_id(const SceNpCommunicationId& com_id, std::vector<u8>& data)
{
ensure(com_id.data[9] == 0 && com_id.num <= 99, "rpcn_client::write_communication_id: Invalid SceNpCommunicationId");
const std::string com_id_str = np::communication_id_to_string(com_id);
ensure(com_id_str.size() == 12, "rpcn_client::write_communication_id: Error formatting SceNpCommunicationId");
memcpy(data.data(), com_id_str.data(), COMMUNICATION_ID_SIZE);
}
bool rpcn_client::forge_request_with_com_id(const flatbuffers::FlatBufferBuilder& builder, const SceNpCommunicationId& com_id, CommandType command, u64 packet_id)
{
const u8* buf = builder.GetBufferPointer();
const usz bufsize = builder.GetSize();
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize);
memcpy(data.data(), com_id.data, COMMUNICATION_ID_SIZE);
rpcn_client::write_communication_id(com_id, data);
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE]) = static_cast<u32>(bufsize);
memcpy(data.data() + COMMUNICATION_ID_SIZE + sizeof(u32), buf, bufsize);
return forge_send(command, packet_id, data);
}
bool rpcn_client::forge_request_with_data(const flatbuffers::FlatBufferBuilder& builder, CommandType command, u64 packet_id)
{
const u8* buf = builder.GetBufferPointer();
const usz bufsize = builder.GetSize();
std::vector<u8> data(sizeof(u32) + bufsize);
reinterpret_cast<le_t<u32>&>(data[0]) = static_cast<u32>(bufsize);
memcpy(data.data() + sizeof(u32), buf, bufsize);
return forge_send(command, packet_id, data);
}
std::vector<u8> rpcn_client::forge_request(u16 command, u64 packet_id, const std::vector<u8>& data) const
{
const usz packet_size = data.size() + RPCN_HEADER_SIZE;

View File

@ -39,7 +39,12 @@
#pragma GCC diagnostic pop
#endif
constexpr usz COMMUNICATION_ID_SIZE = 9;
// COMID is sent as 9 chars - + '_' + 2 digits
constexpr usz COMMUNICATION_ID_COMID_COMPONENT_SIZE = 9;
constexpr usz COMMUNICATION_ID_SUBID_COMPONENT_SIZE = 2;
constexpr usz COMMUNICATION_ID_SIZE = COMMUNICATION_ID_COMID_COMPONENT_SIZE + COMMUNICATION_ID_SUBID_COMPONENT_SIZE + 1;
class vec_stream
{
@ -110,7 +115,17 @@ public:
}
SceNpCommunicationId com_id{};
std::memcpy(&com_id.data[0], &vec[i], COMMUNICATION_ID_SIZE);
std::memcpy(&com_id.data[0], &vec[i], COMMUNICATION_ID_COMID_COMPONENT_SIZE);
const std::string sub_id(reinterpret_cast<const char*>(&vec[i + COMMUNICATION_ID_COMID_COMPONENT_SIZE + 1]), COMMUNICATION_ID_SUBID_COMPONENT_SIZE);
const unsigned long result_num = std::strtoul(sub_id.c_str(), nullptr, 10);
if (result_num > 99)
{
error = true;
return {};
}
com_id.num = static_cast<u8>(result_num);
i += COMMUNICATION_ID_SIZE;
return com_id;
}
@ -223,6 +238,16 @@ namespace rpcn
TusDeleteMultiSlotData,
ClearPresence,
SetPresence,
CreateRoomGUI,
JoinRoomGUI,
LeaveRoomGUI,
GetRoomListGUI,
SetRoomSearchFlagGUI,
GetRoomSearchFlagGUI,
SetRoomInfoGUI,
GetRoomInfoGUI,
QuickMatchGUI,
SearchJoinRoomGUI,
};
enum NotificationType : u16
@ -242,6 +267,12 @@ namespace rpcn
MessageReceived,
FriendPresenceChanged,
SignalingInfo,
MemberJoinedRoomGUI,
MemberLeftRoomGUI,
RoomDisappearedGUI,
RoomOwnerChangedGUI,
UserKickedGUI,
QuickMatchCompleteGUI,
};
enum class rpcn_state
@ -485,6 +516,16 @@ namespace rpcn
bool tus_get_friends_data_status(u32 req_id, SceNpCommunicationId& communication_id, SceNpTusSlotId slotId, bool includeSelf, s32 sortType, s32 arrayNum);
bool tus_delete_multislot_data(u32 req_id, SceNpCommunicationId& communication_id, const SceNpOnlineId& targetNpId, vm::cptr<SceNpTusSlotId> slotIdArray, s32 arrayNum, bool vuser);
bool send_presence(const SceNpCommunicationId& pr_com_id, const std::string& pr_title, const std::string& pr_status, const std::string& pr_comment, const std::vector<u8>& pr_data);
bool createjoin_room_gui(u32 req_id, const SceNpCommunicationId& communication_id, const SceNpMatchingAttr* attr_list);
bool join_room_gui(u32 req_id, const SceNpRoomId& room_id);
bool leave_room_gui(u32 req_id, const SceNpRoomId& room_id);
bool get_room_list_gui(u32 req_id, const SceNpCommunicationId& communication_id, const SceNpMatchingReqRange* range, vm::ptr<SceNpMatchingSearchCondition> cond, vm::ptr<SceNpMatchingAttr> attr);
bool set_room_search_flag_gui(u32 req_id, const SceNpRoomId& room_id, bool stealth);
bool get_room_search_flag_gui(u32 req_id, const SceNpRoomId& room_id);
bool set_room_info_gui(u32 req_id, const SceNpRoomId& room_id, vm::ptr<SceNpMatchingAttr> attrs);
bool get_room_info_gui(u32 req_id, const SceNpRoomId& room_id, vm::ptr<SceNpMatchingAttr> attrs);
bool quickmatch_gui(u32 req_id, const SceNpCommunicationId& com_id, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num);
bool searchjoin_gui(u32 req_id, const SceNpCommunicationId& com_id, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr);
const std::string& get_online_name() const;
const std::string& get_avatar_url() const;
@ -497,9 +538,12 @@ namespace rpcn
private:
bool get_reply(u64 expected_id, std::vector<u8>& data);
static void write_communication_id(const SceNpCommunicationId& com_id, std::vector<u8>& data);
std::vector<u8> forge_request(u16 command, u64 packet_id, const std::vector<u8>& data) const;
bool forge_send(u16 command, u64 packet_id, const std::vector<u8>& data);
bool forge_request_with_com_id(const flatbuffers::FlatBufferBuilder& builder, const SceNpCommunicationId& com_id, CommandType command, u64 packet_id);
bool forge_request_with_data(const flatbuffers::FlatBufferBuilder& builder, CommandType command, u64 packet_id);
bool forge_send_reply(u16 command, u64 packet_id, const std::vector<u8>& data, std::vector<u8>& reply_data);
bool error_and_disconnect(const std::string& error_mgs);

View File

@ -147,8 +147,10 @@
<ClCompile Include="Emu\system_config.cpp" />
<ClCompile Include="Emu\NP\fb_helpers.cpp" />
<ClCompile Include="Emu\NP\np_cache.cpp" />
<ClCompile Include="Emu\NP\np_gui_cache.cpp" />
<ClCompile Include="Emu\NP\np_contexts.cpp" />
<ClCompile Include="Emu\NP\np_dnshook.cpp" />
<ClCompile Include="Emu\NP\np_requests_gui.cpp" />
<ClCompile Include="Emu\NP\np_handler.cpp" />
<ClCompile Include="Emu\NP\np_helpers.cpp" />
<ClCompile Include="Emu\NP\np_notifications.cpp" />

View File

@ -978,12 +978,18 @@
<ClCompile Include="Emu\NP\np_cache.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\np_gui_cache.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\np_contexts.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\np_dnshook.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\np_requests_gui.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\np_handler.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>