Writes the title's internal 'live user' flag byte (0x83028851, derived from
sub_8263E788's lis -32003 / lbz -30639 = recompiler value -2097348608 ->
0x83030000 - 0x77AF) to 1 so the frontend stops refusing Xbox Live features
before it ever calls a rexglue API. Logs the first force.
Adds an 'xnet trace' log to the online-path functions (XNetGetTitleXnAddr,
XNetGetEthernetLinkStatus, QosListen/QosLookup, CreateKey, Connect,
GetConnectStatus, XamUserGetSigninState/Info, XamShowSigninUI, privilege)
gated on the xnet_trace cvar (default on during bring-up, rate-limited for
the polling signin-state calls). Running the game and clicking the online
flow now shows exactly which gate the party/EA path hits, so we can fix the
real check instead of guessing at the reverse-engineered globals.
The game's party state machine (57.cpp sub_82A1B310 state 1) freezes on
'connecting to EA Nation' because it gates on (XNetGetTitleXnAddr status &
0x60) == online AND XNetGetEthernetLinkStatus() != 0 to pick the online EA
server. rexglue returned STATIC (1) + link 0, so the state machine never
advanced. Now:
- XNetGetTitleXnAddr returns status 0x60 (the game's online bits; it checks
(status & 0x60) in the EA resolver and session join) and populates
inaOnline with the virtual IP.
- XNetGetEthernetLinkStatus returns active+100Mbps.
With the ONLINE status the party machine proceeds to CreateKey/RegisterKey,
the sign-in gate, XNetConnect and the session-ready state.
- Deadlock: SetRelay held the transport mutex while join()ing the receive
thread, which needs the mutex to observe running_ and exit. With the 200ms
recv timeout the thread woke and hit the lock -> a room/server change froze
the game (every room keystroke reconnects the transport). StopThread now
detaches the thread under the lock and joins WITHOUT it.
- XamUserCheckPrivilege denied everything, which is the gate the game's
'create a party' flow checks (multiplayer sessions); grant requested
privileges so the P2P session flow opens, and log the mask.
The game gates its online/team flow on XamUserGetSigninState == 2 ('make a
team', 'connect to EA Nation' refused with error 1245 otherwise). rexglue
only returned 2 when user_live_signed_in was set, which defaulted to false,
so the game never opened its P2P session/invite flow. Default the cvar to
true so the netcode revival can reach the session code.
The Run thread blocked in recvfrom with no SO_RCVTIMEO, so when there was no
inbound game traffic the 4s heartbeat never fired (the relay swept the
silent transport client after ~8s) AND StopLocked()'s join() deadlocked
SetRelay on a room change (hanging the ghost network loop). A 200ms receive
timeout wakes the loop regularly: the heartbeat keeps the transport alive
and shutdown/room-change joins complete promptly.
- #pragma pack(push,1) on the wire structs (the relay's proto is packed; the
transport's were not, which would inflate sizes and corrupt every datagram)
plus static_asserts pinning sizes to 7/31/1410/25/801.
- Heartbeat re-JOIN every 4s so the relay never times the transport out.
- REXLOG info for connect/join/session-reply so the flow is observable.
Route the game's own RakNet UDP through the ghost relay so real internet
peers can play, with the server as a pure relay/NAT stabilizer:
- XNetTransport: a rexglue relay client (joins the same relay + room as the
ghost client), a receive thread, and:
- SendGame(): wraps a datagram addressed to a virtual 10.80.0.x peer in a
relay Game payload and sends it OUTBOUND to the relay (no inbound
reachability / port forwarding needed).
- QuerySessions()/Sessions(): discovery - the room members that
XNetQosLookup reports to the game's session search.
- Receive injection: relayed Game payloads are pushed into the game's
registered sockets via XSocket::QueuePacket.
- XSocket: SendTo() to a virtual address routes through the transport;
RecvFrom() drains queued relayed packets first; sockets register with the
transport on Initialize.
- XNetQosLookup: queries the relay and returns the room's members as
discovered sessions (with their virtual addresses), signaling completion.
- XNetGetTitleXnAddr identity now shares one source of truth with the
transport (same 10.80.0.x).
Wire structs are minimal copies of the game's ghost protocol (kept
dependency-free); the relay's version check refuses mismatches.
- cvar.cpp: the static FlagRegistrar destructors run during __cxa_finalize
and touch the registry after its function-local statics are destroyed
(static destruction-order fiasco) - the codegen tool segfaults at exit.
Leak the registry/mutex/index so teardown order cannot bite.
- imgui_drawer.cpp: drop ImFontConfig::RasterizerGamma assignments (removed
from imgui); keeps the build working with the modern imgui a fresh
submodule checkout provides (the pinned imgui commit no longer exists).