mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
fix netplay
This commit is contained in:
@@ -10,7 +10,9 @@ extern "C" {
|
||||
|
||||
#define PSX_LOBBY_ID_LEN 40
|
||||
#define PSX_LOBBY_NAME_LEN 64
|
||||
#define PSX_LOBBY_VERSION_LEN 32
|
||||
/* Title compatibility IDs may contain a prefix and a 160-bit source hash.
|
||||
* Preserve the full 63-byte ID for exact list/join comparisons. */
|
||||
#define PSX_LOBBY_VERSION_LEN 64
|
||||
#define PSX_LOBBY_ENDPOINT_LEN 64
|
||||
#define PSX_LOBBY_MAX_LIST 32
|
||||
/* Player seats this framework can seat. Was what PSX_LOBBY_MAX_MEMBERS meant
|
||||
|
||||
@@ -354,6 +354,11 @@ void psx_netplay_wait_recv(int timeout_ms);
|
||||
void psx_netplay_admit_wait_info(char *stall_out, size_t stall_cap,
|
||||
uint32_t *sim_tick_out, int *lead_out);
|
||||
|
||||
/* One-line transport snapshot for a session stuck before RUNNING: ICE state,
|
||||
* selected path, datagrams received, recv-queue drops and time since the last
|
||||
* peer datagram. Writes "inactive" when no session exists. */
|
||||
void psx_netplay_link_diag(char *out, size_t cap);
|
||||
|
||||
/* Normalize for stabler cross-device blobs: unknown types become digital;
|
||||
* centred axes (sticks, wheel, twist) snap to 0x80 inside a deadzone; NeGcon
|
||||
* pressure bytes (ly/rx/ry) are kept exactly; digital centres everything. */
|
||||
|
||||
@@ -118,6 +118,9 @@ endif()
|
||||
# release when no system package is available, so a default build does not
|
||||
# silently fall back to SDL2. SDL2 remains an explicit, fully supported A/B
|
||||
# backend.
|
||||
# Dev-only: the lobby browser lists every version of this title instead of
|
||||
# pinning to our exact game_version. Joining still requires an exact match.
|
||||
option(PSX_LOBBY_DEV_LIST "Lobby browser ignores game_version (dev testing only)" OFF)
|
||||
set(PSX_SDL_BACKEND "SDL3" CACHE STRING "SDL backend (SDL3 or SDL2)")
|
||||
set_property(CACHE PSX_SDL_BACKEND PROPERTY STRINGS SDL3 SDL2)
|
||||
string(TOUPPER "${PSX_SDL_BACKEND}" _psx_sdl_backend)
|
||||
@@ -2002,7 +2005,8 @@ function(psxrecomp_add_runtime_target target)
|
||||
# target-wide compile line so Ninja does not rebuild every runtime + shard TU.
|
||||
set_source_files_properties(
|
||||
"${PSXRECOMP_ROOT}/runtime/src/psx_lobby_client.c"
|
||||
PROPERTIES COMPILE_DEFINITIONS "PSX_GAME_VERSION=\"${PSXRT_GAME_VERSION}\""
|
||||
PROPERTIES COMPILE_DEFINITIONS
|
||||
"PSX_GAME_VERSION=\"${PSXRT_GAME_VERSION}\";$<$<BOOL:${PSX_LOBBY_DEV_LIST}>:PSX_LOBBY_DEV_LIST=1>"
|
||||
)
|
||||
set_source_files_properties(
|
||||
"${PSXRECOMP_ROOT}/runtime/src/crash_trace.c"
|
||||
|
||||
@@ -6803,6 +6803,11 @@ static void netplay_barrier_admit(int override) {
|
||||
(unsigned long long)(now_ms - clock0),
|
||||
running ? "" : ", linking");
|
||||
last_stall_log_ms = now_ms;
|
||||
if (!running) {
|
||||
char link[320];
|
||||
psx_netplay_link_diag(link, sizeof(link));
|
||||
std::fprintf(stderr, "psxrecomp: netplay link not up: %s\n", link);
|
||||
}
|
||||
}
|
||||
psx_lobby_pump();
|
||||
if (psx_netplay_input_desync(&dt, &lh, &rh)) {
|
||||
|
||||
@@ -1084,6 +1084,9 @@ static const char *effective_game_version(const char *override_ver)
|
||||
* unofficial / mismatched hosts; join still requires an exact version match. */
|
||||
static int list_filter_version_strict(void)
|
||||
{
|
||||
#ifdef PSX_LOBBY_DEV_LIST
|
||||
return 0;
|
||||
#endif
|
||||
const char *gv = effective_game_version(NULL);
|
||||
return gv && gv[0] && strcmp(gv, "dev") != 0;
|
||||
}
|
||||
@@ -1317,7 +1320,7 @@ static void host_ice_step(void)
|
||||
v.is_host = g_lc.is_host ? 1 : 0;
|
||||
v.local_slot = local_member_slot();
|
||||
v.active = psx_lobby_connected() && g_lc.in_lobby && !g_lc.launch_pending &&
|
||||
!g_lc.join.local_is_spectator && room_relays_via_ice() &&
|
||||
!g_lc.ice_rtt_suspended && !g_lc.join.local_is_spectator && room_relays_via_ice() &&
|
||||
v.local_slot >= 0;
|
||||
if (v.active) {
|
||||
if (v.is_host) {
|
||||
@@ -5492,6 +5495,12 @@ int psx_lobby_request_start(const PsxLobbyMatchCaps *match_caps)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* The encoder selects the host relay's path from the local preference.
|
||||
* Keep the waiting-room view on that same path while START is in flight:
|
||||
* callers construct fresh caps and need not copy relay_via_ice. Clearing
|
||||
* it here destroys the completed agents before LAUNCH can take them. */
|
||||
caps_local.relay_via_ice = caps_local.relay_host &&
|
||||
g_relay_via_ice_pref && rnet_host_ice_available();
|
||||
g_lc.match_caps = caps_local;
|
||||
send = &caps_local;
|
||||
}
|
||||
|
||||
@@ -548,6 +548,10 @@ int psx_netplay_input_delay(void) { return 2; }
|
||||
int psx_netplay_catchup_budget(void) { return 0; }
|
||||
void psx_netplay_catchup_consume_frame(void) {}
|
||||
void psx_netplay_wait_recv(int timeout_ms) { (void)timeout_ms; }
|
||||
void psx_netplay_link_diag(char *out, size_t cap)
|
||||
{
|
||||
if (out && cap) snprintf(out, cap, "off");
|
||||
}
|
||||
void psx_netplay_admit_wait_info(char *stall_out, size_t stall_cap,
|
||||
uint32_t *sim_tick_out, int *lead_out)
|
||||
{
|
||||
@@ -4378,7 +4382,7 @@ int psx_netplay_start(const PsxNetplayConfig *cfg)
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_ice) {
|
||||
if (!use_ice && !ice_hub) {
|
||||
/* Host-as-relay: slot 0 with 3+ seats and no dial peer. */
|
||||
#if PSX_MAX_PLAYERS >= 3
|
||||
const int peer_empty =
|
||||
@@ -5680,6 +5684,31 @@ void psx_netplay_wait_recv(int timeout_ms)
|
||||
(void)rnet_session_wait_recv(g_np.session, timeout_ms);
|
||||
}
|
||||
|
||||
void psx_netplay_link_diag(char *out, size_t cap)
|
||||
{
|
||||
RNetSessionStats st;
|
||||
static const char *const k_state[] = {
|
||||
"idle", "gathering", "connecting", "connected", "completed", "failed"
|
||||
};
|
||||
unsigned si;
|
||||
if (!out || !cap) return;
|
||||
if (!psx_netplay_active() || !g_np.session) {
|
||||
snprintf(out, cap, "inactive");
|
||||
return;
|
||||
}
|
||||
memset(&st, 0, sizeof(st));
|
||||
rnet_session_get_stats(g_np.session, &st);
|
||||
si = (unsigned)st.ice_state;
|
||||
snprintf(out, cap,
|
||||
"ice=%s path=%s local=%s remote=%s rx=%u recv_drops=%u rx_age_ms=%llu",
|
||||
si < sizeof(k_state) / sizeof(k_state[0]) ? k_state[si] : "?",
|
||||
st.ice_path[0] ? st.ice_path : "-",
|
||||
st.ice_local[0] ? st.ice_local : "-",
|
||||
st.ice_remote[0] ? st.ice_remote : "-",
|
||||
(unsigned)st.packets_rx, (unsigned)st.ice_recv_drops,
|
||||
(unsigned long long)st.last_peer_rx_age_ms);
|
||||
}
|
||||
|
||||
void psx_netplay_admit_wait_info(char *stall_out, size_t stall_cap,
|
||||
uint32_t *sim_tick_out, int *lead_out)
|
||||
{
|
||||
|
||||
@@ -218,6 +218,67 @@ static void case_profile_settings_roundtrip(void)
|
||||
!strcmp(g_lc.match_caps.mods[0].feats, caps.mods[0].feats), "trusted settings survive the online lobby codec");
|
||||
}
|
||||
|
||||
static void case_full_title_profile_version(void)
|
||||
{
|
||||
static char version[64];
|
||||
static PSXModNetplayProfile profile = {0};
|
||||
char wire[768];
|
||||
memset(version, 'v', sizeof(version) - 1);
|
||||
version[sizeof(version) - 1] = '\0';
|
||||
profile.plugin_id = "lobby.profile.test";
|
||||
profile.compatibility_id = version;
|
||||
ck(psx_mod_register_netplay_profile(&profile), "register maximum-length title profile");
|
||||
psx_lobby_set_game_identity("Profile Fixture", version);
|
||||
ck(!strcmp(g_lc.filter_game_version, version), "retain all 63 profile bytes in local metadata");
|
||||
/* Suppress discovery: this fixture checks the native codec/filter only. */
|
||||
g_list_rtt_active = 1;
|
||||
snprintf(wire, sizeof(wire), "{\"op\":\"lobby_list\",\"lobbies\":[{"
|
||||
"\"lobby_id\":\"profile-room\",\"name\":\"Profile Room\","
|
||||
"\"game_name\":\"Profile Fixture\",\"game_version\":\"%s\"}]}", version);
|
||||
handle_server_json(wire);
|
||||
ck(g_lc.list_count == 1, "matching full profile remains visible");
|
||||
ck(!strcmp(g_lc.list[0].game_version, version), "room metadata retains full profile");
|
||||
/* A difference beyond the former 31-byte prefix must still reject. */
|
||||
char *last = strstr(wire, version);
|
||||
if (last) last[62] = 'w';
|
||||
ck(last != NULL, "locate profile in fixture");
|
||||
handle_server_json(wire);
|
||||
ck(g_lc.list_count == 0, "reject profile differing only in final byte");
|
||||
g_list_rtt_active = 0;
|
||||
}
|
||||
|
||||
static void case_start_retains_relay_path(void)
|
||||
{
|
||||
PsxLobbyMatchCaps caps = {0}, decoded;
|
||||
char wire[4096];
|
||||
int prefer, host;
|
||||
const int old_pref = g_relay_via_ice_pref;
|
||||
printf(" START keeps the advertised relay path locally\n");
|
||||
for (prefer = 0; prefer < 2; ++prefer) {
|
||||
for (host = 0; host < 2; ++host) {
|
||||
memset(&g_lc, 0, sizeof(g_lc));
|
||||
/* An unhandshaken fixture queues START without touching a socket. */
|
||||
g_lc.connected = g_lc.in_lobby = g_lc.is_host = 1;
|
||||
g_lc.fd = 0;
|
||||
caps.valid = 1;
|
||||
caps.relay_host = host;
|
||||
caps.relay_via_ice = 0; /* fresh launcher caps, as in the regression */
|
||||
strcpy(caps.session_bios, "openbios");
|
||||
psx_lobby_set_relay_via_ice_pref(prefer);
|
||||
ck(psx_lobby_request_start(&caps) == 0, "queue host START");
|
||||
ck(psx_lobby_encode_match_caps(wire, sizeof(wire), &caps) &&
|
||||
psx_lobby_decode_match_caps(wire, &decoded), "decode advertised START caps");
|
||||
ck(g_lc.match_caps.relay_via_ice == decoded.relay_via_ice,
|
||||
"local ICE path matches the wire before LAUNCH arrives");
|
||||
ck(room_relays_via_ice() == (host && prefer && rnet_host_ice_available()),
|
||||
"waiting-room agents remain active for an ICE host START");
|
||||
}
|
||||
}
|
||||
memset(&g_lc, 0, sizeof(g_lc));
|
||||
g_lc.fd = -1;
|
||||
psx_lobby_set_relay_via_ice_pref(old_pref);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
case_room_order();
|
||||
@@ -226,6 +287,8 @@ int main(void)
|
||||
case_long_line_is_truncated_not_dropped();
|
||||
case_mod_caps_roundtrip();
|
||||
case_profile_settings_roundtrip();
|
||||
case_full_title_profile_version();
|
||||
case_start_retains_relay_path();
|
||||
if (g_failures == 0) {
|
||||
printf("lobby_chat_ring_test: ok\n");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user