matching2 - P7+P8: more public api additions, changes to context, corrections to multiple callback returns, corrections to A types, etc. (#4671)

This commit is contained in:
metr1k-91 2026-07-05 00:00:16 -05:00 committed by GitHub
parent 03e1497f34
commit 3e1f92353c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1217 additions and 571 deletions

View File

@ -638,7 +638,7 @@ set(NP_LIBS src/core/libraries/np/np_error.h
src/core/libraries/np/np_matching2/np_matching2_mm.h
src/core/libraries/np/np_matching2/np_matching2_signaling.cpp
src/core/libraries/np/np_matching2/np_matching2_signaling.h
src/core/libraries/np/np_matching2/np_matching2_types.h
src/core/libraries/np/np_types2.h
src/core/libraries/np/np_trophy.cpp
src/core/libraries/np/np_trophy.h
src/core/libraries/np/np_tus.cpp

View File

@ -1626,7 +1626,7 @@ static u32 FillRankArrayFromProto(const shadnet::GetScoreResponse& resp,
void NpHandler::OnAsyncReply(s32 user_id, ShadNet::CommandType cmd, u64 pkt_id,
ShadNet::ErrorType error, const std::vector<u8>& body) {
const auto cmd_val = static_cast<u16>(cmd);
if (cmd_val >= 12 && cmd_val <= 23) {
if (cmd_val >= 12 && cmd_val <= 24) {
NpMatching2::OnMatchingReply(cmd, pkt_id, error, body);
} else {
OnScoreReply(user_id, cmd, pkt_id, error, body);

View File

@ -15,7 +15,6 @@
#include "core/libraries/np/np_matching2/np_matching2_internal.h"
#include "core/libraries/np/np_matching2/np_matching2_mm.h"
#include "core/libraries/np/np_matching2/np_matching2_signaling.h"
#include "core/libraries/np/np_matching2/np_matching2_types.h"
#include "core/libraries/np/np_types.h"
#include "core/libraries/system/userservice.h"
@ -55,7 +54,7 @@ int PS4_SYSV_ABI sceNpMatching2CreateContextA(const OrbisNpMatching2CreateContex
const Libraries::Np::OrbisNpId np_id =
Libraries::Np::NpHandler::GetInstance().GetNpId(param->userId);
return ContextManager::Instance().CreateContext(&np_id, param->serviceLabel, ctxId);
return ContextManager::Instance().CreateContext(&np_id, param->serviceLabel, ctxId, true);
}
int PS4_SYSV_ABI sceNpMatching2CreateJoinRoom(OrbisNpMatching2ContextId ctxId,
@ -416,7 +415,7 @@ int PS4_SYSV_ABI sceNpMatching2SearchRoom(OrbisNpMatching2ContextId ctxId,
StoreRequestCallback(ctx, requestOpt);
const OrbisNpMatching2RequestId reqId = AllocRequestId();
*requestId = reqId;
MmSearchRoom(ctxId, reqId, *request);
MmSearchRoom(ctxId, reqId, *request, ctx->a_variant);
return ORBIS_OK;
}
@ -690,8 +689,30 @@ int PS4_SYSV_ABI sceNpMatching2GetLobbyMemberDataInternalList() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNpMatching2GetRoomDataExternalList() {
LOG_INFO(Lib_NpMatching2, "called");
int PS4_SYSV_ABI sceNpMatching2GetRoomDataExternalList(
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2GetRoomDataExternalListRequest* request,
OrbisNpMatching2RequestOptParam* requestOpt, OrbisNpMatching2RequestId* requestId) {
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, requestOpt = {}", ctxId, fmt::ptr(requestOpt));
if (!IsInitialized()) {
LOG_ERROR(Lib_NpMatching2, "not initialized");
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
}
if (!request || !requestId) {
LOG_ERROR(Lib_NpMatching2, "request or requestId null");
return ORBIS_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
}
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
if (!ctx) {
LOG_ERROR(Lib_NpMatching2, "invalid context id");
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
}
StoreRequestCallback(ctx, requestOpt);
const OrbisNpMatching2RequestId reqId = AllocRequestId();
*requestId = reqId;
MmGetRoomDataExternalList(ctxId, reqId, *request, ctx->a_variant);
return ORBIS_OK;
}

View File

@ -4,6 +4,7 @@
#pragma once
#include "common/types.h"
#include "core/libraries/np/np_types2.h"
namespace Core::Loader {
class SymbolsResolver;
@ -11,142 +12,6 @@ class SymbolsResolver;
namespace Libraries::Np::NpMatching2 {
using OrbisNpMatching2AttributeId = u16;
using OrbisNpMatching2BlockKickFlag = u8;
using OrbisNpMatching2ContextId = u16;
using OrbisNpMatching2FlagAttr = u32;
using OrbisNpMatching2Flags = u32;
using OrbisNpMatching2LobbyId = u64;
using OrbisNpMatching2LobbyMemberId = u16;
using OrbisNpMatching2NatType = u8;
using OrbisNpMatching2RequestId = u32;
using OrbisNpMatching2RoomGroupId = u8;
using OrbisNpMatching2RoomId = u64;
using OrbisNpMatching2RoomMemberId = u16;
using OrbisNpMatching2RoomPasswordSlotMask = u64;
using OrbisNpMatching2ServerId = u16;
using OrbisNpMatching2SignalingFlag = u8;
using OrbisNpMatching2SignalingRequestId = u32;
using OrbisNpMatching2TeamId = u8;
using OrbisNpMatching2WorldId = u32;
enum OrbisNpMatching2Event : u16 {
ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_WORLD_INFO_LIST = 0x0002,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_EXTERNAL = 0x0004,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SET_USER_INFO = 0x0007,
ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM = 0x0101,
ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM = 0x0102,
ORBIS_NP_MATCHING2_REQUEST_EVENT_LEAVE_ROOM = 0x0103,
ORBIS_NP_MATCHING2_REQUEST_EVENT_KICKOUT_ROOM_MEMBER = 0x0104,
ORBIS_NP_MATCHING2_REQUEST_EVENT_GRANT_ROOM_OWNER = 0x0105,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM = 0x0106,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SEND_ROOM_MESSAGE = 0x0108,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_INTERNAL = 0x0109,
ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_INTERNAL = 0x010A,
ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_LOBBY = 0x0201,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SIGNALING_GET_PING_INFO = 0x0E01,
ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED = 0x1101,
ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT = 0x1102,
ORBIS_NP_MATCHING2_ROOM_EVENT_KICKEDOUT = 0x1103,
ORBIS_NP_MATCHING2_ROOM_EVENT_ROOM_DESTROYED = 0x1104,
ORBIS_NP_MATCHING2_ROOM_EVENT_ROOM_OWNER_CHANGED = 0x1105,
ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_DATA_INTERNAL = 0x1106,
ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_MEMBER_DATA_INTERNAL = 0x1107,
ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_SIGNALING_OPT_PARAM = 0x1108,
ORBIS_NP_MATCHING2_SIGNALING_EVENT_DEAD = 0x5101,
ORBIS_NP_MATCHING2_SIGNALING_EVENT_ESTABLISHED = 0x5102,
ORBIS_NP_MATCHING2_SIGNALING_EVENT_NETINFO_ERROR = 0x5103,
ORBIS_NP_MATCHING2_CONTEXT_EVENT_START_OVER = 0x6F01,
ORBIS_NP_MATCHING2_CONTEXT_EVENT_STARTED = 0x6F02,
ORBIS_NP_MATCHING2_CONTEXT_EVENT_STOPPED = 0x6F03,
ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM_A = 0x7101,
ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM_A = 0x7102,
ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM_A = 0x7106,
ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED_A = 0x8101,
ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT_A = 0x8102,
ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_MEMBER_DATA_INTERNAL_A = 0x8107,
ORBIS_NP_MATCHING2_ROOM_MSG_EVENT_MESSAGE_A = 0x9102,
};
enum OrbisNpMatching2EventCause : u8 {
ORBIS_NP_MATCHING2_EVENT_CAUSE_LEAVE_ACTION = 1,
ORBIS_NP_MATCHING2_EVENT_CAUSE_KICKOUT_ACTION = 2,
ORBIS_NP_MATCHING2_EVENT_CAUSE_GRANT_OWNER_ACTION = 3,
ORBIS_NP_MATCHING2_EVENT_CAUSE_SERVER_OPERATION = 4,
ORBIS_NP_MATCHING2_EVENT_CAUSE_MEMBER_DISAPPEARED = 5,
ORBIS_NP_MATCHING2_EVENT_CAUSE_SERVER_INTERNAL = 6,
ORBIS_NP_MATCHING2_EVENT_CAUSE_CONNECTION_ERROR = 7,
ORBIS_NP_MATCHING2_EVENT_CAUSE_NP_SIGNED_OUT = 8,
ORBIS_NP_MATCHING2_EVENT_CAUSE_SYSTEM_ERROR = 9,
ORBIS_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ERROR = 10,
ORBIS_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION = 11,
};
enum OrbisNpMatching2SignalingType : u8 {
ORBIS_NP_MATCHING2_SIGNALING_TYPE_NONE = 0,
ORBIS_NP_MATCHING2_SIGNALING_TYPE_MESH = 1,
ORBIS_NP_MATCHING2_SIGNALING_TYPE_STAR = 2,
};
enum OrbisNpMatching2SignalingConnectionInfoType : s32 {
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_RTT = 1,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_BANDWIDTH = 2,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_NP_ID = 3,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_ADDR = 4,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_MAPPED_ADDR = 5,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PACKET_LOSS = 6,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_NPID = 7,
ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_ADDRESS_A = 7,
};
enum OrbisNpMatching2AttrId : OrbisNpMatching2AttributeId {
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_1_ID = 0x004C,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_2_ID = 0x004D,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_3_ID = 0x004E,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_4_ID = 0x004F,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_5_ID = 0x0050,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_6_ID = 0x0051,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_7_ID = 0x0052,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_INT_ATTR_EXTERNAL_8_ID = 0x0053,
ORBIS_NP_MATCHING2_ROOM_SEARCHABLE_BIN_ATTR_EXTERNAL_1_ID = 0x0054,
ORBIS_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID = 0x0055,
ORBIS_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_2_ID = 0x0056,
ORBIS_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID = 0x0057,
ORBIS_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_2_ID = 0x0058,
ORBIS_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID = 0x0059,
};
enum OrbisNpMatching2RoomFlagAttr : OrbisNpMatching2Flags {
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_OWNER_AUTO_GRANT = 0x80000000,
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_CLOSED = 0x40000000,
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_FULL = 0x20000000,
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_HIDDEN = 0x10000000,
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_NAT_TYPE_RESTRICTION = 0x04000000,
ORBIS_NP_MATCHING2_ROOM_FLAG_ATTR_PROHIBITIVE_MODE = 0x02000000,
};
enum OrbisNpMatching2RoomMemberFlagAttr : OrbisNpMatching2Flags {
ORBIS_NP_MATCHING2_ROOMMEMBER_FLAG_ATTR_OWNER = 0x80000000,
};
enum OrbisNpMatching2Role : u8 {
ORBIS_NP_MATCHING2_ROLE_MEMBER = 1,
ORBIS_NP_MATCHING2_ROLE_OWNER = 2,
};
constexpr u32 ORBIS_NP_MATCHING2_SESSION_PASSWORD_SIZE = 8;
constexpr u32 ORBIS_NP_MATCHING2_GROUP_LABEL_SIZE = 8;
enum OrbisNpMatching2InitDefault : u64 {
ORBIS_NP_MATCHING2_THREAD_STACK_SIZE_DEFAULT = 32768,
ORBIS_NP_MATCHING2_POOLSIZE_DEFAULT = 131072,
ORBIS_NP_MATCHING2_SSL_POOLSIZE_DEFAULT = 196608,
};
struct OrbisNpMatching2InitializeParameter;
struct OrbisNpMatching2CreateContextParameter;
struct OrbisNpMatching2CreateContextParameterA;
int PS4_SYSV_ABI sceNpMatching2Initialize(OrbisNpMatching2InitializeParameter* param);
int PS4_SYSV_ABI sceNpMatching2Terminate();
int PS4_SYSV_ABI sceNpMatching2CreateContext(const OrbisNpMatching2CreateContextParameter* param,

View File

@ -28,6 +28,34 @@ u32 IpStringToAddr(std::string_view ip) {
return a | (b << 8) | (c << 16) | (d << 24);
}
template <typename Reply>
void ReserveExternalRoomPayloadStorage(CallbackPayload& p, const Reply& resp) {
size_t groups = 0;
size_t int_attrs = 0;
size_t bin_attrs = 0;
size_t bin_buffers = 0;
size_t owners = 0;
for (int i = 0; i < resp.rooms_size(); ++i) {
const auto& r = resp.rooms(i);
groups += static_cast<size_t>(r.groups_size());
int_attrs += static_cast<size_t>(r.external_search_int_attrs_size());
const size_t room_bin_attrs = static_cast<size_t>(r.external_search_bin_attrs_size()) +
static_cast<size_t>(r.external_bin_attrs_size());
bin_attrs += room_bin_attrs;
bin_buffers += room_bin_attrs;
if (!r.owner_npid().empty()) {
++owners;
}
}
p.ext_room_groups.reserve(groups);
p.ext_int_attrs.reserve(int_attrs);
p.ext_bin_attrs.reserve(bin_attrs);
p.bin_buffers.reserve(bin_buffers);
p.ext_owner_npids.reserve(owners);
}
} // namespace
void BuildCreateJoinRoomPayloadCommon(ContextObject& ctx,
@ -343,6 +371,7 @@ void* BuildGetWorldInfoListPayload(ContextObject& ctx, const shadnet::GetWorldIn
void* BuildSearchRoomPayload(ContextObject& ctx, const shadnet::SearchRoomReply& resp) {
CallbackPayload& p = ctx.request_payload;
p.Reset();
ReserveExternalRoomPayloadStorage(p, resp);
const int room_count = resp.rooms_size();
p.room_data_external.resize(room_count);
@ -444,6 +473,321 @@ void* BuildSearchRoomPayload(ContextObject& ctx, const shadnet::SearchRoomReply&
return p.request_data;
}
void* BuildSearchRoomPayloadA(ContextObject& ctx, const shadnet::SearchRoomReply& resp) {
CallbackPayload& p = ctx.request_payload;
p.Reset();
ReserveExternalRoomPayloadStorage(p, resp);
const int room_count = resp.rooms_size();
p.room_data_external_a.resize(room_count);
for (int i = 0; i < room_count; ++i) {
const auto& r = resp.rooms(i);
auto& dst = p.room_data_external_a[i];
dst = OrbisNpMatching2RoomDataExternalA{};
dst.next = (i + 1 < room_count) ? &p.room_data_external_a[i + 1] : nullptr;
dst.maxSlot = static_cast<u16>(r.max_slot());
dst.curMembers = static_cast<u16>(r.cur_members());
dst.flags = r.flags();
dst.serverId = static_cast<OrbisNpMatching2ServerId>(r.server_id());
dst.worldId = static_cast<OrbisNpMatching2WorldId>(r.world_id());
dst.lobbyId = r.lobby_id();
dst.roomId = r.room_id();
dst.passwdSlotMask = r.passwd_slot_mask();
dst.joinedSlotMask = r.joined_slot_mask();
dst.publicSlots = static_cast<u16>(r.public_slots());
dst.privateSlots = static_cast<u16>(r.private_slots());
dst.openPublicSlots = static_cast<u16>(r.open_public_slots());
dst.openPrivateSlots = static_cast<u16>(r.open_private_slots());
if (!r.owner_npid().empty()) {
std::strncpy(dst.ownerOnlineId.data, r.owner_npid().c_str(),
sizeof(dst.ownerOnlineId.data) - 1);
}
dst.owner.accountId = static_cast<Libraries::Np::OrbisNpAccountId>(r.owner_account_id());
dst.owner.platform = static_cast<Libraries::Np::OrbisNpPlatformType>(r.owner_platform());
if (r.groups_size() > 0) {
OrbisNpMatching2RoomGroupInfo* first = nullptr;
for (int g = 0; g < r.groups_size(); ++g) {
const auto& src = r.groups(g);
auto& gi = p.ext_room_groups.emplace_back();
gi = OrbisNpMatching2RoomGroupInfo{};
gi.id = static_cast<OrbisNpMatching2RoomGroupId>(src.group_id());
gi.hasPasswd = src.has_passwd();
gi.slots = src.slot_count();
gi.groupMembers = src.num_members();
if (!first) {
first = &gi;
}
}
dst.roomGroup = first;
dst.roomGroups = static_cast<u64>(r.groups_size());
}
if (r.external_search_int_attrs_size() > 0) {
OrbisNpMatching2IntAttr* first = nullptr;
for (int a = 0; a < r.external_search_int_attrs_size(); ++a) {
const auto& src = r.external_search_int_attrs(a);
auto& ia = p.ext_int_attrs.emplace_back();
ia = OrbisNpMatching2IntAttr{};
ia.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ia.num = src.attr_value();
if (!first) {
first = &ia;
}
}
dst.externalSearchIntAttr = first;
dst.externalSearchIntAttrs = static_cast<u64>(r.external_search_int_attrs_size());
}
auto build_bin = [&](const auto& src_attrs, OrbisNpMatching2BinAttr*& out_ptr,
u64& out_num) {
if (src_attrs.empty()) {
return;
}
OrbisNpMatching2BinAttr* first = nullptr;
for (const auto& src : src_attrs) {
p.bin_buffers.emplace_back(src.data().begin(), src.data().end());
auto& buf = p.bin_buffers.back();
auto& ba = p.ext_bin_attrs.emplace_back();
ba = OrbisNpMatching2BinAttr{};
ba.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ba.data = buf.empty() ? nullptr : buf.data();
ba.dataSize = buf.size();
if (!first) {
first = &ba;
}
}
out_ptr = first;
out_num = static_cast<u64>(src_attrs.size());
};
build_bin(r.external_search_bin_attrs(), dst.externalSearchBinAttr,
dst.externalSearchBinAttrs);
build_bin(r.external_bin_attrs(), dst.externalBinAttr, dst.externalBinAttrs);
}
p.search_room_response_a = std::make_unique<OrbisNpMatching2SearchRoomResponseA>();
auto& out = *p.search_room_response_a;
out = OrbisNpMatching2SearchRoomResponseA{};
out.range.start = resp.range_start();
out.range.total = resp.range_total();
out.range.results = resp.range_result();
out.roomDataExt = p.room_data_external_a.empty() ? nullptr : p.room_data_external_a.data();
p.request_data = p.search_room_response_a.get();
return p.request_data;
}
void* BuildGetRoomDataExternalListPayload(ContextObject& ctx,
const shadnet::GetRoomDataExternalListReply& resp) {
CallbackPayload& p = ctx.request_payload;
p.Reset();
ReserveExternalRoomPayloadStorage(p, resp);
const int room_count = resp.rooms_size();
p.room_data_external.resize(room_count);
for (int i = 0; i < room_count; ++i) {
const auto& r = resp.rooms(i);
auto& dst = p.room_data_external[i];
dst = OrbisNpMatching2RoomDataExternal{};
dst.next = (i + 1 < room_count) ? &p.room_data_external[i + 1] : nullptr;
dst.maxSlot = static_cast<u16>(r.max_slot());
dst.curMembers = static_cast<u16>(r.cur_members());
dst.flags = r.flags();
dst.serverId = static_cast<OrbisNpMatching2ServerId>(r.server_id());
dst.worldId = static_cast<OrbisNpMatching2WorldId>(r.world_id());
dst.lobbyId = r.lobby_id();
dst.roomId = r.room_id();
dst.passwdSlotMask = r.passwd_slot_mask();
dst.joinedSlotMask = r.joined_slot_mask();
dst.publicSlots = static_cast<u16>(r.public_slots());
dst.privateSlots = static_cast<u16>(r.private_slots());
dst.openPublicSlots = static_cast<u16>(r.open_public_slots());
dst.openPrivateSlots = static_cast<u16>(r.open_private_slots());
if (!r.owner_npid().empty()) {
auto& npid = p.ext_owner_npids.emplace_back();
npid = Libraries::Np::OrbisNpId{};
std::strncpy(npid.handle.data, r.owner_npid().c_str(), sizeof(npid.handle.data) - 1);
dst.ownerNpId = &npid;
}
if (r.groups_size() > 0) {
OrbisNpMatching2RoomGroupInfo* first = nullptr;
for (int g = 0; g < r.groups_size(); ++g) {
const auto& src = r.groups(g);
auto& gi = p.ext_room_groups.emplace_back();
gi = OrbisNpMatching2RoomGroupInfo{};
gi.id = static_cast<OrbisNpMatching2RoomGroupId>(src.group_id());
gi.hasPasswd = src.has_passwd();
gi.slots = src.slot_count();
gi.groupMembers = src.num_members();
if (!first) {
first = &gi;
}
}
dst.roomGroup = first;
dst.roomGroups = static_cast<u64>(r.groups_size());
}
if (r.external_search_int_attrs_size() > 0) {
OrbisNpMatching2IntAttr* first = nullptr;
for (int a = 0; a < r.external_search_int_attrs_size(); ++a) {
const auto& src = r.external_search_int_attrs(a);
auto& ia = p.ext_int_attrs.emplace_back();
ia = OrbisNpMatching2IntAttr{};
ia.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ia.num = src.attr_value();
if (!first) {
first = &ia;
}
}
dst.externalSearchIntAttr = first;
dst.externalSearchIntAttrs = static_cast<u64>(r.external_search_int_attrs_size());
}
auto build_bin = [&](const auto& src_attrs, OrbisNpMatching2BinAttr*& out_ptr,
u64& out_num) {
if (src_attrs.empty()) {
return;
}
OrbisNpMatching2BinAttr* first = nullptr;
for (const auto& src : src_attrs) {
p.bin_buffers.emplace_back(src.data().begin(), src.data().end());
auto& buf = p.bin_buffers.back();
auto& ba = p.ext_bin_attrs.emplace_back();
ba = OrbisNpMatching2BinAttr{};
ba.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ba.data = buf.empty() ? nullptr : buf.data();
ba.dataSize = buf.size();
if (!first) {
first = &ba;
}
}
out_ptr = first;
out_num = static_cast<u64>(src_attrs.size());
};
build_bin(r.external_search_bin_attrs(), dst.externalSearchBinAttr,
dst.externalSearchBinAttrs);
build_bin(r.external_bin_attrs(), dst.externalBinAttr, dst.externalBinAttrs);
}
p.room_data_external_list_response =
std::make_unique<OrbisNpMatching2GetRoomDataExternalListResponse>();
auto& out = *p.room_data_external_list_response;
out = OrbisNpMatching2GetRoomDataExternalListResponse{};
out.roomDataExternal = p.room_data_external.empty() ? nullptr : p.room_data_external.data();
out.roomDataExternalNum = static_cast<u64>(p.room_data_external.size());
p.request_data = p.room_data_external_list_response.get();
return p.request_data;
}
void* BuildGetRoomDataExternalListPayloadA(ContextObject& ctx,
const shadnet::GetRoomDataExternalListReply& resp) {
CallbackPayload& p = ctx.request_payload;
p.Reset();
ReserveExternalRoomPayloadStorage(p, resp);
const int room_count = resp.rooms_size();
p.room_data_external_a.resize(room_count);
for (int i = 0; i < room_count; ++i) {
const auto& r = resp.rooms(i);
auto& dst = p.room_data_external_a[i];
dst = OrbisNpMatching2RoomDataExternalA{};
dst.next = (i + 1 < room_count) ? &p.room_data_external_a[i + 1] : nullptr;
dst.maxSlot = static_cast<u16>(r.max_slot());
dst.curMembers = static_cast<u16>(r.cur_members());
dst.flags = r.flags();
dst.serverId = static_cast<OrbisNpMatching2ServerId>(r.server_id());
dst.worldId = static_cast<OrbisNpMatching2WorldId>(r.world_id());
dst.lobbyId = r.lobby_id();
dst.roomId = r.room_id();
dst.passwdSlotMask = r.passwd_slot_mask();
dst.joinedSlotMask = r.joined_slot_mask();
dst.publicSlots = static_cast<u16>(r.public_slots());
dst.privateSlots = static_cast<u16>(r.private_slots());
dst.openPublicSlots = static_cast<u16>(r.open_public_slots());
dst.openPrivateSlots = static_cast<u16>(r.open_private_slots());
if (!r.owner_npid().empty()) {
std::strncpy(dst.ownerOnlineId.data, r.owner_npid().c_str(),
sizeof(dst.ownerOnlineId.data) - 1);
}
dst.owner.accountId = static_cast<Libraries::Np::OrbisNpAccountId>(r.owner_account_id());
dst.owner.platform = static_cast<Libraries::Np::OrbisNpPlatformType>(r.owner_platform());
if (r.groups_size() > 0) {
OrbisNpMatching2RoomGroupInfo* first = nullptr;
for (int g = 0; g < r.groups_size(); ++g) {
const auto& src = r.groups(g);
auto& gi = p.ext_room_groups.emplace_back();
gi = OrbisNpMatching2RoomGroupInfo{};
gi.id = static_cast<OrbisNpMatching2RoomGroupId>(src.group_id());
gi.hasPasswd = src.has_passwd();
gi.slots = src.slot_count();
gi.groupMembers = src.num_members();
if (!first) {
first = &gi;
}
}
dst.roomGroup = first;
dst.roomGroups = static_cast<u64>(r.groups_size());
}
if (r.external_search_int_attrs_size() > 0) {
OrbisNpMatching2IntAttr* first = nullptr;
for (int a = 0; a < r.external_search_int_attrs_size(); ++a) {
const auto& src = r.external_search_int_attrs(a);
auto& ia = p.ext_int_attrs.emplace_back();
ia = OrbisNpMatching2IntAttr{};
ia.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ia.num = src.attr_value();
if (!first) {
first = &ia;
}
}
dst.externalSearchIntAttr = first;
dst.externalSearchIntAttrs = static_cast<u64>(r.external_search_int_attrs_size());
}
auto build_bin = [&](const auto& src_attrs, OrbisNpMatching2BinAttr*& out_ptr,
u64& out_num) {
if (src_attrs.empty()) {
return;
}
OrbisNpMatching2BinAttr* first = nullptr;
for (const auto& src : src_attrs) {
p.bin_buffers.emplace_back(src.data().begin(), src.data().end());
auto& buf = p.bin_buffers.back();
auto& ba = p.ext_bin_attrs.emplace_back();
ba = OrbisNpMatching2BinAttr{};
ba.id = static_cast<OrbisNpMatching2AttributeId>(src.attr_id());
ba.data = buf.empty() ? nullptr : buf.data();
ba.dataSize = buf.size();
if (!first) {
first = &ba;
}
}
out_ptr = first;
out_num = static_cast<u64>(src_attrs.size());
};
build_bin(r.external_search_bin_attrs(), dst.externalSearchBinAttr,
dst.externalSearchBinAttrs);
build_bin(r.external_bin_attrs(), dst.externalBinAttr, dst.externalBinAttrs);
}
p.room_data_external_list_response_a =
std::make_unique<OrbisNpMatching2GetRoomDataExternalListResponseA>();
auto& out = *p.room_data_external_list_response_a;
out = OrbisNpMatching2GetRoomDataExternalListResponseA{};
out.roomDataExternal = p.room_data_external_a.empty() ? nullptr : p.room_data_external_a.data();
out.roomDataExternalNum = static_cast<u64>(p.room_data_external_a.size());
p.request_data = p.room_data_external_list_response_a.get();
return p.request_data;
}
void* BuildGetRoomDataInternalPayload(ContextObject& ctx, OrbisNpMatching2RoomId room_id) {
const auto rc_it = ctx.room_cache.find(room_id);
if (rc_it == ctx.room_cache.end()) {
@ -548,7 +892,7 @@ ContextObject* ContextManager::GetLocked(OrbisNpMatching2ContextId ctx_id) {
}
s32 ContextManager::CreateContext(const OrbisNpId* owner_np_id, OrbisNpServiceLabel service_label,
OrbisNpMatching2ContextId* out_ctx_id) {
OrbisNpMatching2ContextId* out_ctx_id, bool a_variant) {
if (!out_ctx_id) {
return ORBIS_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
}
@ -572,6 +916,7 @@ s32 ContextManager::CreateContext(const OrbisNpId* owner_np_id, OrbisNpServiceLa
ContextObject& ctx = m_contexts[id];
ctx.Reset();
ctx.ctx_id = id;
ctx.a_variant = a_variant;
ctx.service_label = service_label;
if (owner_np_id) {
ctx.owner_np_id = *owner_np_id;
@ -582,8 +927,8 @@ s32 ContextManager::CreateContext(const OrbisNpId* owner_np_id, OrbisNpServiceLa
m_used[id] = true;
*out_ctx_id = id;
LOG_DEBUG(Lib_NpMatching2, "context created: id={} online_id={} serviceLabel={:#x}", id,
ctx.online_id.data, service_label);
LOG_DEBUG(Lib_NpMatching2, "context{} created: id={} online_id={} serviceLabel={:#x}",
a_variant ? "A" : "", id, ctx.online_id.data, service_label);
return ORBIS_OK;
}

View File

@ -7,7 +7,6 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <map>
#include <memory>
#include <mutex>
@ -17,12 +16,12 @@
#include "common/types.h"
#include "core/libraries/kernel/threads.h"
#include "core/libraries/np/np_matching2/np_matching2.h"
#include "core/libraries/np/np_matching2/np_matching2_types.h"
#include "core/libraries/np/np_types.h"
namespace shadnet {
class CreateJoinRoomResponse;
class GetWorldInfoListReply;
class GetRoomDataExternalListReply;
class LeaveRoomReply;
class SearchRoomReply;
} // namespace shadnet
@ -96,6 +95,11 @@ struct CallbackPayload {
std::unique_ptr<OrbisNpMatching2CreateJoinRoomResponseA> create_join_response_a;
std::unique_ptr<OrbisNpMatching2LeaveRoomResponse> leave_room_response;
std::unique_ptr<OrbisNpMatching2SearchRoomResponse> search_room_response;
std::unique_ptr<OrbisNpMatching2SearchRoomResponseA> search_room_response_a;
std::unique_ptr<OrbisNpMatching2GetRoomDataExternalListResponse>
room_data_external_list_response;
std::unique_ptr<OrbisNpMatching2GetRoomDataExternalListResponseA>
room_data_external_list_response_a;
std::unique_ptr<OrbisNpMatching2GetWorldInfoListResponse> world_info_response;
std::unique_ptr<OrbisNpMatching2SignalingGetPingInfoResponse> ping_info_response;
std::vector<OrbisNpMatching2World> world_list;
@ -107,14 +111,16 @@ struct CallbackPayload {
std::vector<OrbisNpMatching2RoomBinAttrInternal*> room_bin_attr_ptrs;
std::vector<OrbisNpMatching2RoomMemberBinAttrInternal> member_bin_attrs;
std::vector<OrbisNpMatching2RoomDataExternal> room_data_external;
std::vector<OrbisNpMatching2RoomDataExternalA> room_data_external_a;
std::vector<std::vector<u8>> bin_buffers;
std::deque<OrbisNpMatching2IntAttr> ext_int_attrs;
std::deque<OrbisNpMatching2BinAttr> ext_bin_attrs;
std::deque<OrbisNpMatching2RoomGroupInfo> ext_room_groups;
std::deque<Libraries::Np::OrbisNpId> ext_owner_npids;
std::vector<OrbisNpMatching2IntAttr> ext_int_attrs;
std::vector<OrbisNpMatching2BinAttr> ext_bin_attrs;
std::vector<OrbisNpMatching2RoomGroupInfo> ext_room_groups;
std::vector<Libraries::Np::OrbisNpId> ext_owner_npids;
void* request_data = nullptr;
std::unique_ptr<OrbisNpMatching2RoomMemberUpdate> room_member_update;
std::unique_ptr<OrbisNpMatching2RoomMemberUpdateA> room_member_update_a;
std::unique_ptr<OrbisNpMatching2RoomUpdate> room_update;
std::unique_ptr<OrbisNpMatching2RoomDataInternalUpdate> room_data_internal_update;
std::unique_ptr<OrbisNpMatching2FlagAttr> event_chg_flag_attr;
@ -122,6 +128,7 @@ struct CallbackPayload {
std::unique_ptr<OrbisNpMatching2RoomPasswordSlotMask> event_chg_passwd_slot_mask;
std::unique_ptr<OrbisNpMatching2RoomPasswordSlotMask> event_prev_passwd_slot_mask;
std::unique_ptr<OrbisNpMatching2RoomMemberDataInternal> event_member;
std::unique_ptr<OrbisNpMatching2RoomMemberDataInternalA> event_member_a;
void* room_event_data = nullptr;
CallbackPayload() = default;
@ -136,6 +143,9 @@ struct CallbackPayload {
create_join_response_a.reset();
leave_room_response.reset();
search_room_response.reset();
search_room_response_a.reset();
room_data_external_list_response.reset();
room_data_external_list_response_a.reset();
world_info_response.reset();
ping_info_response.reset();
world_list.clear();
@ -147,6 +157,7 @@ struct CallbackPayload {
room_bin_attr_ptrs.clear();
member_bin_attrs.clear();
room_data_external.clear();
room_data_external_a.clear();
bin_buffers.clear();
ext_int_attrs.clear();
ext_bin_attrs.clear();
@ -154,6 +165,7 @@ struct CallbackPayload {
ext_owner_npids.clear();
request_data = nullptr;
room_member_update.reset();
room_member_update_a.reset();
room_update.reset();
room_data_internal_update.reset();
event_chg_flag_attr.reset();
@ -161,6 +173,7 @@ struct CallbackPayload {
event_chg_passwd_slot_mask.reset();
event_prev_passwd_slot_mask.reset();
event_member.reset();
event_member_a.reset();
room_event_data = nullptr;
}
};
@ -168,6 +181,7 @@ struct CallbackPayload {
struct ContextObject {
OrbisNpMatching2ContextId ctx_id = 0;
bool started = false;
bool a_variant = false;
OrbisNpMatching2ServerId server_id = 1;
OrbisNpServiceLabel service_label = 0;
@ -214,6 +228,7 @@ struct ContextObject {
void Reset() {
ctx_id = 0;
started = false;
a_variant = false;
server_id = 1;
service_label = 0;
owner_np_id = {};
@ -253,12 +268,12 @@ struct ContextObject {
class ContextManager {
public:
static constexpr u32 kMaxContexts = 255;
static constexpr u32 kMaxContexts = 10;
static ContextManager& Instance();
s32 CreateContext(const OrbisNpId* owner_np_id, OrbisNpServiceLabel service_label,
OrbisNpMatching2ContextId* out_ctx_id);
OrbisNpMatching2ContextId* out_ctx_id, bool a_variant = false);
bool Check(OrbisNpMatching2ContextId ctx_id);
ContextObject* Get(OrbisNpMatching2ContextId ctx_id);
@ -351,6 +366,11 @@ void* BuildCreateJoinRoomPayloadA(ContextObject& ctx, const shadnet::CreateJoinR
void* BuildLeaveRoomPayload(ContextObject& ctx, const shadnet::LeaveRoomReply& resp);
void* BuildGetWorldInfoListPayload(ContextObject& ctx, const shadnet::GetWorldInfoListReply& resp);
void* BuildSearchRoomPayload(ContextObject& ctx, const shadnet::SearchRoomReply& resp);
void* BuildSearchRoomPayloadA(ContextObject& ctx, const shadnet::SearchRoomReply& resp);
void* BuildGetRoomDataExternalListPayload(ContextObject& ctx,
const shadnet::GetRoomDataExternalListReply& resp);
void* BuildGetRoomDataExternalListPayloadA(ContextObject& ctx,
const shadnet::GetRoomDataExternalListReply& resp);
void* BuildGetRoomDataInternalPayload(ContextObject& ctx, OrbisNpMatching2RoomId room_id);
void InitEventDispatcher();

View File

@ -190,10 +190,19 @@ void DispatchRequestComplete(const PendingRequest& pr, ShadNet::ErrorType error,
if (reply.ParseFromString(proto)) {
request_data = BuildGetWorldInfoListPayload(*ctx, reply);
}
} else if (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM) {
} else if (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM_A) {
shadnet::SearchRoomReply reply;
if (reply.ParseFromString(proto)) {
request_data = BuildSearchRoomPayload(*ctx, reply);
request_data = pr.a_variant ? BuildSearchRoomPayloadA(*ctx, reply)
: BuildSearchRoomPayload(*ctx, reply);
}
} else if (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST_A) {
shadnet::GetRoomDataExternalListReply reply;
if (reply.ParseFromString(proto)) {
request_data = pr.a_variant ? BuildGetRoomDataExternalListPayloadA(*ctx, reply)
: BuildGetRoomDataExternalListPayload(*ctx, reply);
}
}
}
@ -210,16 +219,71 @@ void DispatchRequestComplete(const PendingRequest& pr, ShadNet::ErrorType error,
ev.request_data = request_data;
ScheduleEvent(std::move(ev));
if (error_code == 0 && (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM_A ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM ||
if (error_code == 0 && (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM_A)) {
StartMatching2SignalingForRoomPeers(*ctx, ctx->room_id);
QueueMatching2EstablishedForRoomPeers(*ctx, ctx->room_id);
} else if (error_code == 0 &&
(pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM ||
pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM_A)) {
StartMatching2SignalingForRoomPeers(*ctx, ctx->room_id);
}
}
void AppendEventMemberBinAttrs(CallbackPayload& p, const MemberCache& mc) {
p.member_bin_attrs.resize(mc.bins.size());
p.bin_buffers.reserve(mc.bins.size());
size_t i = 0;
for (const auto& [attr_id, bin] : mc.bins) {
p.bin_buffers.emplace_back(bin.data.begin(), bin.data.end());
auto& buf = p.bin_buffers.back();
auto& dst = p.member_bin_attrs[i++];
dst = OrbisNpMatching2RoomMemberBinAttrInternal{};
dst.lastUpdate.tick = bin.update_date;
dst.binAttr.id = bin.id;
dst.binAttr.data = buf.empty() ? nullptr : buf.data();
dst.binAttr.dataSize = buf.size();
}
}
void BuildMemberUpdate(CallbackPayload& p, const RoomCache& rc, const MemberCache& mc,
OrbisNpMatching2EventCause cause) {
OrbisNpMatching2EventCause cause, bool a_variant) {
if (mc.group_id != 0) {
auto grp_it = rc.groups.find(mc.group_id);
if (grp_it != rc.groups.end()) {
p.room_groups.resize(1);
p.room_groups[0] = grp_it->second;
}
}
AppendEventMemberBinAttrs(p, mc);
if (a_variant) {
p.event_member_a = std::make_unique<OrbisNpMatching2RoomMemberDataInternalA>();
OrbisNpMatching2RoomMemberDataInternalA& m = *p.event_member_a;
m = OrbisNpMatching2RoomMemberDataInternalA{};
m.memberId = mc.member_id;
m.teamId = mc.team_id;
m.natType = mc.nat_type;
m.flags = mc.flag_attr;
m.joinDateTicks.tick = mc.join_date;
m.user.accountId = mc.account_id;
m.user.platform = mc.platform;
std::strncpy(m.onlineId.data, mc.np_id.handle.data, sizeof(m.onlineId.data) - 1);
m.roomGroup = p.room_groups.empty() ? nullptr : p.room_groups.data();
m.roomMemberInternalBinAttr =
p.member_bin_attrs.empty() ? nullptr : p.member_bin_attrs.data();
m.roomMemberInternalBinAttrs = p.member_bin_attrs.size();
p.room_member_update_a = std::make_unique<OrbisNpMatching2RoomMemberUpdateA>();
OrbisNpMatching2RoomMemberUpdateA& u = *p.room_member_update_a;
u = OrbisNpMatching2RoomMemberUpdateA{};
u.roomMemberDataInternal = p.event_member_a.get();
u.eventCause = cause;
p.room_event_data = p.room_member_update_a.get();
return;
}
p.event_member = std::make_unique<OrbisNpMatching2RoomMemberDataInternal>();
OrbisNpMatching2RoomMemberDataInternal& m = *p.event_member;
m = OrbisNpMatching2RoomMemberDataInternal{};
@ -229,28 +293,7 @@ void BuildMemberUpdate(CallbackPayload& p, const RoomCache& rc, const MemberCach
m.flagAttr = mc.flag_attr;
m.joinDate = mc.join_date;
m.npId = mc.np_id;
if (mc.group_id != 0) {
auto grp_it = rc.groups.find(mc.group_id);
if (grp_it != rc.groups.end()) {
p.room_groups.resize(1);
p.room_groups[0] = grp_it->second;
m.roomGroup = p.room_groups.data();
}
}
p.member_bin_attrs.resize(mc.bins.size());
p.bin_buffers.reserve(mc.bins.size());
size_t i = 0;
for (const auto& [attr_id, bin] : mc.bins) {
p.bin_buffers.emplace_back(bin.data.begin(), bin.data.end());
auto& buf = p.bin_buffers.back();
auto& dst = p.member_bin_attrs[i++];
dst = OrbisNpMatching2RoomMemberBinAttrInternal{};
dst.binAttr.id = bin.id;
dst.binAttr.data = buf.empty() ? nullptr : buf.data();
dst.binAttr.dataSize = buf.size();
}
m.roomGroup = p.room_groups.empty() ? nullptr : p.room_groups.data();
m.roomMemberBinAttrInternal = p.member_bin_attrs.empty() ? nullptr : p.member_bin_attrs.data();
m.roomMemberBinAttrInternalNum = p.member_bin_attrs.size();
@ -308,7 +351,7 @@ void HandleRoomEvent(const ShadNet::NotifyRoomEvent& n) {
std::strncpy(pi.online_id.data, n.member_npid.c_str(), sizeof(pi.online_id.data) - 1);
ctx->peers[member_id] = pi;
BuildMemberUpdate(p, room_it->second, mc, cause);
BuildMemberUpdate(p, room_it->second, mc, cause, ctx->a_variant);
break;
}
case ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT: {
@ -320,7 +363,7 @@ void HandleRoomEvent(const ShadNet::NotifyRoomEvent& n) {
if (mem_it == room_it->second.members.end()) {
return;
}
BuildMemberUpdate(p, room_it->second, mem_it->second, cause);
BuildMemberUpdate(p, room_it->second, mem_it->second, cause, ctx->a_variant);
QueueMatching2SignalingEvent(*ctx, room_id, member_id,
ORBIS_NP_MATCHING2_SIGNALING_EVENT_DEAD,
ORBIS_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER);
@ -463,17 +506,35 @@ void HandleRoomEvent(const ShadNet::NotifyRoomEvent& n) {
LOG_DEBUG(Lib_NpMatching2, "RoomEvent ctx={} room={} event={:#x} cause={}", n.ctx_id, n.room_id,
n.event, n.event_cause);
OrbisNpMatching2Event fired_event = event;
if (ctx->a_variant) {
switch (event) {
case ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED:
fired_event = ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED_A;
break;
case ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT:
fired_event = ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT_A;
break;
case ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_MEMBER_DATA_INTERNAL:
fired_event = ORBIS_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_MEMBER_DATA_INTERNAL_A;
break;
default:
break;
}
}
PendingEvent ev{};
ev.type = PendingEvent::ROOM_EVENT_CB;
ev.ctx_id = ctx->ctx_id;
ev.fire_at = std::chrono::steady_clock::now();
ev.room_id = room_id;
ev.room_event = event;
ev.room_event = fired_event;
ev.room_event_data = p.room_event_data;
ScheduleEvent(std::move(ev));
if (event == ORBIS_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED) {
StartMatching2PeerHandshake(*ctx, room_id, member_id);
QueueMatching2EstablishedForRoomPeers(*ctx, room_id);
}
}
@ -780,7 +841,7 @@ s32 MmGetWorldInfoList(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2Request
}
s32 MmSearchRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2SearchRoomRequest& request) {
const OrbisNpMatching2SearchRoomRequest& request, bool a_variant) {
shadnet::SearchRoomRequest req;
req.set_world_id(request.worldId);
req.set_lobby_id(request.lobbyId);
@ -814,8 +875,29 @@ s32 MmSearchRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req
for (u64 i = 0; i < request.attrs; ++i) {
req.add_attr_ids(request.attr[i]);
}
return MmSubmitRequest(ctx_id, req_id, ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM,
MmCommand::SearchRoom, MakeProtoPayload(req));
return MmSubmitRequest(ctx_id, req_id,
a_variant ? ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM_A
: ORBIS_NP_MATCHING2_REQUEST_EVENT_SEARCH_ROOM,
MmCommand::SearchRoom, MakeProtoPayload(req), a_variant);
}
s32 MmGetRoomDataExternalList(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2GetRoomDataExternalListRequest& request,
bool a_variant) {
shadnet::GetRoomDataExternalListRequest req;
for (u64 i = 0; i < request.roomIdNum; ++i) {
req.add_room_ids(request.roomId[i]);
}
for (u64 i = 0; i < request.attrIdNum; ++i) {
req.add_attr_ids(request.attrId[i]);
}
LOG_DEBUG(Lib_NpMatching2, "getRoomDataExternalList roomN={} attrN={}", request.roomIdNum,
request.attrIdNum);
return MmSubmitRequest(ctx_id, req_id,
a_variant
? ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST_A
: ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST,
MmCommand::GetRoomDataExternalList, MakeProtoPayload(req), a_variant);
}
s32 MmSetRoomDataInternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,

View File

@ -9,7 +9,6 @@
#include "common/types.h"
#include "core/libraries/np/np_matching2/np_matching2.h"
#include "core/libraries/np/np_matching2/np_matching2_types.h"
namespace ShadNet {
class ShadNetClient;
@ -31,6 +30,7 @@ enum class MmCommand : u16 {
SetRoomDataExternal = 21,
KickoutRoomMember = 22,
GetWorldInfoList = 23,
GetRoomDataExternalList = 24,
};
void SetMmShadNetClient(std::shared_ptr<ShadNet::ShadNetClient> client,
@ -61,7 +61,10 @@ s32 MmLeaveRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_
s32 MmGetWorldInfoList(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2GetWorldInfoListRequest& request);
s32 MmSearchRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2SearchRoomRequest& request);
const OrbisNpMatching2SearchRoomRequest& request, bool a_variant = false);
s32 MmGetRoomDataExternalList(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2GetRoomDataExternalListRequest& request,
bool a_variant = false);
s32 MmSetRoomDataInternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
const OrbisNpMatching2SetRoomDataInternalRequest& request);
s32 MmSetRoomDataExternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,

View File

@ -416,6 +416,20 @@ void StartMatching2SignalingForRoomPeers(ContextObject& ctx, OrbisNpMatching2Roo
}
}
void QueueMatching2EstablishedForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id) {
const auto room_it = ctx.room_cache.find(room_id);
if (room_it == ctx.room_cache.end()) {
return;
}
for (const auto& [member_id, member] : room_it->second.members) {
if (member_id == 0 || member_id == ctx.my_member_id) {
continue;
}
MarkMatching2PeerActive(ctx, room_id, member_id, member.addr, member.port);
}
}
void QueueMatching2DeadForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
s32 error_code) {
auto room_it = ctx.room_cache.find(room_id);

View File

@ -18,6 +18,7 @@ bool SendMatching2StunPing(const ContextObject& ctx);
void StartMatching2PeerHandshake(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
OrbisNpMatching2RoomMemberId member_id);
void StartMatching2SignalingForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id);
void QueueMatching2EstablishedForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id);
void QueueMatching2DeadForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
s32 error_code);
void QueueMatching2SignalingEvent(ContextObject& ctx, OrbisNpMatching2RoomId room_id,

View File

@ -147,6 +147,8 @@ s32 PS4_SYSV_ABI sceNpSignalingCreateContext(const void* npId, void* callback, v
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
}
const bool transport_ready = Stubs::EnsureTransport();
s32 ctx_id = 0;
{
SignalingMutexGuard lock;
@ -177,7 +179,7 @@ s32 PS4_SYSV_ABI sceNpSignalingCreateContext(const void* npId, void* callback, v
fmt::ptr(callbackArg), ctx.compiled_sdk_version, ctx.bound_port);
}
if (Stubs::TransportIsReady()) {
if (transport_ready) {
SendStunPing(ctx_id);
}
return ORBIS_OK;
@ -203,6 +205,8 @@ s32 PS4_SYSV_ABI sceNpSignalingCreateContextA(s32 userId, void* callback, void*
// Account id isn't needed without matchmaking wired up; leave it 0 for now.
const OrbisNpAccountId account_id = 0;
const bool transport_ready = Stubs::EnsureTransport();
s32 ctx_id = 0;
{
SignalingMutexGuard lock;
@ -234,7 +238,7 @@ s32 PS4_SYSV_ABI sceNpSignalingCreateContextA(s32 userId, void* callback, void*
OnlineIdToString(ctx.owner_online_id), account_id);
}
if (Stubs::TransportIsReady()) {
if (transport_ready) {
SendStunPing(ctx_id);
}
return ORBIS_OK;
@ -297,6 +301,8 @@ s32 PS4_SYSV_ABI sceNpSignalingActivateConnection(OrbisNpSignalingContextId ctxI
s32 cid = 0;
bool reused_established = false;
bool queue_activation = false;
bool start_handshake = true;
{
SignalingMutexGuard lock;
if (!g_initialized) {
@ -322,12 +328,18 @@ s32 PS4_SYSV_ABI sceNpSignalingActivateConnection(OrbisNpSignalingContextId ctxI
} else if (conn_it != g_connections.end()) {
cid = existing_it->second;
ConnectionInfo& ci = conn_it->second;
const bool was_locally_activated = ci.locally_activated;
ci.locally_activated = true;
if (ci.state == ConnState::Established) {
ClearLingerAndTimeoutLocked(cid);
reused_established = true;
start_handshake = false;
} else {
ClearLingerAndTimeoutLocked(cid);
start_handshake = true;
}
if (!was_locally_activated) {
queue_activation = true;
}
}
}
@ -352,23 +364,30 @@ s32 PS4_SYSV_ABI sceNpSignalingActivateConnection(OrbisNpSignalingContextId ctxI
}
if (created_new) {
ArmConnectTimeoutLocked(cid);
QueueActivationLocked(cid, peer_online_id_str);
queue_activation = true;
start_handshake = true;
}
if (queue_activation) {
QueueActivationLocked(cid, peer_online_id_str, start_handshake);
}
LOG_INFO(Lib_NpSignaling, "ctxId={} peer='{}' connId={} Status: {}", ctxId,
peer_online_id_str, cid,
created_new ? "queued, async"
: reused_established ? "reused established"
: reused_established ? "queued local activation on established connection"
: queue_activation ? "queued local activation on existing connection"
: "reused transient");
}
*outConnId = cid;
if (reused_established) {
EstablishConnection(cid, false);
if (queue_activation) {
g_dispatch_cv.notify_all();
return ORBIS_OK;
}
g_dispatch_cv.notify_all();
if (reused_established) {
EstablishConnection(cid, false);
}
return ORBIS_OK;
}

View File

@ -6,6 +6,7 @@
#include <string>
#include "common/types.h"
#include "core/libraries/np/np_types2.h"
namespace Core::Loader {
class SymbolsResolver;
@ -13,66 +14,6 @@ class SymbolsResolver;
namespace Libraries::Np::NpSignaling {
using OrbisNpSignalingContextId = s32;
using OrbisNpSignalingConnectionId = s32;
using OrbisNpSignalingRequestId = u32;
using OrbisNpSignalingHandler = PS4_SYSV_ABI void (*)(u32 ctxId, u32 connId, s32 event,
s32 errorCode, void* userArg);
constexpr s32 ORBIS_NP_SIGNALING_EVENT_DEAD = 0;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_ESTABLISHED = 1;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_NETINFO_ERROR = 2;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_NETINFO_RESULT = 3;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_PEER_ACTIVATED = 10;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_PEER_DEACTIVATED = 11;
constexpr s32 ORBIS_NP_SIGNALING_EVENT_MUTUAL_ACTIVATED = 12;
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE = 0;
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_PENDING = 1;
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_ACTIVE = 2;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_RTT = 1;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_BANDWIDTH = 2;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_NP_ID = 3;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_ADDR = 4;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_MAPPED_ADDR = 5;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PACKET_LOSS = 6;
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_ADDRESS_A = 7;
constexpr s32 ORBIS_NP_SIGNALING_CONTEXT_OPTION_FLAG = 1;
struct OrbisNpSignalingNetInfo {
u64 size;
u32 localAddr;
u32 mappedAddr;
s32 natStatus;
u32 _pad_14;
};
static_assert(sizeof(OrbisNpSignalingNetInfo) == 0x18);
struct OrbisNpSignalingAccountPlatformPair {
u64 accountId;
u32 platformType;
u32 _pad_0c;
};
static_assert(sizeof(OrbisNpSignalingAccountPlatformPair) == 0x10);
struct OrbisNpSignalingMemoryInfo {
u64 currentInUse;
u64 peakInUse;
u64 maxSystemSize;
};
static_assert(sizeof(OrbisNpSignalingMemoryInfo) == 0x18);
struct OrbisNpSignalingConnectionStatistics {
u32 peakConnectionCount;
u32 activeConnectionCount;
u32 transientConnectionCount;
u32 establishedConnectionCount;
};
static_assert(sizeof(OrbisNpSignalingConnectionStatistics) == 0x10);
s32 PS4_SYSV_ABI sceNpSignalingInitialize(s64 memorySize, s32 threadPriority, s32 cpuAffinityMask,
s64 threadStackSize);
s32 PS4_SYSV_ABI sceNpSignalingTerminate();

View File

@ -370,7 +370,7 @@ static void StopReceiveThread() {
static void PingThreadMain() {
while (!g_ping_stop) {
if (!Stubs::TransportIsReady()) {
if (!Stubs::EnsureTransport()) {
std::this_thread::sleep_for(std::chrono::milliseconds(kSigRetryMs));
continue;
}
@ -400,6 +400,7 @@ static void PingThreadMain() {
StunPing ping{};
ping.cmd = 0x01;
std::memcpy(ping.online_id, cs.online_id.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
ping.local_ip = Stubs::AdvertisedAddr();
Stubs::SignalingSendTo(&ping, sizeof(ping), server_addr, server_port);
}

View File

@ -897,8 +897,9 @@ void StartHandshakeInitiator(OrbisNpSignalingConnectionId conn_id) {
}
}
void QueueActivationLocked(OrbisNpSignalingConnectionId conn_id, std::string_view peer_online_id) {
g_pending_activations.push_back({conn_id, std::string(peer_online_id)});
void QueueActivationLocked(OrbisNpSignalingConnectionId conn_id, std::string_view peer_online_id,
bool start_handshake) {
g_pending_activations.push_back({conn_id, std::string(peer_online_id), start_handshake});
}
void ProcessPendingActivations() {
@ -912,6 +913,7 @@ void ProcessPendingActivations() {
}
for (const PendingActivation& act : work) {
bool already_established = false;
{
SignalingMutexGuard lock;
const auto it = g_connections.find(act.conn_id);
@ -940,8 +942,16 @@ void ProcessPendingActivations() {
it->second.addr = peer_addr;
it->second.port = peer_port;
SendActivationRequestLocked(it->second);
already_established = it->second.state == ConnState::Established;
LOG_INFO(Lib_NpSignaling, "connection {} sent local activation to '{}' at {:#x}:{}{}",
act.conn_id, act.peer_online_id, peer_addr, sceNetNtohs(peer_port),
act.start_handshake ? "" : " (existing connection)");
}
if (act.start_handshake) {
StartHandshakeInitiator(act.conn_id);
} else if (already_established) {
EstablishConnection(act.conn_id, false);
}
StartHandshakeInitiator(act.conn_id);
}
}
@ -1154,11 +1164,16 @@ void SendActivationRequestLocked(const ConnectionInfo& ci) {
void SendControlCloseLocked(const ConnectionInfo& ci, ControlReason reason) {
if (ci.addr == 0 || ci.port == 0) {
LOG_WARNING(Lib_NpSignaling,
"Control Close SEND skipped: connId={} reason={} unresolved endpoint",
ci.conn_id, static_cast<u16>(reason));
return;
}
SignalingControl pkt = MakeControlLocked(ci, ControlKind::Close);
pkt.reason = static_cast<u16>(reason);
Stubs::ControlSendTo(&pkt, sizeof(pkt), ci.addr, ci.port);
const int rc = Stubs::ControlSendTo(&pkt, sizeof(pkt), ci.addr, ci.port);
LOG_INFO(Lib_NpSignaling, "Control Close SEND: connId={} reason={} dst={:#x}:{} rc={}",
ci.conn_id, static_cast<u16>(reason), ci.addr, sceNetNtohs(ci.port), rc);
}
void HandleControlPacket(u32 from_addr, u16 from_port, const SignalingControl& pkt) {
@ -1236,6 +1251,9 @@ void HandleControlPacket(u32 from_addr, u16 from_port, const SignalingControl& p
ack_addr = ci.addr;
ack_port = ci.port;
} else if (conn_id == 0) {
LOG_INFO(Lib_NpSignaling,
"Control RECV ignored: kind={} from='{}' src={:#x}:{} no matching connection",
pkt.kind, from_id, from_addr, sceNetNtohs(from_port));
return;
} else if (kind == ControlKind::ActivationAck) {
ConnectionInfo& ci = g_connections[conn_id];
@ -1252,6 +1270,10 @@ void HandleControlPacket(u32 from_addr, u16 from_port, const SignalingControl& p
} else if (kind == ControlKind::Close) {
ConnectionInfo& ci = g_connections[conn_id];
const ControlReason reason = static_cast<ControlReason>(pkt.reason);
LOG_INFO(Lib_NpSignaling,
"Control Close RECV: connId={} from='{}' reason={} src={:#x}:{} state={}",
conn_id, from_id, pkt.reason, from_addr, sceNetNtohs(from_port),
static_cast<s32>(ci.state));
if (reason == ControlReason::Deactivate && ci.state == ConnState::Established) {
peer_deactivated_conn = conn_id;
} else {
@ -1290,7 +1312,7 @@ void SendStunPing(s32 ctx_id) {
online_id = it->second.owner_online_id;
}
if (!Stubs::TransportIsReady()) {
if (!Stubs::EnsureTransport()) {
return;
}
@ -1306,9 +1328,10 @@ void SendStunPing(s32 ctx_id) {
StunPing ping{};
ping.cmd = 0x01;
std::memcpy(ping.online_id, online_id.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
ping.local_ip = Stubs::AdvertisedAddr();
LOG_DEBUG(Lib_NpSignaling, "ctxId={} online_id='{}' server={:#x}:{}", ctx_id,
OnlineIdToString(online_id), server_addr, sceNetNtohs(server_udp));
LOG_DEBUG(Lib_NpSignaling, "ctxId={} online_id='{}' server={:#x}:{} local_ip={:#x}", ctx_id,
OnlineIdToString(online_id), server_addr, sceNetNtohs(server_udp), ping.local_ip);
Stubs::SignalingSendTo(&ping, sizeof(ping), server_addr, server_udp);
}

View File

@ -253,6 +253,7 @@ extern std::unordered_map<s32, PeerNetInfoResult> g_peer_netinfo_results;
struct PendingActivation {
OrbisNpSignalingConnectionId conn_id = 0;
std::string peer_online_id;
bool start_handshake = true;
};
extern std::vector<PendingActivation> g_pending_activations;
extern u32 g_peer_netinfo_next_id;
@ -331,7 +332,8 @@ void TerminateConnectionFaithful(OrbisNpSignalingConnectionId conn_id);
void StartHandshakeInitiator(OrbisNpSignalingConnectionId conn_id);
void QueueActivationLocked(OrbisNpSignalingConnectionId conn_id, std::string_view peer_online_id);
void QueueActivationLocked(OrbisNpSignalingConnectionId conn_id, std::string_view peer_online_id,
bool start_handshake = true);
void ProcessPendingActivations();
void HandleHandshakePacket(u32 from_addr, u16 from_port, const SignalingHandshake& pkt);

View File

@ -279,6 +279,8 @@ message MatchingRoomDataExternal {
repeated MatchingBinAttr external_search_bin_attrs = 16;
repeated MatchingBinAttr external_bin_attrs = 17;
string owner_npid = 18;
uint64 owner_account_id = 19;
uint32 owner_platform = 20;
}
message CreateJoinRoomResponse {
@ -433,6 +435,15 @@ message SearchRoomReply {
uint32 range_result = 4;
}
message GetRoomDataExternalListRequest {
repeated uint64 room_ids = 1;
repeated uint32 attr_ids = 2;
}
message GetRoomDataExternalListReply {
repeated MatchingRoomDataExternal rooms = 1;
}
message MatchingWorld {
uint32 world_id = 1;
uint32 lobbies_num = 2;