Steam: the lobby + IDENTITY-TOKEN roster -- internet MP code-complete (step 4c)

NEW gated (BT_STEAM) game/glass/btl4lobby: an ISteamMatchmaking room replacing
the arcade Site-Management screen -- host creates (lobby data btl4=1), members
join by filter, pilots publish name/mech/color, the host ENTER mints the
roster and signals GO.

THE FAKEIP LESSON (live-verified, prior-art assumption DISPROVEN): a fresh
process gets a DIFFERENT FakeIP, so menu-time fake addresses go stale by
mission time -- the first cycle timed out connecting to its own stale address.
Redesign: roster addresses are opaque ipv4-shaped TOKENS (169.254.77.N with
ports 1501/1502) minted by the host at GO, mapped to Steam IDENTITIES;
connections ride ConnectP2P(identity, channel) with console=0/game=1 virtual
ports; the map reaches mission processes via env (BT_FE_MYFAKE +
BT_FE_STEAMMAP); the GetMyAddress seam feeds the pod its own token for roster
self-match; CheckSocket reports peers by token.  L4STEAMNET reworked (no
FakeIP allocation at all); the marshal gained the Steam-wire branch.

Verified single-machine (ON/ON, live Steam): menu -> HOST STEAM LOBBY ->
room -> GO -> token map minted -> egg roster carries the token -> mission
process up with 1 roster token incl. self -> pod self-matches -> stock
console ladder -> mission RUNS (46 ticks).  Remaining: the live 2-account
cross-machine session (docs/STEAM_TEST.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-18 00:03:17 -05:00
co-authored by Claude Fable 5
parent 48ede2f7d7
commit f703bb1d56
11 changed files with 875 additions and 124 deletions
+108 -12
View File
@@ -68,6 +68,56 @@ struct MarshalState
static MarshalState marshalState;
//
// The Steam-wire branch (BT_STEAM): a pod whose console address is a
// FakeIP is reached through the engine's Steam transport (munga_engine)
// instead of raw Winsock -- same wire bytes, different carrier.
//
#ifdef BT_STEAM
extern int BTSteamNet_IsFakeAddress(unsigned long internet_address_be);
extern SOCKET BTSteamNet_Connect(unsigned long internet_address_be, int remote_port);
extern int BTSteamNet_Owns(SOCKET wire_socket);
extern int BTSteamNet_Send(SOCKET wire_socket, const char *data, int length);
extern int BTSteamNet_Recv(SOCKET wire_socket, char *buffer, int capacity);
extern void BTSteamNet_Close(SOCKET wire_socket);
#endif
static int
MarshalIsSteam(SOCKET s)
{
#ifdef BT_STEAM
return BTSteamNet_Owns(s);
#else
(void)s;
return 0;
#endif
}
static int
MarshalSend(SOCKET s, const char *data, int length)
{
#ifdef BT_STEAM
if (BTSteamNet_Owns(s))
{
return BTSteamNet_Send(s, data, length);
}
#endif
return send(s, data, length, 0);
}
static void
MarshalClose(SOCKET s)
{
#ifdef BT_STEAM
if (BTSteamNet_Owns(s))
{
BTSteamNet_Close(s);
return;
}
#endif
closesocket(s);
}
//###########################################################################
void
@@ -199,7 +249,7 @@ static int
PutInt32(packet + 32, wire_length);
PutInt32(packet + 36, this_length);
memcpy(packet + 40, wire + off, this_length);
if (send(s, (const char *)packet, sizeof(packet), 0) != sizeof(packet))
if (MarshalSend(s, (const char *)packet, sizeof(packet)) != sizeof(packet))
{
return -1;
}
@@ -222,7 +272,7 @@ static int
PutInt32(packet + 16, 12);
PutInt32(packet + 20, message_id);
PutInt32(packet + 24, ReliableFlag);
return (send(s, (const char *)packet, sizeof(packet), 0) == sizeof(packet))
return (MarshalSend(s, (const char *)packet, sizeof(packet)) == sizeof(packet))
? 0 : -1;
}
@@ -233,6 +283,24 @@ static int
static SOCKET
ConnectWithRetry(const char *host, int port, int attempts)
{
#ifdef BT_STEAM
{
unsigned long address_be = inet_addr(host);
if (address_be != INADDR_NONE && BTSteamNet_IsFakeAddress(address_be))
{
for (int attempt = 0; attempt < attempts; ++attempt)
{
SOCKET s = BTSteamNet_Connect(address_be, port);
if (s != INVALID_SOCKET)
{
return s;
}
Sleep(1000);
}
return INVALID_SOCKET;
}
}
#endif
for (int attempt = 0; attempt < attempts; ++attempt)
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -348,24 +416,52 @@ static DWORD WINAPI
char drain[4096];
while (GetTickCount() < mission_end)
{
//
// select() only understands REAL sockets; Steam pseudo-sockets
// drain nonblocking on their own pass.
//
fd_set readable;
FD_ZERO(&readable);
int real_count = 0;
for (int p = 0; p < pod_count; ++p)
{
FD_SET(pods[p], &readable);
}
timeval tv = { 1, 0 };
int ready = select(0, &readable, NULL, NULL, &tv);
if (ready > 0)
{
for (int p = 0; p < pod_count; ++p)
if (!MarshalIsSteam(pods[p]))
{
if (FD_ISSET(pods[p], &readable))
FD_SET(pods[p], &readable);
++real_count;
}
}
if (real_count > 0)
{
timeval tv = { 1, 0 };
int ready = select(0, &readable, NULL, NULL, &tv);
if (ready > 0)
{
for (int p = 0; p < pod_count; ++p)
{
recv(pods[p], drain, sizeof(drain), 0);
if (!MarshalIsSteam(pods[p]) &&
FD_ISSET(pods[p], &readable))
{
recv(pods[p], drain, sizeof(drain), 0);
}
}
}
}
else
{
Sleep(1000);
}
#ifdef BT_STEAM
for (int p = 0; p < pod_count; ++p)
{
if (MarshalIsSteam(pods[p]))
{
while (BTSteamNet_Recv(pods[p], drain, sizeof(drain)) > 0)
{
}
}
}
#endif
}
MarshalLog("mission clock expired -- StopMission to all pods");
@@ -376,7 +472,7 @@ static DWORD WINAPI
Sleep(MissionEndGraceSeconds * 1000);
for (int p = 0; p < pod_count; ++p)
{
closesocket(pods[p]);
MarshalClose(pods[p]);
}
MarshalLog("relaunching the menu");