From 1a5a4a220c1297b9e20f69bc5eb629f78e4547db Mon Sep 17 00:00:00 2001 From: Cyd Date: Mon, 10 Aug 2026 15:14:18 -0500 Subject: [PATCH] A Live Cam host brings no vehicle Picking Live Cam and then hosting still showed the host in the room with a VTV and a colour, because the room row draws whatever loadout the member published and nothing on the wire said the host had given up its grid slot. The lobby now publishes a cam key with the rest of the member data, carries it in MemberInfo, and the owner's row reads LIVE CAM where a loadout would go. The loadout itself still goes out unchanged. Live Cam is a role, not a vehicle, so vh/cl/bd keep carrying what was picked and switching back to Racer finds it all still there. Only the owner's row shows it. The host is the one that writes the egg, so the host's pick is the only one acted on; a member who set Live Cam is still going to race, and its row goes on saying so. Painting every cam=1 row as LIVE CAM would have the room screen lying about the grid. Letting members spectate too is a real feature - the same hostType=1 on their egg entry, plus a guard that one racer is left - but it is not this change. Co-Authored-By: Claude Opus 5 (1M context) --- RP_L4/RPL4FE.cpp | 6 ++++++ RP_L4/RPL4FE.h | 10 ++++++++++ RP_L4/RPL4LOBBY.cpp | 30 +++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/RP_L4/RPL4FE.cpp b/RP_L4/RPL4FE.cpp index 9cb3407..7603933 100644 --- a/RP_L4/RPL4FE.cpp +++ b/RP_L4/RPL4FE.cpp @@ -2267,6 +2267,12 @@ Logical return gHavePersist && IsFootball(gPersistSelection); } +Logical + RPL4FrontEnd_IsCameraRole() +{ + return gHavePersist && WantsCamera(gPersistSelection); +} + void RPL4FrontEnd_SetHostedPilots( const char *owner_address, diff --git a/RP_L4/RPL4FE.h b/RP_L4/RPL4FE.h index b6bf02c..1ad3643 100644 --- a/RP_L4/RPL4FE.h +++ b/RP_L4/RPL4FE.h @@ -110,6 +110,16 @@ void Logical RPL4FrontEnd_IsFootballSelected(); +// +// True when this player's setup menu has YOUR ROLE on Live Cam. Only the +// HOST's pick is acted on - the host is the one that writes the egg - so +// the lobby publishes this and then shows it against the owner's row +// only. A member who picked it still races, which is what their row goes +// on saying. +// +Logical + RPL4FrontEnd_IsCameraRole(); + // Hosted-race pilots fed by the Steam lobby: overrides the // RP412HOSTPODS parsing with real personas and loadouts. owner_address // is this pod's mesh IP (the FakeIP); count 0 clears the override. diff --git a/RP_L4/RPL4LOBBY.cpp b/RP_L4/RPL4LOBBY.cpp index 01118f2..549065d 100644 --- a/RP_L4/RPL4LOBBY.cpp +++ b/RP_L4/RPL4LOBBY.cpp @@ -65,6 +65,9 @@ namespace const char kNetRevision[] = "2"; const char kNetRevKey[] = "nr"; + // this member picked Live Cam rather than a grid slot + const char kCamKey[] = "cam"; + // the owner's mission setup, shown to everyone in the room const char kMapKey[] = "mp"; const char kTimeKey[] = "td"; @@ -172,6 +175,15 @@ namespace SteamMatchmaking()->SetLobbyMemberData(gLobby, "cl", color); SteamMatchmaking()->SetLobbyMemberData(gLobby, "bd", badge); + // + // Live Cam. The loadout above still goes out unchanged - the pick + // is a role, not a vehicle, and it is only acted on for the host, + // so a member's own row must go on showing what it will really + // fly. The room screen reads this against the owner's row. + // + SteamMatchmaking()->SetLobbyMemberData(gLobby, kCamKey, + RPL4FrontEnd_IsCameraRole() ? "1" : "0"); + // football: this member's own team and position pick SteamMatchmaking()->SetLobbyMemberData(gLobby, "tm", RPL4FrontEnd_TeamKey(RPL4FrontEnd_GetTeamIndex())); @@ -246,6 +258,7 @@ namespace char team[32]; // football pick char position[16]; char netRev[8]; // simulation protocol revision + Logical camera; // picked Live Cam (acted on for the host) Logical published; }; @@ -289,6 +302,9 @@ namespace strncpy(member->netRev, SteamMatchmaking()->GetLobbyMemberData(gLobby, member->id, kNetRevKey), sizeof(member->netRev) - 1); + member->camera = (atoi( + SteamMatchmaking()->GetLobbyMemberData(gLobby, member->id, kCamKey)) != 0) + ? True : False; member->published = member->ip[0] != '\0' && member->consolePort > 0 && member->gamePort > 0; } @@ -566,7 +582,19 @@ namespace // travel on the wire; the catalogs turn them back into // names, so nobody reads "bttlbrg". //----------------------------------------------------------- - if (FootballLobby()) + // + // A Live Cam host brings no vehicle, so its row says the role + // instead of a loadout. Only the owner's row: the host writes + // the egg, so only the host's pick is acted on, and a member + // who set Live Cam is still going to race - saying otherwise + // here would be the room screen lying about the grid. + // + if (member->camera && is_owner_row) + { + DrawTextA(mem, "LIVE CAM", -1, &row, + DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + } + else if (FootballLobby()) { if (member->team[0] != '\0') {