Steam lobby: host, join, room, and launch into a marshaled race
RPL4LOBBY implements the multiplayer front door on ISteamMatchmaking. The setup menu grows HOST STEAM RACE / JOIN STEAM RACE buttons when the Steam wire is live; hosting creates a tagged public lobby, joining finds one. Every member publishes FakeIP + fake ports + persona + loadout as member data; the room screen lists members (host marked) and gives the owner a launch button. Launching writes a nonced go-roster into lobby data. Each pod registers every peer with the Steam transport (two-port peer table: engine console/game ports map to Steam fake ports on connect) and enters the race: the owner through the hosted-race path - it builds the multi-pilot egg from real personas and loadouts and its console marshals everyone - and members as network pods that boot straight into WaitingForEgg for the owner to feed over the wire. The lobby outlives races: members loop back through WinMain into the room (no local console needed - MissionCompleted is waived for member races), and the owner returns to the room after its results screen. Leaving the lobby clears the hosted-race priming. Verified on this box: menu buttons appear under RP412STEAM=1, hosting creates a lobby on the Steam backend, the room runs and leaves back to the menu; single-player cycling and the LAN hosted race both still pass. Full three-account mesh test is next, on real hardware. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,9 +58,13 @@ namespace
|
||||
struct PeerRecord
|
||||
{
|
||||
unsigned long fakeIP; // host order
|
||||
unsigned short fakeConsolePort; // host order
|
||||
unsigned short fakeGamePort; // host order
|
||||
};
|
||||
|
||||
// engine-side port convention (lobby default; game port is +1)
|
||||
unsigned short gEngineConsolePort = 1501;
|
||||
|
||||
Logical gSteamReady = False;
|
||||
unsigned long gLocalFakeIP = 0; // host order
|
||||
unsigned short gLocalFakePorts[2] = { 0, 0 };
|
||||
@@ -136,14 +140,17 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
// engine port in a SOCKADDR_IN -> the peer's matching fake port
|
||||
unsigned short
|
||||
LookupPeerFakeGamePort(unsigned long fake_ip_host)
|
||||
LookupPeerFakePort(unsigned long fake_ip_host, unsigned short engine_port)
|
||||
{
|
||||
for (int i = 0; i < gPeerCount; ++i)
|
||||
{
|
||||
if (gPeers[i].fakeIP == fake_ip_host)
|
||||
{
|
||||
return gPeers[i].fakeGamePort;
|
||||
return (engine_port == gEngineConsolePort)
|
||||
? gPeers[i].fakeConsolePort
|
||||
: gPeers[i].fakeGamePort;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -272,8 +279,9 @@ namespace
|
||||
)
|
||||
{
|
||||
unsigned long remote_fake_ip = ntohl(remote->sin_addr.S_un.S_addr);
|
||||
unsigned short fake_game_port = LookupPeerFakeGamePort(remote_fake_ip);
|
||||
if (fake_game_port == 0)
|
||||
unsigned short fake_port =
|
||||
LookupPeerFakePort(remote_fake_ip, ntohs(remote->sin_port));
|
||||
if (fake_port == 0)
|
||||
{
|
||||
DEBUG_STREAM << "SteamNetTransport: no registered peer for "
|
||||
<< inet_ntoa(remote->sin_addr) << " - lobby did not feed it\n" << std::flush;
|
||||
@@ -281,8 +289,8 @@ namespace
|
||||
}
|
||||
|
||||
DEBUG_STREAM << "SteamNetTransport: connecting to "
|
||||
<< inet_ntoa(remote->sin_addr) << " (fake port "
|
||||
<< fake_game_port << ")...\n" << std::flush;
|
||||
<< inet_ntoa(remote->sin_addr) << ":" << ntohs(remote->sin_port)
|
||||
<< " (fake port " << fake_port << ")...\n" << std::flush;
|
||||
|
||||
SteamNetworkingConfigValue_t option;
|
||||
option.SetPtr(
|
||||
@@ -291,7 +299,7 @@ namespace
|
||||
|
||||
SteamNetworkingIPAddr target;
|
||||
target.Clear();
|
||||
target.SetIPv4(remote_fake_ip, fake_game_port);
|
||||
target.SetIPv4(remote_fake_ip, fake_port);
|
||||
|
||||
// mirror the TCP retry-while-refused loop, bounded: the
|
||||
// egg-ACK ordering means the peer may not be listening yet
|
||||
@@ -620,32 +628,56 @@ const char *
|
||||
return gLocalFakeAddressString;
|
||||
}
|
||||
|
||||
int
|
||||
SteamNetTransport_GetFakeConsolePort()
|
||||
{
|
||||
return gLocalFakePorts[0];
|
||||
}
|
||||
|
||||
int
|
||||
SteamNetTransport_GetFakeGamePort()
|
||||
{
|
||||
return gLocalFakePorts[1];
|
||||
}
|
||||
|
||||
void
|
||||
SteamNetTransport_SetEnginePorts(int console_port)
|
||||
{
|
||||
gEngineConsolePort = (unsigned short) console_port;
|
||||
}
|
||||
|
||||
void
|
||||
SteamNetTransport_RegisterPeer(
|
||||
const char *fake_ip,
|
||||
int fake_console_port,
|
||||
int fake_game_port
|
||||
)
|
||||
{
|
||||
if (gPeerCount >= maxPeers)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SteamNetworkingIPAddr parsed;
|
||||
if (!parsed.ParseString(fake_ip))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < gPeerCount; ++i)
|
||||
{
|
||||
if (gPeers[i].fakeIP == parsed.GetIPv4())
|
||||
{
|
||||
gPeers[i].fakeConsolePort = (unsigned short) fake_console_port;
|
||||
gPeers[i].fakeGamePort = (unsigned short) fake_game_port;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (gPeerCount >= maxPeers)
|
||||
{
|
||||
return;
|
||||
}
|
||||
gPeers[gPeerCount].fakeIP = parsed.GetIPv4();
|
||||
gPeers[gPeerCount].fakeConsolePort = (unsigned short) fake_console_port;
|
||||
gPeers[gPeerCount].fakeGamePort = (unsigned short) fake_game_port;
|
||||
++gPeerCount;
|
||||
DEBUG_STREAM << "SteamNetTransport: peer registered: " << fake_ip
|
||||
<< " game port " << fake_game_port << "\n" << std::flush;
|
||||
<< " (console " << fake_console_port << ", game "
|
||||
<< fake_game_port << ")\n" << std::flush;
|
||||
}
|
||||
|
||||
#endif // RP412_STEAM
|
||||
|
||||
@@ -68,15 +68,25 @@ Logical
|
||||
const char *
|
||||
SteamNetTransport_GetFakeAddressString();
|
||||
|
||||
// Our Steam-assigned fake game port (lobby member data).
|
||||
// Our Steam-assigned fake ports (lobby member data): the console
|
||||
// channel and the game mesh.
|
||||
int
|
||||
SteamNetTransport_GetFakeConsolePort();
|
||||
int
|
||||
SteamNetTransport_GetFakeGamePort();
|
||||
|
||||
// The lobby feeds every member's FakeIP + fake game port here before
|
||||
// StartConnecting runs.
|
||||
// The engine-side port convention for this session (default 1501;
|
||||
// game port is +1). Connect() maps an engine port in a SOCKADDR_IN to
|
||||
// the peer's matching Steam fake port.
|
||||
void
|
||||
SteamNetTransport_SetEnginePorts(int console_port);
|
||||
|
||||
// The lobby feeds every member's FakeIP + fake ports here before
|
||||
// anything dials out. Registering is idempotent per IP.
|
||||
void
|
||||
SteamNetTransport_RegisterPeer(
|
||||
const char *fake_ip,
|
||||
int fake_console_port,
|
||||
int fake_game_port
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user