3.3 KiB
Netcode revival (branch netcode-revival)
Goal: revive Skate 3's original Xbox 360 multiplayer — the game's own
RakNet-based peer-to-peer netcode — instead of only the ghost co-presence
layer. main keeps the working ghost multiplayer + releases; this branch
carries the netcode work and stays clearly separate.
The transport is RakNet over XNet/XSocket (confirmed: rexglue's XNet
comments reference RakNet, and the game's socket → setsockopt → bind → sendto sequence matches RakPeer::Startup). The game speaks its own
protocol; we only need the platform netcode layer to work (implement
rexglue's stubbed XNet session APIs + route the game's UDP through the
relay). We do not decode the game protocol.
Architecture
- Virtual addressing: each machine gets a stable
XNADDR(virtual IP10.80.0.x+ unique 6-byteabEnet→ RakNet GUID).XNetXnAddrToInAddr/XNetServerToInAddrresolve those into the socket layer's address space. - Relay = P2P stabilizer: session UDP is forwarded outbound through the
relay (tagged
gamevsghost) to the destination member's real socket; on a LAN the transport can go direct. The server stabilizes NAT/remote play but is not required on a LAN. - Session registry in the relay:
XNetQosListenadvertises a session;XNetQosLookupreturns discovered sessions; the lobby/room-code UI stays as the manual join path. - Ghost layer is kept as the guaranteed fallback (co-presence that works for everyone even if the netcode path fails).
Phase 0 — XNet session/address layer (done, rexglue 767bd6e)
Implemented in rexglue-sdk/src/kernel/xam/xam_net.cpp:
XNetGetTitleXnAddr: stable virtual identity (was loopback +0xCCMAC).XNetXnAddrToInAddr/XNetInAddrToXnAddr/XNetServerToInAddr/XNetXnAddrToMachineId/XNetInAddrToString: resolve virtual addresses (were failure /666.666.666.666).XNetQosListen: accept advertisement (wasX_ERROR_FUNCTION_FAILED).XNetQosLookup: success + emptyXNQOS+ completion signal (Phase 1 fills it from the relay registry).XNetCreateKey/XNetRegisterKey/XNetUnregisterKey: session keys.XNetConnect/XNetGetConnectStatus: report established.getsockopt: real basic reads off the native socket.XNetSetSystemLinkPort: accept.
Phase 1 — relay game-transport + session registry (next)
- Extend
ghost_relayto forward game UDP between room members + expose the session list thatXNetQosLookupreads. - Give rexglue
XSocketa relay-transport mode (recognize10.80.0.xvirtual destinations; route via the relay outbound). - Test: two game instances on one machine (loopback through the relay) reach a joined session.
Phase 2 — invite UI
XamShowGameInviteUI/XamShowFriendsUIas ImGuiXamDialogs backed by the relay lobby (real player list). Receive side (XamNotifyCreateListener/XamSessionRefObjByHandle) already works.
Phase 3 — iterate to playable
Whatever the game needs past discovery (RakNet handshake, ports, privilege fakes). Ghost stays as fallback throughout.
Notes
- Testing is done with two instances on one machine (no second device);
the relay loops them via
127.0.0.1. A headless harness may be added. - Build:
clang-22override, presetlinux-relwithdebinfo, perdocs/build.md— same asmain.