mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-03 15:20:27 +01:00
Simplify signaling by making Matching2 a layer over normal signaling. Implements UPNP port forwarding Implement sceNpMatching2AbortRequest Fix reported bw in sceNpUtil Hack for Fat Princess binding udp on 3658 Reenable CB for sceNpBasicAddPlayersHistoryAsync Misc fixes
1135 lines
37 KiB
C++
1135 lines
37 KiB
C++
#include "stdafx.h"
|
|
#include "Emu/Cell/PPUModule.h"
|
|
#include "Emu/Cell/lv2/sys_sync.h"
|
|
#include "Emu/system_config.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"
|
|
|
|
LOG_CHANNEL(rpcn_log, "rpcn");
|
|
|
|
namespace np
|
|
{
|
|
std::vector<SceNpMatching2ServerId> np_handler::get_match2_server_list(SceNpMatching2ContextId ctx_id)
|
|
{
|
|
std::vector<SceNpMatching2ServerId> server_list{};
|
|
|
|
if (g_cfg.net.psn_status != np_psn_status::psn_rpcn)
|
|
{
|
|
return server_list;
|
|
}
|
|
|
|
if (!rpcn->get_server_list(get_req_id(0), get_match2_context(ctx_id)->communicationId, server_list))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return server_list;
|
|
}
|
|
|
|
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);
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetServerInfo, sizeof(SceNpMatching2GetServerInfoResponse));
|
|
SceNpMatching2GetServerInfoResponse* serv_info = reinterpret_cast<SceNpMatching2GetServerInfoResponse*>(edata.data());
|
|
serv_info->server.serverId = server_id;
|
|
serv_info->server.status = SCE_NP_MATCHING2_SERVER_STATUS_AVAILABLE;
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
const auto cb_info_opt = take_pending_request(req_id);
|
|
ensure(cb_info_opt);
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return req_id;
|
|
}
|
|
|
|
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 auto cb_info_opt = take_pending_request(req_id);
|
|
ensure(cb_info_opt);
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return req_id;
|
|
}
|
|
|
|
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 auto cb_info_opt = take_pending_request(req_id);
|
|
ensure(cb_info_opt);
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return req_id;
|
|
}
|
|
|
|
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);
|
|
|
|
if (!rpcn->get_world_list(req_id, get_match2_context(ctx_id)->communicationId, server_id))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_get_world_list(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
std::vector<u32> world_list;
|
|
u32 num_worlds = reply.get<u32>();
|
|
for (u32 i = 0; i < num_worlds; i++)
|
|
{
|
|
world_list.push_back(reply.get<u32>());
|
|
}
|
|
|
|
if (reply.is_error())
|
|
{
|
|
return error_and_disconnect("Malformed reply to GetWorldList command");
|
|
}
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetWorldInfoList, sizeof(SceNpMatching2GetWorldInfoListResponse));
|
|
auto* world_info = reinterpret_cast<SceNpMatching2GetWorldInfoListResponse*>(edata.data());
|
|
world_info->worldNum = world_list.size();
|
|
|
|
if (!world_list.empty())
|
|
{
|
|
auto* worlds = edata.allocate<SceNpMatching2World>(sizeof(SceNpMatching2World) * world_list.size(), world_info->world);
|
|
for (usz i = 0; i < world_list.size(); i++)
|
|
{
|
|
worlds[i].worldId = world_list[i];
|
|
}
|
|
}
|
|
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_createjoinroom(req);
|
|
|
|
if (!rpcn->createjoin_room(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
// More elegant solution would be to send back password with creation reply
|
|
cached_cj_password = req->roomPassword ? std::optional<SceNpMatching2SessionPassword>{*req->roomPassword} : std::nullopt;
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_create_join_room(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to CreateRoom command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_CreateJoinRoom, sizeof(SceNpMatching2CreateJoinRoomResponse));
|
|
auto* room_resp = reinterpret_cast<SceNpMatching2CreateJoinRoomResponse*>(edata.data());
|
|
auto* room_info = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal);
|
|
RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
np_cache.insert_room(room_info);
|
|
np_cache.update_password(room_resp->roomDataInternal->roomId, cached_cj_password);
|
|
|
|
extra_nps::print_create_room_resp(room_resp);
|
|
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_joinroom(req);
|
|
|
|
if (!rpcn->join_room(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_join_room(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
s32 error_code = 0;
|
|
|
|
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
|
|
{
|
|
switch (reply_data[0])
|
|
{
|
|
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
|
|
case rpcn::ErrorType::RoomAlreadyJoined: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED; break;
|
|
case rpcn::ErrorType::RoomFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL; break;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
if (error_code != 0)
|
|
{
|
|
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
|
|
return true;
|
|
}
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to JoinRoom command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_JoinRoom, sizeof(SceNpMatching2JoinRoomResponse));
|
|
auto* room_resp = reinterpret_cast<SceNpMatching2JoinRoomResponse*>(edata.data());
|
|
auto* room_info = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal);
|
|
RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
np_cache.insert_room(room_info);
|
|
|
|
extra_nps::print_room_data_internal(room_info);
|
|
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
if (!rpcn->leave_room(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_leave_room(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
u64 room_id = reply.get<u64>();
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to LeaveRoom command");
|
|
|
|
// Disconnect all users from that room
|
|
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
|
|
sigh.disconnect_sig2_users(room_id);
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_search_room(req);
|
|
|
|
if (!rpcn->search_room(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_search_room(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
auto* resp = reply.get_flatbuffer<SearchRoomResponse>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to SearchRoom command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_SearchRoom, sizeof(SceNpMatching2SearchRoomResponse));
|
|
auto* search_resp = reinterpret_cast<SceNpMatching2SearchRoomResponse*>(edata.data());
|
|
SearchRoomResponse_to_SceNpMatching2SearchRoomResponse(edata, resp, search_resp);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
extra_nps::print_search_room_resp(search_resp);
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_get_roomdata_external_list_req(req);
|
|
|
|
if (!rpcn->get_roomdata_external_list(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_get_roomdata_external_list(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
auto* resp = reply.get_flatbuffer<GetRoomDataExternalListResponse>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to GetRoomDataExternalList command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetRoomDataExternalList, sizeof(SceNpMatching2GetRoomDataExternalListResponse));
|
|
auto* sce_get_room_ext_resp = reinterpret_cast<SceNpMatching2GetRoomDataExternalListResponse*>(edata.data());
|
|
GetRoomDataExternalListResponse_to_SceNpMatching2GetRoomDataExternalListResponse(edata, resp, sce_get_room_ext_resp);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
extra_nps::print_get_roomdata_external_list_resp(sce_get_room_ext_resp);
|
|
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_set_roomdata_ext_req(req);
|
|
|
|
if (!rpcn->set_roomdata_external(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_set_roomdata_external(u32 req_id, std::vector<u8>& /*reply_data*/)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
if (!rpcn->get_roomdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_get_roomdata_internal(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
auto* resp = reply.get_flatbuffer<RoomDataInternal>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to GetRoomDataInternal command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetRoomDataInternal, sizeof(SceNpMatching2GetRoomDataInternalResponse));
|
|
auto* room_resp = reinterpret_cast<SceNpMatching2GetRoomDataInternalResponse*>(edata.data());
|
|
auto* room_info = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal);
|
|
RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
|
|
np_cache.insert_room(room_info);
|
|
|
|
extra_nps::print_room_data_internal(room_info);
|
|
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
// TODO: extra_nps::print_set_roomdata_req(req);
|
|
|
|
extra_nps::print_set_roomdata_int_req(req);
|
|
|
|
if (!rpcn->set_roomdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_set_roomdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
extra_nps::print_set_roommemberdata_int_req(req);
|
|
|
|
if (!rpcn->set_roommemberdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_set_roommemberdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
if (!rpcn->ping_room_owner(req_id, get_match2_context(ctx_id)->communicationId, req->roomId))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_get_ping_info(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
auto* resp = reply.get_flatbuffer<GetPingInfoResponse>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to PingRoomOwner command");
|
|
|
|
u32 event_key = get_event_key();
|
|
|
|
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_SignalingGetPingInfo, sizeof(SceNpMatching2SignalingGetPingInfoResponse));
|
|
auto* final_ping_resp = reinterpret_cast<SceNpMatching2SignalingGetPingInfoResponse*>(edata.data());
|
|
GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(resp, final_ping_resp);
|
|
np_memory.shrink_allocation(edata.addr(), edata.size());
|
|
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
if (!rpcn->send_room_message(req_id, get_match2_context(ctx_id)->communicationId, req))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return req_id;
|
|
}
|
|
|
|
bool np_handler::reply_send_room_message(u32 req_id, std::vector<u8>& /*reply_data*/)
|
|
{
|
|
auto cb_info_opt = take_pending_request(req_id);
|
|
|
|
if (!cb_info_opt)
|
|
return true;
|
|
|
|
cb_info_opt->queue_callback(req_id, 0, 0, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
void np_handler::req_sign_infos(const std::string& npid, u32 conn_id)
|
|
{
|
|
u32 req_id = get_req_id(0x3333);
|
|
{
|
|
std::lock_guard lock(mutex_pending_sign_infos_requests);
|
|
pending_sign_infos_requests[req_id] = conn_id;
|
|
}
|
|
|
|
if (!rpcn->req_sign_infos(req_id, npid))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
}
|
|
|
|
bool np_handler::reply_req_sign_infos(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
u32 conn_id;
|
|
{
|
|
std::lock_guard lock(mutex_pending_sign_infos_requests);
|
|
conn_id = ::at32(pending_sign_infos_requests, req_id);
|
|
pending_sign_infos_requests.erase(req_id);
|
|
}
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
u32 addr = reply.get<u32>();
|
|
u16 port = reply.get<u16>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to RequestSignalingInfos command");
|
|
|
|
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
|
|
sigh.start_sig(conn_id, addr, port);
|
|
|
|
return true;
|
|
}
|
|
|
|
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(0x3333);
|
|
|
|
std::string service_id_str(service_id);
|
|
|
|
std::vector<u8> cookie_vec;
|
|
if (cookie && cookie_size)
|
|
{
|
|
cookie_vec.assign(cookie, cookie + cookie_size);
|
|
}
|
|
|
|
if (!rpcn->req_ticket(req_id, service_id_str, cookie_vec))
|
|
{
|
|
rpcn_log.error("Disconnecting from RPCN!");
|
|
is_psn_active = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
const ticket& np_handler::get_ticket() const
|
|
{
|
|
return current_ticket;
|
|
}
|
|
|
|
bool np_handler::reply_req_ticket([[maybe_unused]] u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
vec_stream reply(reply_data, 1);
|
|
auto ticket_raw = reply.get_rawdata();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to RequestTicket command");
|
|
|
|
current_ticket = ticket(std::move(ticket_raw));
|
|
auto ticket_size = static_cast<s32>(current_ticket.size());
|
|
|
|
if (manager_cb)
|
|
{
|
|
sysutil_register_cb([manager_cb = this->manager_cb, ticket_size, manager_cb_arg = this->manager_cb_arg](ppu_thread& cb_ppu) -> s32
|
|
{
|
|
manager_cb(cb_ppu, SCE_NP_MANAGER_EVENT_GOT_TICKET, ticket_size, manager_cb_arg);
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void np_handler::score_async_handler(std::unique_lock<shared_mutex> lock, const std::shared_ptr<score_transaction_ctx>& trans_ctx, u32 req_id, bool async)
|
|
{
|
|
auto worker_function = [trans_ctx = trans_ctx, req_id, this](std::unique_lock<shared_mutex> lock)
|
|
{
|
|
auto res = trans_ctx->wake_cond.wait_for(lock, std::chrono::microseconds(trans_ctx->timeout));
|
|
{
|
|
std::lock_guard lock_threads(this->mutex_score_transactions);
|
|
this->score_transactions.erase(req_id);
|
|
}
|
|
|
|
if (res == std::cv_status::timeout)
|
|
{
|
|
trans_ctx->result = SCE_NP_COMMUNITY_ERROR_TIMEOUT;
|
|
return;
|
|
}
|
|
|
|
// Only 2 cases should be timeout or caller setting result
|
|
ensure(trans_ctx->result);
|
|
|
|
trans_ctx->completion_cond.notify_one();
|
|
};
|
|
|
|
{
|
|
std::lock_guard lock_score(mutex_score_transactions);
|
|
ensure(score_transactions.insert({req_id, trans_ctx}).second);
|
|
}
|
|
|
|
if (async)
|
|
{
|
|
trans_ctx->thread = std::thread(worker_function, std::move(lock));
|
|
return;
|
|
}
|
|
|
|
auto& cpu_thread = *get_current_cpu_thread();
|
|
lv2_obj::sleep(cpu_thread);
|
|
worker_function(std::move(lock));
|
|
cpu_thread.check_state();
|
|
}
|
|
|
|
void np_handler::get_board_infos(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, vm::ptr<SceNpScoreBoardInfo> boardInfo, bool async)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
|
|
u32 req_id = get_req_id(0x3334);
|
|
trans_ctx->tdata = tdata_get_board_infos{.boardInfo = boardInfo};
|
|
rpcn->get_board_infos(req_id, trans_ctx->communicationId, boardId);
|
|
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
|
|
bool np_handler::reply_get_board_infos(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
auto* resp = reply.get_flatbuffer<BoardInfo>();
|
|
|
|
if (reply.is_error())
|
|
return error_and_disconnect("Malformed reply to GetBoardInfos command");
|
|
|
|
SceNpScoreBoardInfo board_info;
|
|
|
|
board_info.rankLimit = resp->rankLimit();
|
|
board_info.updateMode = resp->updateMode();
|
|
board_info.sortMode = resp->sortMode();
|
|
board_info.uploadNumLimit = resp->uploadNumLimit();
|
|
board_info.uploadSizeLimit = resp->uploadSizeLimit();
|
|
|
|
std::lock_guard lock_trans(mutex_score_transactions);
|
|
if (!score_transactions.count(req_id))
|
|
{
|
|
rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id);
|
|
return false;
|
|
}
|
|
|
|
auto trans = ::at32(score_transactions, req_id);
|
|
std::lock_guard lock(trans->mutex);
|
|
|
|
const auto* tdata = std::get_if<tdata_get_board_infos>(&trans->tdata);
|
|
ensure(tdata);
|
|
|
|
memcpy(reinterpret_cast<u8*>(tdata->boardInfo.get_ptr()), &board_info, sizeof(SceNpScoreBoardInfo));
|
|
trans->result = CELL_OK;
|
|
trans->wake_cond.notify_one();
|
|
|
|
return true;
|
|
}
|
|
|
|
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(0x3334);
|
|
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;
|
|
|
|
if (data)
|
|
{
|
|
vec_data = std::vector<u8>(data, data + data_size);
|
|
}
|
|
|
|
trans_ctx->tdata = tdata_record_score{.tmpRank = tmpRank};
|
|
|
|
rpcn->record_score(req_id, trans_ctx->communicationId, boardId, trans_ctx->pcId, score, str_comment, vec_data);
|
|
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
|
|
bool np_handler::reply_record_score(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
std::lock_guard lock_trans(mutex_score_transactions);
|
|
if (!score_transactions.count(req_id))
|
|
{
|
|
rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id);
|
|
return false;
|
|
}
|
|
|
|
auto trans = ::at32(score_transactions, req_id);
|
|
std::lock_guard lock(trans->mutex);
|
|
|
|
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
|
|
{
|
|
switch (reply_data[0])
|
|
{
|
|
case rpcn::ErrorType::ScoreNotBest:
|
|
{
|
|
trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE;
|
|
trans->wake_cond.notify_one();
|
|
return true;
|
|
}
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
auto tmp_rank = reply.get<u32>();
|
|
|
|
if (reply.is_error())
|
|
{
|
|
rpcn_log.error("Error parsing response in reply_record_score");
|
|
return false;
|
|
}
|
|
|
|
const auto* tdata = std::get_if<tdata_record_score>(&trans->tdata);
|
|
ensure(tdata);
|
|
|
|
if (tdata->tmpRank)
|
|
{
|
|
*tdata->tmpRank = tmp_rank;
|
|
}
|
|
|
|
trans->result = CELL_OK;
|
|
trans->wake_cond.notify_one();
|
|
return true;
|
|
}
|
|
|
|
void np_handler::record_score_data(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
|
|
auto* tdata = std::get_if<tdata_record_score_data>(&trans_ctx->tdata);
|
|
if (!tdata)
|
|
{
|
|
trans_ctx->tdata = tdata_record_score_data{.game_data_size = totalSize};
|
|
tdata = std::get_if<tdata_record_score_data>(&trans_ctx->tdata);
|
|
tdata->game_data.reserve(totalSize);
|
|
}
|
|
|
|
std::copy(score_data, score_data + sendSize, std::back_inserter(tdata->game_data));
|
|
|
|
if (tdata->game_data.size() == tdata->game_data_size)
|
|
{
|
|
trans_ctx->result = std::nullopt;
|
|
u32 req_id = get_req_id(0x3334);
|
|
rpcn->record_score_data(req_id, trans_ctx->communicationId, trans_ctx->pcId, boardId, score, tdata->game_data);
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
else
|
|
{
|
|
trans_ctx->result = CELL_OK;
|
|
}
|
|
}
|
|
|
|
bool np_handler::reply_record_score_data(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
std::lock_guard lock_trans(mutex_score_transactions);
|
|
if (!score_transactions.count(req_id))
|
|
{
|
|
rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id);
|
|
return false;
|
|
}
|
|
|
|
auto trans = ::at32(score_transactions, req_id);
|
|
std::lock_guard lock(trans->mutex);
|
|
|
|
auto set_result_and_wake = [&](error_code err) -> bool
|
|
{
|
|
trans->result = err;
|
|
trans->wake_cond.notify_one();
|
|
return true;
|
|
};
|
|
|
|
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
|
|
{
|
|
switch (reply_data[0])
|
|
{
|
|
case rpcn::ErrorType::NotFound: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND);
|
|
case rpcn::ErrorType::ScoreInvalid: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE);
|
|
case rpcn::ErrorType::ScoreHasData: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS);
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
return set_result_and_wake(CELL_OK);
|
|
}
|
|
|
|
void np_handler::get_score_data(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr<u32> totalSize, u32 recvSize, vm::ptr<void> score_data, bool async)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
|
|
auto* tdata = std::get_if<tdata_get_score_data>(&trans_ctx->tdata);
|
|
if (!tdata)
|
|
{
|
|
trans_ctx->tdata = tdata_get_score_data{.totalSize = totalSize, .recvSize = recvSize, .score_data = score_data};
|
|
|
|
u32 req_id = get_req_id(0x3334);
|
|
rpcn->get_score_data(req_id, trans_ctx->communicationId, trans_ctx->pcId, boardId, npId);
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
return;
|
|
}
|
|
|
|
// Check if the transaction has actually completed, otherwise adjust tdata parameters
|
|
if (!trans_ctx->result)
|
|
{
|
|
tdata->totalSize = totalSize;
|
|
tdata->recvSize = recvSize;
|
|
tdata->score_data = score_data;
|
|
return;
|
|
}
|
|
|
|
// If here the data has already been acquired and the client is just asking for part of it
|
|
usz to_copy = std::min(tdata->game_data.size(), static_cast<usz>(recvSize));
|
|
std::memcpy(score_data.get_ptr(), tdata->game_data.data(), to_copy);
|
|
tdata->game_data.erase(tdata->game_data.begin(), tdata->game_data.begin() + to_copy);
|
|
*totalSize = tdata->game_data_size;
|
|
trans_ctx->result = not_an_error(to_copy);
|
|
}
|
|
|
|
bool np_handler::reply_get_score_data(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
std::lock_guard lock_trans(mutex_score_transactions);
|
|
if (!score_transactions.count(req_id))
|
|
{
|
|
rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id);
|
|
return false;
|
|
}
|
|
|
|
auto trans = ::at32(score_transactions, req_id);
|
|
std::lock_guard lock(trans->mutex);
|
|
|
|
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
|
|
{
|
|
switch (reply_data[0])
|
|
{
|
|
case rpcn::ErrorType::NotFound: return trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND);
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
|
|
auto* tdata = std::get_if<tdata_get_score_data>(&trans->tdata);
|
|
ensure(tdata);
|
|
|
|
tdata->game_data = reply.get_rawdata();
|
|
|
|
if (reply.is_error())
|
|
{
|
|
rpcn_log.error("Error parsing response in reply_get_score_data");
|
|
return false;
|
|
}
|
|
|
|
tdata->game_data_size = tdata->game_data.size();
|
|
|
|
usz to_copy = std::min(tdata->game_data.size(), static_cast<usz>(tdata->recvSize));
|
|
std::memcpy(tdata->score_data.get_ptr(), tdata->game_data.data(), to_copy);
|
|
tdata->game_data.erase(tdata->game_data.begin(), tdata->game_data.begin() + to_copy);
|
|
*tdata->totalSize = tdata->game_data_size;
|
|
|
|
return trans->set_result_and_wake(not_an_error(to_copy));
|
|
}
|
|
|
|
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)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
u32 req_id = get_req_id(0x3334);
|
|
|
|
trans_ctx->tdata = tdata_get_score_generic{
|
|
.rankArray = rankArray,
|
|
.rankArraySize = rankArraySize,
|
|
.commentArray = commentArray,
|
|
.infoArray = infoArray,
|
|
.infoArraySize = infoArraySize,
|
|
.arrayNum = arrayNum,
|
|
.lastSortDate = lastSortDate,
|
|
.totalRecord = totalRecord,
|
|
};
|
|
|
|
bool with_comments = !!commentArray;
|
|
bool with_gameinfo = !!infoArray;
|
|
|
|
rpcn->get_score_range(req_id, trans_ctx->communicationId, boardId, startSerialRank, arrayNum, with_comments, with_gameinfo);
|
|
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
|
|
bool np_handler::handle_GetScoreResponse(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
std::lock_guard lock_trans(mutex_score_transactions);
|
|
if (!score_transactions.count(req_id))
|
|
{
|
|
rpcn_log.error("Couldn't find transaction(%d) in trans_id!", req_id);
|
|
return false;
|
|
}
|
|
|
|
auto trans_ctx = ::at32(score_transactions, req_id);
|
|
std::lock_guard lock(trans_ctx->mutex);
|
|
|
|
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vec_stream reply(reply_data, 1);
|
|
auto* resp = reply.get_flatbuffer<GetScoreResponse>();
|
|
|
|
if (reply.is_error())
|
|
{
|
|
rpcn_log.error("Error parsing response in handle_GetScoreResponse");
|
|
return false;
|
|
}
|
|
|
|
const auto* tdata = std::get_if<tdata_get_score_generic>(&trans_ctx->tdata);
|
|
ensure(tdata);
|
|
ensure(resp->rankArray() && resp->rankArray()->size() <= tdata->arrayNum);
|
|
|
|
memset(tdata->rankArray.get_ptr(), 0, tdata->rankArraySize);
|
|
auto* fb_rankarray = resp->rankArray();
|
|
u32 target_index = 0;
|
|
|
|
vm::ptr<SceNpScoreRankData> rankArray = vm::static_ptr_cast<SceNpScoreRankData>(tdata->rankArray);
|
|
vm::ptr<SceNpScorePlayerRankData> rankPlayerArray = vm::static_ptr_cast<SceNpScorePlayerRankData>(tdata->rankArray);
|
|
|
|
for (flatbuffers::uoffset_t i = 0; i < fb_rankarray->size(); i++)
|
|
{
|
|
const auto* fb_rankdata = fb_rankarray->Get(i);
|
|
ensure(fb_rankdata->npId() && fb_rankdata->onlineName());
|
|
|
|
if (fb_rankdata->recordDate() == 0)
|
|
continue;
|
|
|
|
SceNpScoreRankData* cur_rank;
|
|
if (tdata->rankArraySize == (tdata->arrayNum * sizeof(SceNpScoreRankData)))
|
|
{
|
|
cur_rank = &rankArray[i];
|
|
}
|
|
else
|
|
{
|
|
rankPlayerArray[i].hasData = 1;
|
|
cur_rank = &rankPlayerArray[i].rankData;
|
|
}
|
|
|
|
string_to_npid(fb_rankdata->npId()->string_view(), cur_rank->npId);
|
|
string_to_online_name(fb_rankdata->onlineName()->string_view(), cur_rank->onlineName);
|
|
|
|
cur_rank->pcId = fb_rankdata->pcId();
|
|
cur_rank->serialRank = fb_rankdata->rank();
|
|
cur_rank->rank = fb_rankdata->rank();
|
|
cur_rank->highestRank = fb_rankdata->rank();
|
|
cur_rank->scoreValue = fb_rankdata->score();
|
|
cur_rank->hasGameData = fb_rankdata->hasGameData();
|
|
cur_rank->recordDate.tick = fb_rankdata->recordDate();
|
|
|
|
target_index++;
|
|
}
|
|
|
|
if (tdata->commentArray)
|
|
{
|
|
ensure(resp->commentArray() && resp->commentArray()->size() <= tdata->arrayNum);
|
|
memset(tdata->commentArray.get_ptr(), 0, sizeof(SceNpScoreComment) * tdata->arrayNum);
|
|
|
|
auto* fb_commentarray = resp->commentArray();
|
|
for (flatbuffers::uoffset_t i = 0; i < fb_commentarray->size(); i++)
|
|
{
|
|
const auto* fb_comment = fb_commentarray->Get(i);
|
|
strcpy_trunc(tdata->commentArray[i].data, fb_comment->string_view());
|
|
}
|
|
}
|
|
|
|
if (tdata->infoArray)
|
|
{
|
|
ensure(resp->infoArray() && resp->infoArray()->size() <= tdata->arrayNum);
|
|
auto* fb_infoarray = resp->infoArray();
|
|
|
|
if ((tdata->arrayNum * sizeof(SceNpScoreGameInfo)) == tdata->infoArraySize)
|
|
{
|
|
vm::ptr<SceNpScoreGameInfo> ptr_gameinfo = vm::static_ptr_cast<SceNpScoreGameInfo>(tdata->infoArray);
|
|
memset(ptr_gameinfo.get_ptr(), 0, sizeof(SceNpScoreGameInfo) * tdata->arrayNum);
|
|
for (flatbuffers::uoffset_t i = 0; i < fb_infoarray->size(); i++)
|
|
{
|
|
const auto* fb_info = fb_infoarray->Get(i);
|
|
ensure(fb_info->data()->size() <= SCE_NP_SCORE_GAMEINFO_SIZE);
|
|
memcpy(ptr_gameinfo[i].nativeData, fb_info->data()->data(), fb_info->data()->size());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vm::ptr<SceNpScoreVariableSizeGameInfo> ptr_vargameinfo = vm::static_ptr_cast<SceNpScoreVariableSizeGameInfo>(tdata->infoArray);
|
|
memset(ptr_vargameinfo.get_ptr(), 0, sizeof(SceNpScoreVariableSizeGameInfo) * tdata->arrayNum);
|
|
for (flatbuffers::uoffset_t i = 0; i < fb_infoarray->size(); i++)
|
|
{
|
|
const auto* fb_info = fb_infoarray->Get(i);
|
|
ensure(fb_info->data()->size() <= SCE_NP_SCORE_VARIABLE_SIZE_GAMEINFO_MAXSIZE);
|
|
ptr_vargameinfo[i].infoSize = fb_info->data()->size();
|
|
memcpy(ptr_vargameinfo[i].data, fb_info->data(), fb_info->data()->size());
|
|
}
|
|
}
|
|
}
|
|
|
|
tdata->lastSortDate->tick = resp->lastSortDate();
|
|
*tdata->totalRecord = resp->totalRecord();
|
|
|
|
if (fb_rankarray->size())
|
|
trans_ctx->result = not_an_error(fb_rankarray->size());
|
|
else
|
|
trans_ctx->result = SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND;
|
|
|
|
trans_ctx->wake_cond.notify_one();
|
|
return true;
|
|
}
|
|
bool np_handler::reply_get_score_range(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
return handle_GetScoreResponse(req_id, reply_data);
|
|
}
|
|
|
|
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)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
u32 req_id = get_req_id(0x3334);
|
|
trans_ctx->tdata = tdata_get_score_generic{
|
|
.rankArray = rankArray,
|
|
.rankArraySize = rankArraySize,
|
|
.commentArray = commentArray,
|
|
.infoArray = infoArray,
|
|
.infoArraySize = infoArraySize,
|
|
.arrayNum = arrayNum,
|
|
.lastSortDate = lastSortDate,
|
|
.totalRecord = totalRecord,
|
|
};
|
|
|
|
bool with_comments = !!commentArray;
|
|
bool with_gameinfo = !!infoArray;
|
|
|
|
rpcn->get_score_friend(req_id, trans_ctx->communicationId, boardId, include_self, with_comments, with_gameinfo, arrayNum);
|
|
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
bool np_handler::reply_get_score_friends(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
return handle_GetScoreResponse(req_id, reply_data);
|
|
}
|
|
|
|
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)
|
|
{
|
|
std::unique_lock lock(trans_ctx->mutex);
|
|
u32 req_id = get_req_id(0x3334);
|
|
trans_ctx->tdata = tdata_get_score_generic{
|
|
.rankArray = rankArray,
|
|
.rankArraySize = rankArraySize,
|
|
.commentArray = commentArray,
|
|
.infoArray = infoArray,
|
|
.infoArraySize = infoArraySize,
|
|
.arrayNum = arrayNum,
|
|
.lastSortDate = lastSortDate,
|
|
.totalRecord = totalRecord,
|
|
};
|
|
|
|
bool with_comments = !!commentArray;
|
|
bool with_gameinfo = !!infoArray;
|
|
|
|
rpcn->get_score_npid(req_id, trans_ctx->communicationId, boardId, npid_vec, with_comments, with_gameinfo);
|
|
|
|
score_async_handler(std::move(lock), trans_ctx, req_id, async);
|
|
}
|
|
bool np_handler::reply_get_score_npid(u32 req_id, std::vector<u8>& reply_data)
|
|
{
|
|
return handle_GetScoreResponse(req_id, reply_data);
|
|
}
|
|
|
|
} // namespace np
|