mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-10 10:14:44 -06:00
Matching2 P6: Public API additions, Stub Additions, networking layer stubs, more type additions, more struct additions, matching2signaling work. (#4654)
This commit is contained in:
parent
b6026cc65d
commit
9756843860
@ -85,4 +85,44 @@ int P2PSocket::fstat(Libraries::Kernel::OrbisKernelStat* stat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 GetP2PConfiguredPort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetP2PAdvertisedAddr() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EnsureP2PTransport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool P2PTransportIsReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int P2PSignalingSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PSignalingRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PControlSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PControlRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PMatching2SendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PMatching2RecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
||||
@ -179,4 +179,15 @@ struct UnixSocket : public Socket {
|
||||
}
|
||||
};
|
||||
|
||||
u16 GetP2PConfiguredPort();
|
||||
u32 GetP2PAdvertisedAddr();
|
||||
bool EnsureP2PTransport();
|
||||
bool P2PTransportIsReady();
|
||||
int P2PSignalingSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int P2PSignalingRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
int P2PControlSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int P2PControlRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
int P2PMatching2SendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int P2PMatching2RecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
|
||||
} // namespace Libraries::Net
|
||||
@ -8,6 +8,7 @@
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/emulator_settings.h"
|
||||
#include "core/libraries/network/net_upnp.h"
|
||||
#include "core/libraries/np/np_error.h"
|
||||
#include "core/libraries/np/np_manager.h"
|
||||
#include "core/libraries/np/np_matching2/np_matching2_mm.h"
|
||||
@ -177,6 +178,9 @@ bool NpHandler::ConnectUser(s32 user_id, const std::string& host, u16 port, cons
|
||||
// Seed the current Appear-Offline preference so the login packet carries it (the send
|
||||
// is suppressed pre-auth; it just caches on the client).
|
||||
client->SetAppearOffline(m_appear_offline.load());
|
||||
if (EmulatorSettings.IsUPnPEnabled()) {
|
||||
Net::UPnPClient::Instance().Start();
|
||||
}
|
||||
client->Start(host, port, npid, password, token);
|
||||
|
||||
const ShadNet::ShadNetState conn_state = client->WaitForConnection();
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/emulator_settings.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/np/np_handler.h"
|
||||
#include "core/libraries/np/np_manager.h"
|
||||
#include "core/libraries/np/np_matching2/np_matching2.h"
|
||||
@ -57,13 +59,185 @@ int PS4_SYSV_ABI sceNpMatching2CreateContextA(const OrbisNpMatching2CreateContex
|
||||
return ContextManager::Instance().CreateContext(&np_id, param->serviceLabel, ctxId);
|
||||
}
|
||||
|
||||
static void StoreRequestCallback(ContextObject* ctx, OrbisNpMatching2RequestOptParam* requestOpt) {
|
||||
static void StoreRequestCallback(ContextObject* ctx,
|
||||
const OrbisNpMatching2RequestOptParam* requestOpt) {
|
||||
if (requestOpt && requestOpt->callback) {
|
||||
ctx->default_request_callback = requestOpt->callback;
|
||||
ctx->default_request_callback_arg = requestOpt->arg;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 GetRoomPingUs(const ContextObject& ctx, OrbisNpMatching2RoomId roomId) {
|
||||
const auto room_it = ctx.room_cache.find(roomId);
|
||||
if (room_it == ctx.room_cache.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 total_ping = 0;
|
||||
u32 ping_count = 0;
|
||||
for (const auto& [member_id, member] : room_it->second.members) {
|
||||
if (member_id == ctx.my_member_id) {
|
||||
continue;
|
||||
}
|
||||
const auto peer_it = ctx.peers.find(member_id);
|
||||
if (peer_it == ctx.peers.end() || peer_it->second.ping_us == 0) {
|
||||
continue;
|
||||
}
|
||||
total_ping += peer_it->second.ping_us;
|
||||
++ping_count;
|
||||
}
|
||||
|
||||
return ping_count == 0 ? 0 : static_cast<u32>(total_ping / ping_count);
|
||||
}
|
||||
|
||||
static void* BuildSignalingGetPingInfoPayload(ContextObject& ctx, OrbisNpMatching2RoomId roomId) {
|
||||
CallbackPayload& p = ctx.request_payload;
|
||||
p.Reset();
|
||||
|
||||
const auto room_it = ctx.room_cache.find(roomId);
|
||||
p.ping_info_response = std::make_unique<OrbisNpMatching2SignalingGetPingInfoResponse>();
|
||||
auto& out = *p.ping_info_response;
|
||||
out = {};
|
||||
if (room_it != ctx.room_cache.end()) {
|
||||
out.serverId = room_it->second.server_id;
|
||||
out.worldId = room_it->second.world_id;
|
||||
out.roomId = room_it->second.room_id;
|
||||
} else {
|
||||
out.serverId = ctx.server_id;
|
||||
out.worldId = ctx.world_id;
|
||||
out.roomId = roomId;
|
||||
}
|
||||
out.rtt = GetRoomPingUs(ctx, roomId);
|
||||
|
||||
p.request_data = p.ping_info_response.get();
|
||||
return p.request_data;
|
||||
}
|
||||
|
||||
static Libraries::Np::OrbisNpId MakePeerNpId(const PeerInfo* peer, const MemberCache* member) {
|
||||
Libraries::Np::OrbisNpId npid{};
|
||||
if (member) {
|
||||
npid = member->np_id;
|
||||
} else if (peer) {
|
||||
npid.handle = peer->online_id;
|
||||
}
|
||||
return npid;
|
||||
}
|
||||
|
||||
static u64 StableAccountIdFromNpId(const Libraries::Np::OrbisNpId& npid) {
|
||||
u64 hash = 1469598103934665603ULL;
|
||||
for (const char c : npid.handle.data) {
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
hash ^= static_cast<u8>(c);
|
||||
hash *= 1099511628211ULL;
|
||||
}
|
||||
return hash == 0 ? 1 : hash;
|
||||
}
|
||||
|
||||
static Libraries::Np::OrbisNpPeerAddressA MakePeerAddressA(const PeerInfo* peer,
|
||||
const MemberCache* member) {
|
||||
const Libraries::Np::OrbisNpId npid = MakePeerNpId(peer, member);
|
||||
Libraries::Np::OrbisNpPeerAddressA addr{};
|
||||
addr.accountId = StableAccountIdFromNpId(npid);
|
||||
addr.platform = Libraries::Np::OrbisNpPlatformType::PS4;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static s32 FillMatching2ConnectionInfo(const ContextObject& ctx, OrbisNpMatching2RoomId roomId,
|
||||
OrbisNpMatching2RoomMemberId memberId, u32 infoType,
|
||||
void* connInfo, bool a_variant) {
|
||||
if (!connInfo) {
|
||||
LOG_ERROR(Lib_NpMatching2, "connInfo null");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const auto room_it = ctx.room_cache.find(roomId);
|
||||
if (room_it == ctx.room_cache.end()) {
|
||||
LOG_INFO(Lib_NpMatching2, "room={} not cached for connection info", roomId);
|
||||
if (a_variant) {
|
||||
*static_cast<OrbisNpMatching2SignalingConnectionInfoA*>(connInfo) = {};
|
||||
} else {
|
||||
*static_cast<OrbisNpMatching2SignalingConnectionInfo*>(connInfo) = {};
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
const auto member_it = room_it->second.members.find(memberId);
|
||||
const MemberCache* member =
|
||||
member_it != room_it->second.members.end() ? &member_it->second : nullptr;
|
||||
const auto peer_it = ctx.peers.find(memberId);
|
||||
const PeerInfo* peer = peer_it != ctx.peers.end() ? &peer_it->second : nullptr;
|
||||
|
||||
if (a_variant) {
|
||||
auto* out = static_cast<OrbisNpMatching2SignalingConnectionInfoA*>(connInfo);
|
||||
*out = {};
|
||||
switch (infoType) {
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_RTT:
|
||||
out->rtt = peer ? peer->ping_us : 0;
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_BANDWIDTH:
|
||||
out->bandwidth = 0;
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_ADDR:
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_MAPPED_ADDR:
|
||||
if (peer) {
|
||||
out->address.addr = peer->addr;
|
||||
out->address.port = peer->port;
|
||||
} else if (member) {
|
||||
out->address.addr = member->addr;
|
||||
out->address.port = member->port;
|
||||
}
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PACKET_LOSS:
|
||||
out->packetLoss = 0;
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_ADDRESS_A:
|
||||
out->peerAddrA = MakePeerAddressA(peer, member);
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING(Lib_NpMatching2, "unsupported connection info A type={}", infoType);
|
||||
return ORBIS_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
} else {
|
||||
auto* out = static_cast<OrbisNpMatching2SignalingConnectionInfo*>(connInfo);
|
||||
*out = {};
|
||||
switch (infoType) {
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_RTT:
|
||||
out->rtt = peer ? peer->ping_us : 0;
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_BANDWIDTH:
|
||||
out->bandwidth = 0;
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_NP_ID:
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_NPID:
|
||||
out->npId = MakePeerNpId(peer, member);
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PEER_ADDR:
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_MAPPED_ADDR:
|
||||
if (peer) {
|
||||
out->address.addr = peer->addr;
|
||||
out->address.port = peer->port;
|
||||
} else if (member) {
|
||||
out->address.addr = member->addr;
|
||||
out->address.port = member->port;
|
||||
}
|
||||
break;
|
||||
case ORBIS_NP_MATCHING2_SIGNALING_CONN_INFO_PACKET_LOSS:
|
||||
out->packetLoss = 0;
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING(Lib_NpMatching2, "unsupported connection info type={}", infoType);
|
||||
return ORBIS_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpMatching2, "connection info{}: ctx={} room={} member={} type={} rtt={}",
|
||||
a_variant ? "A" : "", ctx.ctx_id, roomId, memberId, infoType,
|
||||
peer ? peer->ping_us : 0);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2CreateJoinRoom(OrbisNpMatching2ContextId ctxId,
|
||||
OrbisNpMatching2CreateJoinRoomRequest* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt,
|
||||
@ -479,9 +653,9 @@ int PS4_SYSV_ABI sceNpMatching2SendRoomMessage(OrbisNpMatching2ContextId ctxId,
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SetRoomDataExternal(OrbisNpMatching2ContextId ctxId, void* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt,
|
||||
OrbisNpMatching2RequestId* requestId) {
|
||||
int PS4_SYSV_ABI sceNpMatching2SetRoomDataExternal(
|
||||
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2SetRoomDataExternalRequest* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt, OrbisNpMatching2RequestId* requestId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, requestOpt = {}", ctxId, fmt::ptr(requestOpt));
|
||||
|
||||
if (!g_initialized) {
|
||||
@ -500,14 +674,15 @@ int PS4_SYSV_ABI sceNpMatching2SetRoomDataExternal(OrbisNpMatching2ContextId ctx
|
||||
}
|
||||
|
||||
StoreRequestCallback(ctx, requestOpt);
|
||||
*requestId = AllocRequestId();
|
||||
LOG_WARNING(Lib_NpMatching2, "not implemented");
|
||||
const OrbisNpMatching2RequestId reqId = AllocRequestId();
|
||||
*requestId = reqId;
|
||||
MmSetRoomDataExternal(ctxId, reqId, *request);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SetRoomDataInternal(OrbisNpMatching2ContextId ctxId, void* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt,
|
||||
OrbisNpMatching2RequestId* requestId) {
|
||||
int PS4_SYSV_ABI sceNpMatching2SetRoomDataInternal(
|
||||
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2SetRoomDataInternalRequest* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt, OrbisNpMatching2RequestId* requestId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, requestOpt = {}", ctxId, fmt::ptr(requestOpt));
|
||||
|
||||
if (!g_initialized) {
|
||||
@ -526,8 +701,415 @@ int PS4_SYSV_ABI sceNpMatching2SetRoomDataInternal(OrbisNpMatching2ContextId ctx
|
||||
}
|
||||
|
||||
StoreRequestCallback(ctx, requestOpt);
|
||||
*requestId = AllocRequestId();
|
||||
LOG_WARNING(Lib_NpMatching2, "not implemented");
|
||||
const OrbisNpMatching2RequestId reqId = AllocRequestId();
|
||||
*requestId = reqId;
|
||||
MmSetRoomDataInternal(ctxId, reqId, *request);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpMatching2SignalingGetConnectionStatus(OrbisNpMatching2ContextId ctxId,
|
||||
OrbisNpMatching2RoomId roomId,
|
||||
OrbisNpMatching2RoomMemberId memberId,
|
||||
s32* connStatus, void* peerAddr,
|
||||
u16* peerPort) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, roomId = {}, memberId = {}", ctxId, roomId,
|
||||
memberId);
|
||||
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
|
||||
if (!ctx) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
constexpr s32 kInactive = 0;
|
||||
constexpr s32 kPending = 1;
|
||||
constexpr s32 kActive = 2;
|
||||
const auto room_it = ctx->room_cache.find(roomId);
|
||||
const bool in_room = room_it != ctx->room_cache.end() &&
|
||||
room_it->second.members.find(memberId) != room_it->second.members.end();
|
||||
|
||||
if (!in_room) {
|
||||
if (connStatus) {
|
||||
*connStatus = kInactive;
|
||||
}
|
||||
LOG_INFO(Lib_NpMatching2, "member={} is not in room={}, status=inactive", memberId, roomId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
auto peer_it = ctx->peers.find(memberId);
|
||||
if (peer_it == ctx->peers.end()) {
|
||||
PeerInfo pi{};
|
||||
pi.member_id = memberId;
|
||||
pi.status = kPending;
|
||||
const auto member_it = room_it->second.members.find(memberId);
|
||||
if (member_it != room_it->second.members.end()) {
|
||||
pi.addr = member_it->second.addr;
|
||||
pi.port = member_it->second.port;
|
||||
std::strncpy(pi.online_id.data, member_it->second.np_id.handle.data,
|
||||
sizeof(pi.online_id.data) - 1);
|
||||
}
|
||||
peer_it = ctx->peers.emplace(memberId, pi).first;
|
||||
}
|
||||
|
||||
const s32 status = peer_it->second.status == kActive ? kActive : kPending;
|
||||
if (connStatus) {
|
||||
*connStatus = status;
|
||||
}
|
||||
if (peerAddr) {
|
||||
*reinterpret_cast<u32*>(peerAddr) = peer_it->second.addr;
|
||||
}
|
||||
if (peerPort) {
|
||||
*peerPort = peer_it->second.port;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpMatching2, "member={} is in room={}, status={} addr={:#x}:{}", memberId, roomId,
|
||||
status, peer_it->second.addr, Libraries::Net::sceNetNtohs(peer_it->second.port));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2AbortContextStart(OrbisNpMatching2ContextId ctxId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2DestroyContext(OrbisNpMatching2ContextId ctxId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!ContextManager::Instance().Destroy(ctxId)) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2RegisterLobbyMessageCallback(
|
||||
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2LobbyMessageCallback callback,
|
||||
void* userdata) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, userdata = {}", ctxId, userdata);
|
||||
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
|
||||
if (!ctx) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
ctx->lobby_message_callback = callback;
|
||||
ctx->lobby_message_callback_arg = userdata;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2RegisterRoomMessageCallback(
|
||||
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2RoomMessageCallback callback, void* userdata) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, userdata = {}", ctxId, userdata);
|
||||
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
|
||||
if (!ctx) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
ctx->room_message_callback = callback;
|
||||
ctx->room_message_callback_arg = userdata;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetMemoryInfo() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetSslMemoryInfo() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomMemberIdListLocal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomPasswordLocal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetSignalingOptParamLocal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetLobbyInfoList() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetLobbyMemberDataInternal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetLobbyMemberDataInternalList() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomDataExternalList() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomDataInternal(
|
||||
OrbisNpMatching2ContextId ctxId, OrbisNpMatching2GetRoomDataInternalRequest* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt, OrbisNpMatching2RequestId* requestId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, requestOpt = {}", ctxId, fmt::ptr(requestOpt));
|
||||
|
||||
if (!g_initialized) {
|
||||
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;
|
||||
|
||||
void* request_data = BuildGetRoomDataInternalPayload(*ctx, request->roomId);
|
||||
|
||||
PendingEvent ev{};
|
||||
ev.type = PendingEvent::REQUEST_CB;
|
||||
ev.ctx_id = ctxId;
|
||||
ev.fire_at = std::chrono::steady_clock::now();
|
||||
ev.req_id = reqId;
|
||||
ev.req_event = ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_INTERNAL;
|
||||
ev.error_code = 0;
|
||||
ev.request_cb = ctx->default_request_callback;
|
||||
ev.request_cb_arg = ctx->default_request_callback_arg;
|
||||
ev.request_data = request_data;
|
||||
ScheduleEvent(std::move(ev));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomMemberDataExternalList() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetRoomMemberDataInternal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetUserInfoListA() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GetUserInfoList() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2GrantRoomOwner(OrbisNpMatching2ContextId ctxId, void* reqParam,
|
||||
void* optParam, s32* reqId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2JoinLobby(OrbisNpMatching2ContextId ctxId, void* reqParam,
|
||||
void* optParam, s32* reqId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2JoinRoomA(OrbisNpMatching2ContextId ctxId, void* reqParam,
|
||||
void* optParam, s32* reqId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2KickoutRoomMember(OrbisNpMatching2ContextId ctxId,
|
||||
OrbisNpMatching2KickoutRoomMemberRequest* request,
|
||||
OrbisNpMatching2RequestOptParam* requestOpt,
|
||||
OrbisNpMatching2RequestId* requestId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, requestOpt = {}", ctxId, fmt::ptr(requestOpt));
|
||||
|
||||
if (!g_initialized) {
|
||||
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;
|
||||
MmKickoutRoomMember(ctxId, reqId, *request);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2LeaveLobby() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SendLobbyChatMessage() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SendRoomChatMessage(OrbisNpMatching2ContextId ctxId, void* reqParam,
|
||||
void* optParam, s32* reqId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SetLobbyMemberDataInternal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SetRoomMemberDataInternal() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SetSignalingOptParam() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetPeerNetInfo() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetPingInfo(OrbisNpMatching2ContextId ctxId,
|
||||
const void* reqParam, const void* optParam,
|
||||
s32* reqId) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!reqParam || !reqId) {
|
||||
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;
|
||||
}
|
||||
|
||||
const auto* request = static_cast<const OrbisNpMatching2SignalingGetPingInfoRequest*>(reqParam);
|
||||
StoreRequestCallback(ctx, static_cast<const OrbisNpMatching2RequestOptParam*>(optParam));
|
||||
const OrbisNpMatching2RequestId request_id = AllocRequestId();
|
||||
*reqId = request_id;
|
||||
|
||||
const bool room_found = ctx->room_cache.find(request->roomId) != ctx->room_cache.end();
|
||||
void* request_data =
|
||||
room_found ? BuildSignalingGetPingInfoPayload(*ctx, request->roomId) : nullptr;
|
||||
|
||||
PendingEvent ev{};
|
||||
ev.type = PendingEvent::REQUEST_CB;
|
||||
ev.ctx_id = ctxId;
|
||||
ev.fire_at = std::chrono::steady_clock::now();
|
||||
ev.req_id = request_id;
|
||||
ev.req_event = ORBIS_NP_MATCHING2_REQUEST_EVENT_SIGNALING_GET_PING_INFO;
|
||||
ev.error_code = room_found ? ORBIS_OK : ORBIS_NP_MATCHING2_ERROR_ROOM_NOT_FOUND;
|
||||
ev.request_cb = ctx->default_request_callback;
|
||||
ev.request_cb_arg = ctx->default_request_callback_arg;
|
||||
ev.request_data = request_data;
|
||||
ScheduleEvent(std::move(ev));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingCancelPeerNetInfo() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetConnectionInfoA(OrbisNpMatching2ContextId ctxId,
|
||||
OrbisNpMatching2RoomId roomId,
|
||||
OrbisNpMatching2RoomMemberId memberId,
|
||||
u32 infoType, void* connInfo) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, roomId = {}, memberId = {}", ctxId, roomId,
|
||||
memberId);
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
|
||||
if (!ctx) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
return FillMatching2ConnectionInfo(*ctx, roomId, memberId, infoType, connInfo, true);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetConnectionInfo(OrbisNpMatching2ContextId ctxId,
|
||||
OrbisNpMatching2RoomId roomId,
|
||||
OrbisNpMatching2RoomMemberId memberId,
|
||||
u32 infoType, void* connInfo) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}, roomId = {}, memberId = {}", ctxId, roomId,
|
||||
memberId);
|
||||
if (!g_initialized) {
|
||||
LOG_ERROR(Lib_NpMatching2, "not initialized");
|
||||
return ORBIS_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
ContextObject* ctx = ContextManager::Instance().Get(ctxId);
|
||||
if (!ctx) {
|
||||
LOG_ERROR(Lib_NpMatching2, "invalid context id");
|
||||
return ORBIS_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
return FillMatching2ConnectionInfo(*ctx, roomId, memberId, infoType, connInfo, false);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetLocalNetInfo(OrbisNpMatching2ContextId ctxId,
|
||||
void* info) {
|
||||
LOG_INFO(Lib_NpMatching2, "called, ctxId = {}", ctxId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpMatching2SignalingGetPeerNetInfoResult() {
|
||||
LOG_INFO(Lib_NpMatching2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -576,6 +1158,78 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
sceNpMatching2SetRoomDataExternal);
|
||||
LIB_FUNCTION("S9D8JSYIrjE", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SetRoomDataInternal);
|
||||
LIB_FUNCTION("tHD5FPFXtu4", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetConnectionStatus);
|
||||
LIB_FUNCTION("pFzhpCMlJXQ", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2AbortContextStart);
|
||||
LIB_FUNCTION("Nz-ZE7ur32I", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2DestroyContext);
|
||||
LIB_FUNCTION("DnPUsBAe8oI", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2RegisterLobbyMessageCallback);
|
||||
LIB_FUNCTION("uBESzz4CQws", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2RegisterRoomMessageCallback);
|
||||
LIB_FUNCTION("gpSAvdheZ0Q", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetMemoryInfo);
|
||||
LIB_FUNCTION("8btynvj0KNA", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetSslMemoryInfo);
|
||||
LIB_FUNCTION("KC+GnHzrK2o", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomMemberIdListLocal);
|
||||
LIB_FUNCTION("vbtWT3lZBOM", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomPasswordLocal);
|
||||
LIB_FUNCTION("cgQhq3E0eGo", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetSignalingOptParamLocal);
|
||||
LIB_FUNCTION("wyvlEgZ-55w", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetLobbyInfoList);
|
||||
LIB_FUNCTION("1JtbJ0kxm3E", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetLobbyMemberDataInternal);
|
||||
LIB_FUNCTION("1Z4Xxumgm+Y", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetLobbyMemberDataInternalList);
|
||||
LIB_FUNCTION("26vWrPAWJfM", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomDataExternalList);
|
||||
LIB_FUNCTION("Jraxifmoet4", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomDataInternal);
|
||||
LIB_FUNCTION("dMQ+xGvTdqM", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomMemberDataExternalList);
|
||||
LIB_FUNCTION("5lhvOqheFBA", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetRoomMemberDataInternal);
|
||||
LIB_FUNCTION("GyI2f9yDUXM", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetUserInfoListA);
|
||||
LIB_FUNCTION("qeF-q5KDtAc", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GetUserInfoList);
|
||||
LIB_FUNCTION("NCP3bLGPt+o", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2GrantRoomOwner);
|
||||
LIB_FUNCTION("n5JmImxTiZU", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2JoinLobby);
|
||||
LIB_FUNCTION("gQ6cUriNpgs", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2JoinRoomA);
|
||||
LIB_FUNCTION("AUVfU6byg3c", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2KickoutRoomMember);
|
||||
LIB_FUNCTION("BBbJ92uUdCg", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2LeaveLobby);
|
||||
LIB_FUNCTION("K+KtxhPsMZ4", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SendLobbyChatMessage);
|
||||
LIB_FUNCTION("opDpl74pi2E", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SendRoomChatMessage);
|
||||
LIB_FUNCTION("ir2CzSs9K-g", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SetLobbyMemberDataInternal);
|
||||
LIB_FUNCTION("HoqTrkS9c5Q", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SetRoomMemberDataInternal);
|
||||
LIB_FUNCTION("ES3UMUWWj9U", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SetSignalingOptParam);
|
||||
LIB_FUNCTION("8CqniKDzjvg", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetPeerNetInfo);
|
||||
LIB_FUNCTION("wUmwXZHaX1w", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetPingInfo);
|
||||
LIB_FUNCTION("GNSN5849fjU", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingCancelPeerNetInfo);
|
||||
LIB_FUNCTION("nNeC3F8-g+4", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetConnectionInfoA);
|
||||
LIB_FUNCTION("twVupeaYYrk", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetConnectionInfo);
|
||||
LIB_FUNCTION("380EWm2DrVg", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetLocalNetInfo);
|
||||
LIB_FUNCTION("CTy4PBhpWDw", "libSceNpMatching2", 1, "libSceNpMatching2",
|
||||
sceNpMatching2SignalingGetPeerNetInfoResult);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Np::NpMatching2
|
||||
} // namespace Libraries::Np::NpMatching2
|
||||
|
||||
@ -12,6 +12,7 @@ class SymbolsResolver;
|
||||
namespace Libraries::Np::NpMatching2 {
|
||||
|
||||
using OrbisNpMatching2AttributeId = u16;
|
||||
using OrbisNpMatching2BlockKickFlag = u8;
|
||||
using OrbisNpMatching2ContextId = u16;
|
||||
using OrbisNpMatching2Flags = u32;
|
||||
using OrbisNpMatching2LobbyId = u64;
|
||||
@ -85,6 +86,17 @@ enum OrbisNpMatching2SignalingType : u8 {
|
||||
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,
|
||||
@ -141,4 +153,4 @@ int PS4_SYSV_ABI sceNpMatching2CreateContextA(const OrbisNpMatching2CreateContex
|
||||
OrbisNpMatching2ContextId* ctxId);
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Np::NpMatching2
|
||||
} // namespace Libraries::Np::NpMatching2
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/np/np_common.h"
|
||||
#include "core/libraries/np/np_error.h"
|
||||
#include "core/libraries/np/np_matching2/np_matching2_internal.h"
|
||||
@ -15,6 +17,18 @@ namespace Libraries::Np::NpMatching2 {
|
||||
|
||||
NpMatching2State g_state;
|
||||
|
||||
namespace {
|
||||
|
||||
u32 IpStringToAddr(std::string_view ip) {
|
||||
u32 a, b, c, d;
|
||||
if (std::sscanf(std::string(ip).c_str(), "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
|
||||
return 0;
|
||||
}
|
||||
return a | (b << 8) | (c << 16) | (d << 24);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void* BuildCreateJoinRoomPayload(ContextObject& ctx, const shadnet::CreateJoinRoomResponse& resp) {
|
||||
CallbackPayload& p = ctx.request_payload;
|
||||
p.Reset();
|
||||
@ -99,11 +113,33 @@ void* BuildCreateJoinRoomPayload(ContextObject& ctx, const shadnet::CreateJoinRo
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.room_id != 0 && ctx.room_id != room.roomId) {
|
||||
ctx.room_cache.erase(ctx.room_id);
|
||||
}
|
||||
ctx.peers.clear();
|
||||
|
||||
RoomCache& rc = ctx.room_cache[room.roomId];
|
||||
rc = RoomCache{};
|
||||
rc.num_slots = room.maxSlot;
|
||||
rc.mask_password = room.passwdSlotMask;
|
||||
rc.server_id = room.serverId;
|
||||
rc.world_id = room.worldId;
|
||||
rc.lobby_id = room.lobbyId;
|
||||
rc.room_id = room.roomId;
|
||||
rc.max_slot = room.maxSlot;
|
||||
rc.public_slots = room.publicSlots;
|
||||
rc.private_slots = room.privateSlots;
|
||||
rc.open_public_slots = room.openPublicSlots;
|
||||
rc.open_private_slots = room.openPrivateSlots;
|
||||
rc.passwd_slot_mask = room.passwdSlotMask;
|
||||
rc.joined_slot_mask = room.joinedSlotMask;
|
||||
rc.flags = room.flags;
|
||||
rc.owner = resp.me_member_id() == resp.owner_member_id();
|
||||
rc.signaling_type = ORBIS_NP_MATCHING2_SIGNALING_TYPE_MESH;
|
||||
rc.signaling_main_member = static_cast<OrbisNpMatching2RoomMemberId>(resp.owner_member_id());
|
||||
ctx.room_id = room.roomId;
|
||||
ctx.my_member_id = static_cast<OrbisNpMatching2RoomMemberId>(resp.me_member_id());
|
||||
ctx.is_room_owner = rc.owner;
|
||||
for (const auto& g : p.room_groups) {
|
||||
rc.groups[g.id] = g;
|
||||
}
|
||||
@ -117,20 +153,47 @@ void* BuildCreateJoinRoomPayload(ContextObject& ctx, const shadnet::CreateJoinRo
|
||||
mc.flag_attr = m.flag_attr();
|
||||
mc.group_id = static_cast<OrbisNpMatching2RoomGroupId>(m.group_id());
|
||||
mc.join_date = m.join_date();
|
||||
mc.addr = 0;
|
||||
mc.port = 0;
|
||||
mc.addr = IpStringToAddr(m.addr());
|
||||
mc.port = Libraries::Net::sceNetHtons(static_cast<u16>(m.port()));
|
||||
std::strncpy(mc.np_id.handle.data, m.npid().c_str(), sizeof(mc.np_id.handle.data) - 1);
|
||||
for (const auto& a : m.bin_attrs_internal()) {
|
||||
MemberBinCache& b = mc.bins[a.attr_id()];
|
||||
b.id = static_cast<OrbisNpMatching2AttributeId>(a.attr_id());
|
||||
b.data.assign(a.data().begin(), a.data().end());
|
||||
}
|
||||
if (mc.member_id != ctx.my_member_id) {
|
||||
PeerInfo peer{};
|
||||
peer.member_id = mc.member_id;
|
||||
peer.addr = mc.addr;
|
||||
peer.port = mc.port;
|
||||
std::strncpy(peer.online_id.data, m.npid().c_str(), sizeof(peer.online_id.data) - 1);
|
||||
ctx.peers[mc.member_id] = peer;
|
||||
}
|
||||
}
|
||||
|
||||
p.request_data = p.create_join_response.get();
|
||||
return p.request_data;
|
||||
}
|
||||
|
||||
void* BuildLeaveRoomPayload(ContextObject& ctx, const shadnet::LeaveRoomReply& resp) {
|
||||
CallbackPayload& p = ctx.request_payload;
|
||||
p.Reset();
|
||||
|
||||
p.leave_room_response = std::make_unique<OrbisNpMatching2LeaveRoomResponse>();
|
||||
p.leave_room_response->roomId = static_cast<OrbisNpMatching2RoomId>(resp.room_id());
|
||||
|
||||
if (ctx.room_id == p.leave_room_response->roomId) {
|
||||
ctx.room_cache.erase(ctx.room_id);
|
||||
ctx.peers.clear();
|
||||
ctx.room_id = 0;
|
||||
ctx.my_member_id = 0;
|
||||
ctx.is_room_owner = false;
|
||||
}
|
||||
|
||||
p.request_data = p.leave_room_response.get();
|
||||
return p.request_data;
|
||||
}
|
||||
|
||||
void* BuildGetWorldInfoListPayload(ContextObject& ctx, const shadnet::GetWorldInfoListReply& resp) {
|
||||
CallbackPayload& p = ctx.request_payload;
|
||||
p.Reset();
|
||||
@ -263,6 +326,51 @@ void* BuildSearchRoomPayload(ContextObject& ctx, const shadnet::SearchRoomReply&
|
||||
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()) {
|
||||
return nullptr;
|
||||
}
|
||||
const RoomCache& rc = rc_it->second;
|
||||
|
||||
CallbackPayload& p = ctx.request_payload;
|
||||
p.Reset();
|
||||
|
||||
p.room_groups.clear();
|
||||
p.room_groups.reserve(rc.groups.size());
|
||||
for (const auto& [gid, g] : rc.groups) {
|
||||
p.room_groups.push_back(g);
|
||||
}
|
||||
|
||||
p.room_bin_attrs.resize(rc.bin_attrs_internal.size());
|
||||
for (size_t i = 0; i < rc.bin_attrs_internal.size(); ++i) {
|
||||
p.room_bin_attrs[i] = rc.bin_attrs_internal[i];
|
||||
}
|
||||
|
||||
p.room_data = std::make_unique<OrbisNpMatching2RoomDataInternal>();
|
||||
auto& room = *p.room_data;
|
||||
room = {};
|
||||
room.publicSlots = rc.public_slots;
|
||||
room.privateSlots = rc.private_slots;
|
||||
room.openPublicSlots = rc.open_public_slots;
|
||||
room.openPrivateSlots = rc.open_private_slots;
|
||||
room.maxSlot = rc.max_slot;
|
||||
room.serverId = rc.server_id;
|
||||
room.worldId = rc.world_id;
|
||||
room.lobbyId = rc.lobby_id;
|
||||
room.roomId = rc.room_id;
|
||||
room.passwdSlotMask = rc.passwd_slot_mask;
|
||||
room.joinedSlotMask = rc.joined_slot_mask;
|
||||
room.flags = rc.flags;
|
||||
room.roomGroup = p.room_groups.empty() ? nullptr : p.room_groups.data();
|
||||
room.roomGroups = p.room_groups.size();
|
||||
room.internalBinAttr = p.room_bin_attrs.empty() ? nullptr : p.room_bin_attrs.data();
|
||||
room.internalBinAttrs = p.room_bin_attrs.size();
|
||||
|
||||
p.request_data = p.room_data.get();
|
||||
return p.request_data;
|
||||
}
|
||||
|
||||
ContextManager& ContextManager::Instance() {
|
||||
static ContextManager instance;
|
||||
return instance;
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
namespace shadnet {
|
||||
class CreateJoinRoomResponse;
|
||||
class GetWorldInfoListReply;
|
||||
class LeaveRoomReply;
|
||||
class SearchRoomReply;
|
||||
} // namespace shadnet
|
||||
|
||||
@ -35,6 +36,13 @@ struct PeerInfo {
|
||||
s32 conn_id = 0;
|
||||
s32 status = 0;
|
||||
Libraries::Np::OrbisNpOnlineId online_id{};
|
||||
bool handshake_started = false;
|
||||
bool sent_check = false;
|
||||
bool sent_established = false;
|
||||
u64 nonce = 0;
|
||||
u32 ping_us = 0;
|
||||
std::chrono::steady_clock::time_point last_send{};
|
||||
std::chrono::steady_clock::time_point last_check_send{};
|
||||
};
|
||||
|
||||
struct MemberBinCache {
|
||||
@ -59,6 +67,22 @@ struct MemberCache {
|
||||
struct RoomCache {
|
||||
u32 num_slots = 0;
|
||||
u64 mask_password = 0;
|
||||
OrbisNpMatching2SignalingType signaling_type = ORBIS_NP_MATCHING2_SIGNALING_TYPE_MESH;
|
||||
OrbisNpMatching2RoomMemberId signaling_main_member = 0;
|
||||
OrbisNpMatching2ServerId server_id = 0;
|
||||
OrbisNpMatching2WorldId world_id = 0;
|
||||
OrbisNpMatching2LobbyId lobby_id = 0;
|
||||
OrbisNpMatching2RoomId room_id = 0;
|
||||
u16 max_slot = 0;
|
||||
u16 public_slots = 0;
|
||||
u16 private_slots = 0;
|
||||
u16 open_public_slots = 0;
|
||||
u16 open_private_slots = 0;
|
||||
u64 passwd_slot_mask = 0;
|
||||
u64 joined_slot_mask = 0;
|
||||
OrbisNpMatching2Flags flags = 0;
|
||||
std::vector<OrbisNpMatching2RoomBinAttrInternal> bin_attrs_internal;
|
||||
std::vector<std::vector<u8>> bin_buffers;
|
||||
std::map<OrbisNpMatching2RoomGroupId, OrbisNpMatching2RoomGroup> groups;
|
||||
std::map<OrbisNpMatching2RoomMemberId, MemberCache> members;
|
||||
bool owner = false;
|
||||
@ -67,8 +91,10 @@ struct RoomCache {
|
||||
struct CallbackPayload {
|
||||
std::unique_ptr<OrbisNpMatching2RoomDataInternal> room_data;
|
||||
std::unique_ptr<OrbisNpMatching2CreateJoinRoomResponse> create_join_response;
|
||||
std::unique_ptr<OrbisNpMatching2LeaveRoomResponse> leave_room_response;
|
||||
std::unique_ptr<OrbisNpMatching2SearchRoomResponse> search_room_response;
|
||||
std::unique_ptr<OrbisNpMatching2GetWorldInfoListResponse> world_info_response;
|
||||
std::unique_ptr<OrbisNpMatching2SignalingGetPingInfoResponse> ping_info_response;
|
||||
std::vector<OrbisNpMatching2World> world_list;
|
||||
std::vector<OrbisNpMatching2RoomMemberDataInternal> member_data;
|
||||
std::vector<OrbisNpMatching2RoomGroup> room_groups;
|
||||
@ -96,8 +122,10 @@ struct CallbackPayload {
|
||||
void Reset() {
|
||||
room_data.reset();
|
||||
create_join_response.reset();
|
||||
leave_room_response.reset();
|
||||
search_room_response.reset();
|
||||
world_info_response.reset();
|
||||
ping_info_response.reset();
|
||||
world_list.clear();
|
||||
member_data.clear();
|
||||
room_groups.clear();
|
||||
@ -295,8 +323,10 @@ extern NpMatching2State g_state;
|
||||
OrbisNpMatching2RequestId AllocRequestId();
|
||||
|
||||
void* BuildCreateJoinRoomPayload(ContextObject& ctx, const shadnet::CreateJoinRoomResponse& resp);
|
||||
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* BuildGetRoomDataInternalPayload(ContextObject& ctx, OrbisNpMatching2RoomId room_id);
|
||||
|
||||
void InitEventDispatcher();
|
||||
void TermEventDispatcher();
|
||||
|
||||
@ -4,15 +4,20 @@
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/network/sockets.h"
|
||||
#include "core/libraries/np/np_error.h"
|
||||
#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_signaling/np_signaling_stubs.h"
|
||||
#include "shadnet.pb.h"
|
||||
#include "shadnet/client.h"
|
||||
|
||||
@ -91,6 +96,391 @@ std::string ExtractProtoBytes(const std::vector<u8>& payload, size_t offset = 0)
|
||||
return std::string(reinterpret_cast<const char*>(payload.data() + offset + 4), len);
|
||||
}
|
||||
|
||||
constexpr s32 kMatching2ConnInactive = 0;
|
||||
constexpr s32 kMatching2ConnPending = 1;
|
||||
constexpr s32 kMatching2ConnActive = 2;
|
||||
constexpr auto kMatching2HandshakeRetry = std::chrono::milliseconds(350);
|
||||
constexpr auto kMatching2HandshakeTimeout = std::chrono::seconds(10);
|
||||
|
||||
std::atomic<bool> g_matching2_stop{false};
|
||||
std::mutex g_matching2_thread_mutex;
|
||||
std::thread g_matching2_thread;
|
||||
|
||||
enum class Matching2HandshakeKind : u8 {
|
||||
Offer = 1,
|
||||
Accept = 2,
|
||||
Check = 3,
|
||||
CheckAck = 4,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Matching2HandshakePacket {
|
||||
u8 magic[4] = {'S', 'H', 'A', 'D'};
|
||||
u8 type = 0x21;
|
||||
u8 kind = 0;
|
||||
u64 room_id = 0;
|
||||
u16 from_member_id = 0;
|
||||
u16 to_member_id = 0;
|
||||
u8 online_id_from[16]{};
|
||||
u32 mapped_addr = 0;
|
||||
u16 mapped_port = 0;
|
||||
u16 reserved = 0;
|
||||
u64 nonce = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(Matching2HandshakePacket) == 0x32);
|
||||
|
||||
bool HasMatching2Magic(const Matching2HandshakePacket& pkt) {
|
||||
return pkt.magic[0] == 'S' && pkt.magic[1] == 'H' && pkt.magic[2] == 'A' &&
|
||||
pkt.magic[3] == 'D' && pkt.type == 0x21;
|
||||
}
|
||||
|
||||
std::string OnlineIdToString(const Libraries::Np::OrbisNpOnlineId& online_id) {
|
||||
char buf[ORBIS_NP_ONLINEID_MAX_LENGTH + 1]{};
|
||||
std::memcpy(buf, online_id.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
bool ShouldConnectToPeer(const RoomCache& room, OrbisNpMatching2RoomMemberId self,
|
||||
OrbisNpMatching2RoomMemberId peer) {
|
||||
if (peer == 0 || peer == self) {
|
||||
return false;
|
||||
}
|
||||
if (room.signaling_type == ORBIS_NP_MATCHING2_SIGNALING_TYPE_NONE) {
|
||||
return false;
|
||||
}
|
||||
if (room.signaling_type == ORBIS_NP_MATCHING2_SIGNALING_TYPE_STAR &&
|
||||
room.signaling_main_member != 0) {
|
||||
return self == room.signaling_main_member || peer == room.signaling_main_member;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QueueMatching2SignalingEvent(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
|
||||
OrbisNpMatching2RoomMemberId member_id,
|
||||
OrbisNpMatching2Event event, s32 error_code) {
|
||||
PendingEvent ev{};
|
||||
ev.type = PendingEvent::SIGNALING_CB;
|
||||
ev.ctx_id = ctx.ctx_id;
|
||||
ev.fire_at = std::chrono::steady_clock::now();
|
||||
ev.room_id = room_id;
|
||||
ev.member_id = member_id;
|
||||
ev.sig_event = event;
|
||||
ev.error_code = error_code;
|
||||
ScheduleEvent(std::move(ev));
|
||||
}
|
||||
|
||||
void QueueMatching2DeadForRoomPeers(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
|
||||
s32 error_code) {
|
||||
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;
|
||||
}
|
||||
|
||||
auto peer_it = ctx.peers.find(member_id);
|
||||
if (peer_it != ctx.peers.end()) {
|
||||
peer_it->second.status = kMatching2ConnInactive;
|
||||
peer_it->second.handshake_started = false;
|
||||
peer_it->second.sent_check = false;
|
||||
}
|
||||
|
||||
QueueMatching2SignalingEvent(ctx, room_id, member_id,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_EVENT_DEAD, error_code);
|
||||
LOG_INFO(Lib_NpMatching2, "Matching2 signaling dead: ctx={} room={} member={} reason={:#x}",
|
||||
ctx.ctx_id, room_id, member_id, static_cast<u32>(error_code));
|
||||
}
|
||||
}
|
||||
|
||||
bool ResolvePeerEndpoint(const MemberCache& member, PeerInfo& peer) {
|
||||
if (peer.addr != 0 && peer.port != 0) {
|
||||
return true;
|
||||
}
|
||||
if (member.addr != 0 && member.port != 0) {
|
||||
peer.addr = member.addr;
|
||||
peer.port = member.port;
|
||||
if (peer.online_id.data[0] == 0) {
|
||||
std::strncpy(peer.online_id.data, member.np_id.handle.data,
|
||||
sizeof(peer.online_id.data) - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string online_id(member.np_id.handle.data);
|
||||
u32 resolved_addr = 0;
|
||||
u16 resolved_port = 0;
|
||||
if (!online_id.empty() && RequestSignalingInfos(online_id, &resolved_addr, &resolved_port)) {
|
||||
peer.addr = resolved_addr;
|
||||
peer.port = resolved_port;
|
||||
}
|
||||
if (peer.online_id.data[0] == 0) {
|
||||
std::strncpy(peer.online_id.data, member.np_id.handle.data,
|
||||
sizeof(peer.online_id.data) - 1);
|
||||
}
|
||||
return peer.addr != 0 && peer.port != 0;
|
||||
}
|
||||
|
||||
void MarkMatching2PeerActive(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
|
||||
OrbisNpMatching2RoomMemberId member_id, u32 addr, u16 port) {
|
||||
if (member_id == 0 || member_id == ctx.my_member_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
PeerInfo& peer = ctx.peers[member_id];
|
||||
peer.member_id = member_id;
|
||||
if (addr != 0) {
|
||||
peer.addr = addr;
|
||||
}
|
||||
if (port != 0) {
|
||||
peer.port = port;
|
||||
}
|
||||
const bool first_active = peer.status != kMatching2ConnActive;
|
||||
peer.status = kMatching2ConnActive;
|
||||
peer.handshake_started = true;
|
||||
|
||||
if (first_active && !peer.sent_established) {
|
||||
peer.sent_established = true;
|
||||
QueueMatching2SignalingEvent(ctx, room_id, member_id,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_EVENT_ESTABLISHED, ORBIS_OK);
|
||||
LOG_INFO(Lib_NpMatching2,
|
||||
"Matching2 signaling established: ctx={} room={} member={} addr={:#x}:{}",
|
||||
ctx.ctx_id, room_id, member_id, peer.addr, Libraries::Net::sceNetNtohs(peer.port));
|
||||
}
|
||||
}
|
||||
|
||||
bool SendMatching2Handshake(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
|
||||
OrbisNpMatching2RoomMemberId member_id, Matching2HandshakeKind kind,
|
||||
u64 nonce) {
|
||||
auto room_it = ctx.room_cache.find(room_id);
|
||||
if (room_it == ctx.room_cache.end()) {
|
||||
return false;
|
||||
}
|
||||
auto member_it = room_it->second.members.find(member_id);
|
||||
if (member_it == room_it->second.members.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PeerInfo& peer = ctx.peers[member_id];
|
||||
peer.member_id = member_id;
|
||||
if (!ResolvePeerEndpoint(member_it->second, peer)) {
|
||||
LOG_WARNING(Lib_NpMatching2, "Matching2 signaling: unresolved endpoint room={} member={}",
|
||||
room_id, member_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
Matching2HandshakePacket pkt{};
|
||||
pkt.kind = static_cast<u8>(kind);
|
||||
pkt.room_id = room_id;
|
||||
pkt.from_member_id = ctx.my_member_id;
|
||||
pkt.to_member_id = member_id;
|
||||
std::memcpy(pkt.online_id_from, ctx.online_id.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
|
||||
pkt.mapped_addr = Net::GetP2PAdvertisedAddr();
|
||||
pkt.mapped_port = Net::GetP2PConfiguredPort() != 0
|
||||
? Libraries::Net::sceNetHtons(Net::GetP2PConfiguredPort())
|
||||
: 0;
|
||||
pkt.nonce = nonce;
|
||||
|
||||
const int rc = Net::P2PMatching2SendTo(&pkt, sizeof(pkt), peer.addr, peer.port);
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
peer.last_send = now;
|
||||
if (kind == Matching2HandshakeKind::Check) {
|
||||
peer.last_check_send = now;
|
||||
}
|
||||
LOG_DEBUG(Lib_NpMatching2,
|
||||
"Matching2 handshake send kind={} ctx={} room={} {}->{} dst={:#x}:{} rc={}",
|
||||
static_cast<u8>(kind), ctx.ctx_id, room_id, ctx.my_member_id, member_id, peer.addr,
|
||||
Libraries::Net::sceNetNtohs(peer.port), rc);
|
||||
return rc >= 0;
|
||||
}
|
||||
|
||||
void StartMatching2PeerHandshake(ContextObject& ctx, OrbisNpMatching2RoomId room_id,
|
||||
OrbisNpMatching2RoomMemberId member_id) {
|
||||
auto room_it = ctx.room_cache.find(room_id);
|
||||
if (room_it == ctx.room_cache.end() ||
|
||||
!ShouldConnectToPeer(room_it->second, ctx.my_member_id, member_id)) {
|
||||
return;
|
||||
}
|
||||
auto member_it = room_it->second.members.find(member_id);
|
||||
if (member_it == room_it->second.members.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Net::EnsureP2PTransport();
|
||||
|
||||
PeerInfo& peer = ctx.peers[member_id];
|
||||
peer.member_id = member_id;
|
||||
if (peer.status == kMatching2ConnActive) {
|
||||
return;
|
||||
}
|
||||
ResolvePeerEndpoint(member_it->second, peer);
|
||||
peer.status = kMatching2ConnPending;
|
||||
peer.handshake_started = true;
|
||||
peer.sent_check = false;
|
||||
if (peer.nonce == 0) {
|
||||
peer.nonce = static_cast<u64>(std::chrono::steady_clock::now().time_since_epoch().count() ^
|
||||
(static_cast<u64>(ctx.ctx_id) << 48) ^
|
||||
(static_cast<u64>(member_id) << 16));
|
||||
}
|
||||
SendMatching2Handshake(ctx, room_id, member_id, Matching2HandshakeKind::Offer, 0);
|
||||
}
|
||||
|
||||
void StartMatching2SignalingForRoomPeers(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) {
|
||||
StartMatching2PeerHandshake(ctx, room_id, member_id);
|
||||
}
|
||||
}
|
||||
|
||||
ContextObject* FindContextForMatching2Packet(const Matching2HandshakePacket& pkt) {
|
||||
for (u32 id = 1; id <= ContextManager::kMaxContexts; ++id) {
|
||||
ContextObject* ctx =
|
||||
ContextManager::Instance().Get(static_cast<OrbisNpMatching2ContextId>(id));
|
||||
if (!ctx || ctx->room_id != pkt.room_id || ctx->my_member_id != pkt.to_member_id) {
|
||||
continue;
|
||||
}
|
||||
if (ctx->room_cache.find(static_cast<OrbisNpMatching2RoomId>(pkt.room_id)) !=
|
||||
ctx->room_cache.end()) {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HandleMatching2HandshakePacket(u32 from_addr, u16 from_port,
|
||||
const Matching2HandshakePacket& pkt) {
|
||||
if (!HasMatching2Magic(pkt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContextObject* ctx = FindContextForMatching2Packet(pkt);
|
||||
if (!ctx) {
|
||||
LOG_DEBUG(Lib_NpMatching2, "Matching2 handshake: no ctx for room={} to_member={}",
|
||||
pkt.room_id, pkt.to_member_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto room_id = static_cast<OrbisNpMatching2RoomId>(pkt.room_id);
|
||||
const auto member_id = static_cast<OrbisNpMatching2RoomMemberId>(pkt.from_member_id);
|
||||
auto room_it = ctx->room_cache.find(room_id);
|
||||
if (room_it == ctx->room_cache.end() ||
|
||||
!ShouldConnectToPeer(room_it->second, ctx->my_member_id, member_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PeerInfo& peer = ctx->peers[member_id];
|
||||
peer.member_id = member_id;
|
||||
peer.addr = pkt.mapped_addr != 0 ? pkt.mapped_addr : from_addr;
|
||||
peer.port = pkt.mapped_port != 0 ? pkt.mapped_port : from_port;
|
||||
peer.status =
|
||||
peer.status == kMatching2ConnActive ? kMatching2ConnActive : kMatching2ConnPending;
|
||||
peer.handshake_started = true;
|
||||
std::memcpy(peer.online_id.data, pkt.online_id_from, ORBIS_NP_ONLINEID_MAX_LENGTH);
|
||||
|
||||
const auto kind = static_cast<Matching2HandshakeKind>(pkt.kind);
|
||||
switch (kind) {
|
||||
case Matching2HandshakeKind::Offer:
|
||||
SendMatching2Handshake(*ctx, room_id, member_id, Matching2HandshakeKind::Accept, 0);
|
||||
break;
|
||||
case Matching2HandshakeKind::Accept:
|
||||
peer.sent_check = true;
|
||||
SendMatching2Handshake(*ctx, room_id, member_id, Matching2HandshakeKind::Check, peer.nonce);
|
||||
break;
|
||||
case Matching2HandshakeKind::Check:
|
||||
SendMatching2Handshake(*ctx, room_id, member_id, Matching2HandshakeKind::CheckAck,
|
||||
pkt.nonce);
|
||||
MarkMatching2PeerActive(*ctx, room_id, member_id, peer.addr, peer.port);
|
||||
break;
|
||||
case Matching2HandshakeKind::CheckAck:
|
||||
if (pkt.nonce == 0 || pkt.nonce == peer.nonce) {
|
||||
if (peer.last_check_send.time_since_epoch().count() != 0) {
|
||||
const auto rtt = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - peer.last_check_send);
|
||||
peer.ping_us =
|
||||
static_cast<u32>(std::min<u64>(static_cast<u64>(std::max<s64>(0, rtt.count())),
|
||||
std::numeric_limits<u32>::max()));
|
||||
peer.last_check_send = {};
|
||||
}
|
||||
MarkMatching2PeerActive(*ctx, room_id, member_id, peer.addr, peer.port);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Matching2HandshakeThreadMain() {
|
||||
while (!g_matching2_stop.load(std::memory_order_relaxed)) {
|
||||
Matching2HandshakePacket pkt{};
|
||||
u32 from_addr = 0;
|
||||
u16 from_port = 0;
|
||||
const int rc = Net::P2PMatching2RecvFrom(&pkt, sizeof(pkt), &from_addr, &from_port);
|
||||
if (rc == sizeof(pkt)) {
|
||||
HandleMatching2HandshakePacket(from_addr, from_port, pkt);
|
||||
}
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
for (u32 id = 1; id <= ContextManager::kMaxContexts; ++id) {
|
||||
ContextObject* ctx =
|
||||
ContextManager::Instance().Get(static_cast<OrbisNpMatching2ContextId>(id));
|
||||
if (!ctx || ctx->room_id == 0) {
|
||||
continue;
|
||||
}
|
||||
auto room_it = ctx->room_cache.find(ctx->room_id);
|
||||
if (room_it == ctx->room_cache.end()) {
|
||||
continue;
|
||||
}
|
||||
for (auto& [member_id, peer] : ctx->peers) {
|
||||
if (peer.status != kMatching2ConnPending || !peer.handshake_started) {
|
||||
continue;
|
||||
}
|
||||
if (peer.last_send.time_since_epoch().count() != 0 &&
|
||||
now - peer.last_send > kMatching2HandshakeTimeout) {
|
||||
peer.status = kMatching2ConnInactive;
|
||||
QueueMatching2SignalingEvent(*ctx, ctx->room_id, member_id,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_EVENT_NETINFO_ERROR,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_ERROR_TIMEOUT);
|
||||
continue;
|
||||
}
|
||||
if (peer.last_send.time_since_epoch().count() == 0 ||
|
||||
now - peer.last_send >= kMatching2HandshakeRetry) {
|
||||
SendMatching2Handshake(*ctx, ctx->room_id, member_id,
|
||||
peer.sent_check ? Matching2HandshakeKind::Check
|
||||
: Matching2HandshakeKind::Offer,
|
||||
peer.sent_check ? peer.nonce : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
void StartMatching2HandshakeThread() {
|
||||
std::lock_guard lock(g_matching2_thread_mutex);
|
||||
if (g_matching2_thread.joinable()) {
|
||||
return;
|
||||
}
|
||||
g_matching2_stop.store(false, std::memory_order_relaxed);
|
||||
g_matching2_thread = std::thread(Matching2HandshakeThreadMain);
|
||||
}
|
||||
|
||||
void StopMatching2HandshakeThread() {
|
||||
{
|
||||
std::lock_guard lock(g_matching2_thread_mutex);
|
||||
g_matching2_stop.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
if (g_matching2_thread.joinable()) {
|
||||
g_matching2_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void DispatchRequestComplete(const PendingRequest& pr, ShadNet::ErrorType error,
|
||||
const std::vector<u8>& body) {
|
||||
ContextObject* ctx = ContextManager::Instance().Get(pr.ctx_id);
|
||||
@ -127,6 +517,14 @@ void DispatchRequestComplete(const PendingRequest& pr, ShadNet::ErrorType error,
|
||||
if (reply.ParseFromString(proto) && reply.has_details()) {
|
||||
request_data = BuildCreateJoinRoomPayload(*ctx, reply.details());
|
||||
}
|
||||
} else if (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_LEAVE_ROOM) {
|
||||
shadnet::LeaveRoomReply reply;
|
||||
if (reply.ParseFromString(proto)) {
|
||||
QueueMatching2DeadForRoomPeers(
|
||||
*ctx, static_cast<OrbisNpMatching2RoomId>(reply.room_id()),
|
||||
ORBIS_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_MYSELF);
|
||||
request_data = BuildLeaveRoomPayload(*ctx, reply);
|
||||
}
|
||||
} else if (pr.req_event == ORBIS_NP_MATCHING2_REQUEST_EVENT_GET_WORLD_INFO_LIST) {
|
||||
shadnet::GetWorldInfoListReply reply;
|
||||
if (reply.ParseFromString(proto)) {
|
||||
@ -151,6 +549,11 @@ void DispatchRequestComplete(const PendingRequest& pr, ShadNet::ErrorType error,
|
||||
ev.request_cb_arg = ctx->default_request_callback_arg;
|
||||
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_JOIN_ROOM)) {
|
||||
StartMatching2SignalingForRoomPeers(*ctx, ctx->room_id);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildMemberUpdate(CallbackPayload& p, const RoomCache& rc, const MemberCache& mc,
|
||||
@ -254,6 +657,9 @@ void HandleRoomEvent(const ShadNet::NotifyRoomEvent& n) {
|
||||
return;
|
||||
}
|
||||
BuildMemberUpdate(p, room_it->second, mem_it->second, cause);
|
||||
QueueMatching2SignalingEvent(*ctx, room_id, member_id,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_EVENT_DEAD,
|
||||
ORBIS_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER);
|
||||
room_it->second.members.erase(mem_it);
|
||||
ctx->peers.erase(member_id);
|
||||
break;
|
||||
@ -283,6 +689,10 @@ void HandleRoomEvent(const ShadNet::NotifyRoomEvent& n) {
|
||||
ev.room_event = 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);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -315,6 +725,8 @@ void OnMatchingReply(ShadNet::CommandType cmd, u64 pkt_id, ShadNet::ErrorType er
|
||||
|
||||
void SetMmShadNetClient(std::shared_ptr<ShadNet::ShadNetClient> client,
|
||||
std::string_view server_host, u16 tcp_port) {
|
||||
u32 server_addr = 0;
|
||||
u16 server_udp_port = 0;
|
||||
{
|
||||
std::lock_guard lock(g_mm.mutex);
|
||||
g_mm.client = client;
|
||||
@ -323,12 +735,31 @@ void SetMmShadNetClient(std::shared_ptr<ShadNet::ShadNetClient> client,
|
||||
g_mm.server_addr = IpStringToAddr(server_host);
|
||||
}
|
||||
g_mm.server_udp_port = Libraries::Net::sceNetHtons(static_cast<u16>(tcp_port + 1));
|
||||
server_addr = g_mm.server_addr;
|
||||
server_udp_port = g_mm.server_udp_port;
|
||||
}
|
||||
|
||||
if (!client) {
|
||||
NpSignaling::Stubs::SetTransportHooks({});
|
||||
NpSignaling::Stubs::SetPeerResolver(nullptr);
|
||||
NpSignaling::Stubs::SetMmServerEndpoint(0, 0);
|
||||
StopMatching2HandshakeThread();
|
||||
return;
|
||||
}
|
||||
|
||||
NpSignaling::Stubs::SetTransportHooks({
|
||||
.signaling_send = Net::P2PSignalingSendTo,
|
||||
.signaling_recv = Net::P2PSignalingRecvFrom,
|
||||
.control_send = Net::P2PControlSendTo,
|
||||
.control_recv = Net::P2PControlRecvFrom,
|
||||
.transport_ready = Net::P2PTransportIsReady,
|
||||
.configured_port = Net::GetP2PConfiguredPort,
|
||||
.advertised_addr = Net::GetP2PAdvertisedAddr,
|
||||
.ensure_transport = Net::EnsureP2PTransport,
|
||||
});
|
||||
NpSignaling::Stubs::SetPeerResolver(RequestSignalingInfos);
|
||||
NpSignaling::Stubs::SetMmServerEndpoint(server_addr, server_udp_port);
|
||||
StartMatching2HandshakeThread();
|
||||
client->onRoomEvent = [](const ShadNet::NotifyRoomEvent& n) { HandleRoomEvent(n); };
|
||||
}
|
||||
|
||||
@ -343,6 +774,10 @@ void ClearMmShadNetClient() {
|
||||
if (old_client) {
|
||||
old_client->onRoomEvent = nullptr;
|
||||
}
|
||||
NpSignaling::Stubs::SetTransportHooks({});
|
||||
NpSignaling::Stubs::SetPeerResolver(nullptr);
|
||||
NpSignaling::Stubs::SetMmServerEndpoint(0, 0);
|
||||
StopMatching2HandshakeThread();
|
||||
{
|
||||
std::lock_guard lock(g_mm.pending_mutex);
|
||||
g_mm.pending.clear();
|
||||
@ -501,6 +936,53 @@ s32 MmSearchRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req
|
||||
MmCommand::SearchRoom, MakeProtoPayload(req));
|
||||
}
|
||||
|
||||
s32 MmSetRoomDataInternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2SetRoomDataInternalRequest& request) {
|
||||
shadnet::SetRoomDataInternalRequest req;
|
||||
req.set_req_id(req_id);
|
||||
req.set_room_id(request.roomId);
|
||||
req.set_flag_filter(request.flagFilter);
|
||||
req.set_flag_attr(request.flagAttr);
|
||||
for (u64 i = 0; i < request.roomBinAttrInternalNum; ++i) {
|
||||
AppendBinAttr(req.add_bin_attrs(), request.roomBinAttrInternal[i]);
|
||||
}
|
||||
if (request.passwordSlotMask) {
|
||||
req.set_has_passwd_mask(true);
|
||||
req.set_passwd_slot_mask(*request.passwordSlotMask);
|
||||
}
|
||||
return MmSubmitRequest(ctx_id, req_id, ORBIS_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_INTERNAL,
|
||||
MmCommand::SetRoomDataInternal, MakeProtoPayload(req));
|
||||
}
|
||||
|
||||
s32 MmSetRoomDataExternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2SetRoomDataExternalRequest& request) {
|
||||
shadnet::SetRoomDataExternalRequest req;
|
||||
req.set_req_id(req_id);
|
||||
req.set_room_id(request.roomId);
|
||||
for (u64 i = 0; i < request.roomSearchableIntAttrExternalNum; ++i) {
|
||||
AppendIntAttr(req.add_search_int_attrs(), request.roomSearchableIntAttrExternal[i]);
|
||||
}
|
||||
for (u64 i = 0; i < request.roomSearchableBinAttrExternalNum; ++i) {
|
||||
AppendBinAttr(req.add_search_bin_attrs(), request.roomSearchableBinAttrExternal[i]);
|
||||
}
|
||||
for (u64 i = 0; i < request.roomBinAttrExternalNum; ++i) {
|
||||
AppendBinAttr(req.add_ext_bin_attrs(), request.roomBinAttrExternal[i]);
|
||||
}
|
||||
return MmSubmitRequest(ctx_id, req_id, ORBIS_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_EXTERNAL,
|
||||
MmCommand::SetRoomDataExternal, MakeProtoPayload(req));
|
||||
}
|
||||
|
||||
s32 MmKickoutRoomMember(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2KickoutRoomMemberRequest& request) {
|
||||
shadnet::KickoutRoomMemberRequest req;
|
||||
req.set_req_id(req_id);
|
||||
req.set_room_id(request.roomId);
|
||||
req.set_target_member_id(request.memberId);
|
||||
req.set_block_kick_flag(request.blockKickFlag);
|
||||
return MmSubmitRequest(ctx_id, req_id, ORBIS_NP_MATCHING2_REQUEST_EVENT_KICKOUT_ROOM_MEMBER,
|
||||
MmCommand::KickoutRoomMember, MakeProtoPayload(req));
|
||||
}
|
||||
|
||||
u32 GetMmServerAddr() {
|
||||
std::lock_guard lock(g_mm.mutex);
|
||||
return g_mm.server_addr;
|
||||
|
||||
@ -57,6 +57,12 @@ s32 MmGetWorldInfoList(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2Request
|
||||
const OrbisNpMatching2GetWorldInfoListRequest& request);
|
||||
s32 MmSearchRoom(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2SearchRoomRequest& request);
|
||||
s32 MmSetRoomDataInternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2SetRoomDataInternalRequest& request);
|
||||
s32 MmSetRoomDataExternal(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2SetRoomDataExternalRequest& request);
|
||||
s32 MmKickoutRoomMember(OrbisNpMatching2ContextId ctx_id, OrbisNpMatching2RequestId req_id,
|
||||
const OrbisNpMatching2KickoutRoomMemberRequest& request);
|
||||
|
||||
u32 GetMmServerAddr();
|
||||
u16 GetMmServerUdpPort();
|
||||
|
||||
@ -221,6 +221,12 @@ struct OrbisNpMatching2GetWorldInfoListRequest {
|
||||
OrbisNpMatching2ServerId serverId;
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2GetRoomDataInternalRequest {
|
||||
OrbisNpMatching2RoomId roomId;
|
||||
const OrbisNpMatching2AttributeId* attrId;
|
||||
u64 attrIdNum;
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2World {
|
||||
OrbisNpMatching2World* next;
|
||||
OrbisNpMatching2WorldId worldId;
|
||||
@ -297,14 +303,9 @@ static_assert(sizeof(OrbisNpMatching2JoinRoomRequest) == 0x58);
|
||||
struct OrbisNpMatching2KickoutRoomMemberRequest {
|
||||
OrbisNpMatching2RoomId roomId;
|
||||
OrbisNpMatching2RoomMemberId memberId;
|
||||
u8 pad0[6];
|
||||
u32 blockKickFlag;
|
||||
u8 pad1[12];
|
||||
u64 reserved;
|
||||
|
||||
int Validate() {
|
||||
return 0;
|
||||
}
|
||||
OrbisNpMatching2BlockKickFlag blockKickFlag;
|
||||
u8 padding[5];
|
||||
OrbisNpMatching2PresenceOptionData optData;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpMatching2KickoutRoomMemberRequest) == 0x28);
|
||||
|
||||
@ -397,6 +398,12 @@ struct OrbisNpMatching2RoomGroupConfig {
|
||||
u8 pad[2];
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2RoomGroupPasswordConfig {
|
||||
OrbisNpMatching2RoomGroupId groupId;
|
||||
bool hasPassword;
|
||||
u8 pad[1];
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2RoomGroupInfo {
|
||||
OrbisNpMatching2RoomGroupId id;
|
||||
bool hasPasswd;
|
||||
@ -505,29 +512,25 @@ struct OrbisNpMatching2SearchRoomResponseA {
|
||||
|
||||
struct OrbisNpMatching2SetRoomDataExternalRequest {
|
||||
OrbisNpMatching2RoomId roomId;
|
||||
OrbisNpMatching2IntAttr* roomSearchableIntAttrExternal;
|
||||
u32 roomSearchableIntAttrExternalNum;
|
||||
u8 pad1[4];
|
||||
OrbisNpMatching2BinAttr* roomSearchableBinAttrExternal;
|
||||
u32 roomSearchableBinAttrExternalNum;
|
||||
u8 pad2[4];
|
||||
OrbisNpMatching2BinAttr* roomBinAttrExternal;
|
||||
u32 roomBinAttrExternalNum;
|
||||
u8 pad3[4];
|
||||
const OrbisNpMatching2IntAttr* roomSearchableIntAttrExternal;
|
||||
u64 roomSearchableIntAttrExternalNum;
|
||||
const OrbisNpMatching2BinAttr* roomSearchableBinAttrExternal;
|
||||
u64 roomSearchableBinAttrExternalNum;
|
||||
const OrbisNpMatching2BinAttr* roomBinAttrExternal;
|
||||
u64 roomBinAttrExternalNum;
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2SetRoomDataInternalRequest {
|
||||
OrbisNpMatching2RoomId roomId;
|
||||
OrbisNpMatching2Flags flagFilter;
|
||||
OrbisNpMatching2Flags flagAttr;
|
||||
OrbisNpMatching2BinAttr* roomBinAttrInternal;
|
||||
u32 roomBinAttrInternalNum;
|
||||
OrbisNpMatching2RoomGroupConfig* passwordConfig;
|
||||
u32 passwordConfigNum;
|
||||
u64* passwordSlotMask;
|
||||
OrbisNpMatching2RoomMemberId* ownerPrivilegeRank;
|
||||
u32 ownerPrivilegeRankNum;
|
||||
u8 padding[4];
|
||||
const OrbisNpMatching2BinAttr* roomBinAttrInternal;
|
||||
u64 roomBinAttrInternalNum;
|
||||
const OrbisNpMatching2RoomGroupPasswordConfig* passwordConfig;
|
||||
u64 passwordConfigNum;
|
||||
const OrbisNpMatching2RoomPasswordSlotMask* passwordSlotMask;
|
||||
const OrbisNpMatching2RoomMemberId* ownerPrivilegeRank;
|
||||
u64 ownerPrivilegeRankNum;
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2SetUserInfoRequest {
|
||||
@ -543,9 +546,23 @@ struct OrbisNpMatching2SignalingConnectionInfoAddr {
|
||||
u8 pad[2];
|
||||
};
|
||||
|
||||
struct OrbisNpMatching2SignalingConnectionInfo {
|
||||
union OrbisNpMatching2SignalingConnectionInfo {
|
||||
u32 rtt;
|
||||
u32 bandwidth;
|
||||
Libraries::Np::OrbisNpId npId;
|
||||
OrbisNpMatching2SignalingConnectionInfoAddr address;
|
||||
u32 packetLoss;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpMatching2SignalingConnectionInfo) == 0x24);
|
||||
|
||||
union OrbisNpMatching2SignalingConnectionInfoA {
|
||||
u32 rtt;
|
||||
u32 bandwidth;
|
||||
Libraries::Np::OrbisNpPeerAddressA peerAddrA;
|
||||
OrbisNpMatching2SignalingConnectionInfoAddr address;
|
||||
u32 packetLoss;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpMatching2SignalingConnectionInfoA) == 0x10);
|
||||
|
||||
// internal - to be removed.
|
||||
struct OrbisNpMatching2SignalingEvent {
|
||||
@ -570,9 +587,10 @@ struct OrbisNpMatching2SignalingGetPingInfoResponse {
|
||||
u8 pad[2];
|
||||
OrbisNpMatching2WorldId worldId;
|
||||
OrbisNpMatching2RoomId roomId;
|
||||
u32 pingUs;
|
||||
u32 rtt;
|
||||
u8 reserved[20];
|
||||
};
|
||||
static_assert(sizeof(OrbisNpMatching2SignalingGetPingInfoResponse) == 0x28);
|
||||
|
||||
struct OrbisNpMatching2SignalingParam {
|
||||
int type;
|
||||
|
||||
@ -43,6 +43,14 @@ u16 ConfiguredPort() {
|
||||
return g_transport.configured_port ? g_transport.configured_port() : 0;
|
||||
}
|
||||
|
||||
u32 AdvertisedAddr() {
|
||||
return g_transport.advertised_addr ? g_transport.advertised_addr() : 0;
|
||||
}
|
||||
|
||||
bool EnsureTransport() {
|
||||
return g_transport.ensure_transport ? g_transport.ensure_transport() : TransportIsReady();
|
||||
}
|
||||
|
||||
void SetPeerResolver(PeerResolver fn) {
|
||||
g_peer_resolver = fn;
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ struct TransportHooks {
|
||||
int (*control_recv)(void* buf, u32 len, u32* from_addr, u16* from_port) = nullptr;
|
||||
bool (*transport_ready)() = nullptr;
|
||||
u16 (*configured_port)() = nullptr;
|
||||
u32 (*advertised_addr)() = nullptr;
|
||||
bool (*ensure_transport)() = nullptr;
|
||||
};
|
||||
void SetTransportHooks(const TransportHooks& hooks);
|
||||
|
||||
@ -24,6 +26,8 @@ int ControlSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int ControlRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
bool TransportIsReady();
|
||||
u16 ConfiguredPort();
|
||||
u32 AdvertisedAddr();
|
||||
bool EnsureTransport();
|
||||
|
||||
using PeerResolver = bool (*)(std::string_view online_id, u32* out_addr, u16* out_port);
|
||||
void SetPeerResolver(PeerResolver fn);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user