Members get the score sheet: owner publishes results through the lobby
Round seven was the first complete Steam race: three machines, five minutes, wall deaths respawning, the console ending the race on time, and rematches launched from the same lobby. The one gap the run showed: only the owner saw scores - members went straight back to the room. The owner now publishes its console results (host, score, name, keyed by the race nonce) into lobby data right after teardown; members pull the sheet (waiting up to 8s for it to land), inject it into the local results intake, and the same RACE RESULTS screen shows on every machine before the room. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "rpl4pb.h"
|
||||
#include "rpl4fe.h"
|
||||
#include "rpl4console.h"
|
||||
#include "rpl4lobby.h"
|
||||
#include "..\munga_l4\l4steamtransport.h"
|
||||
#include "..\munga_l4\l4splr.h"
|
||||
#include "rpl4ver.h"
|
||||
@@ -279,6 +280,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
}
|
||||
|
||||
// lobby races: the owner publishes the score sheet, members
|
||||
// pull it - the same results screen shows on every machine
|
||||
RPL4Lobby_PushRaceResults();
|
||||
RPL4Lobby_PullRaceResults();
|
||||
|
||||
// last race's final scores first (no-op on first boot)
|
||||
if (!RPL4FrontEnd_ShowResults(hInstance, hWnd))
|
||||
{
|
||||
|
||||
@@ -703,3 +703,33 @@ const char *
|
||||
}
|
||||
return gPilotNames[index];
|
||||
}
|
||||
|
||||
void
|
||||
RPL4LocalConsole_ClearResults()
|
||||
{
|
||||
gResultCount = 0;
|
||||
gPilotNameCount = 0;
|
||||
}
|
||||
|
||||
void
|
||||
RPL4LocalConsole_InjectResult(int host_ID, int score, const char *name)
|
||||
{
|
||||
if (gResultCount >= maxResults)
|
||||
{
|
||||
return;
|
||||
}
|
||||
gResults[gResultCount].hostID = host_ID;
|
||||
gResults[gResultCount].score = score;
|
||||
++gResultCount;
|
||||
|
||||
int index = host_ID - firstPilotHostID;
|
||||
if (name != NULL && index >= 0 && index < maxRemotePods + 1)
|
||||
{
|
||||
strncpy(gPilotNames[index], name, sizeof(gPilotNames[index]) - 1);
|
||||
gPilotNames[index][sizeof(gPilotNames[index]) - 1] = '\0';
|
||||
if (index >= gPilotNameCount)
|
||||
{
|
||||
gPilotNameCount = index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,3 +55,11 @@ Logical
|
||||
// NULL when unknown - the results screen falls back to pod numbers.
|
||||
const char *
|
||||
RPL4LocalConsole_GetResultName(int host_ID);
|
||||
|
||||
// Lobby members do not marshal races - the owner publishes the score
|
||||
// sheet through lobby data and it is injected here so the same results
|
||||
// screen shows on every machine.
|
||||
void
|
||||
RPL4LocalConsole_ClearResults();
|
||||
void
|
||||
RPL4LocalConsole_InjectResult(int host_ID, int score, const char *name);
|
||||
|
||||
@@ -15,10 +15,13 @@ Logical RPL4Lobby_InRoom() { return False; }
|
||||
int RPL4Lobby_Host(HINSTANCE, HWND) { return LobbyRoomLeft; }
|
||||
int RPL4Lobby_Join(HINSTANCE, HWND) { return LobbyRoomLeft; }
|
||||
int RPL4Lobby_Room(HINSTANCE, HWND) { return LobbyRoomLeft; }
|
||||
void RPL4Lobby_PushRaceResults() { }
|
||||
void RPL4Lobby_PullRaceResults() { }
|
||||
|
||||
#else
|
||||
|
||||
#include "rpl4fe.h"
|
||||
#include "rpl4console.h"
|
||||
#include "..\munga_l4\l4steamtransport.h"
|
||||
|
||||
#pragma pack(push, 8)
|
||||
@@ -40,6 +43,8 @@ namespace
|
||||
CSteamID gLobby;
|
||||
Logical gInLobby = False;
|
||||
int gLastGoNonce = 0; // launches we already answered
|
||||
int gShownResultsNonce = 0; // score sheets we already displayed
|
||||
const char kResultsKey[] = "res";
|
||||
|
||||
// async call-result plumbing
|
||||
Logical gCallDone = False;
|
||||
@@ -696,4 +701,104 @@ int
|
||||
return RunRoom(instance, main_window);
|
||||
}
|
||||
|
||||
void
|
||||
RPL4Lobby_PushRaceResults()
|
||||
{
|
||||
if (!gInLobby || !IsOwner() || RPL4LocalConsole_ResultCount() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SteamAPI_RunCallbacks();
|
||||
|
||||
char sheet[600];
|
||||
sprintf(sheet, "%d:", gLastGoNonce);
|
||||
for (int i = 0; i < RPL4LocalConsole_ResultCount(); ++i)
|
||||
{
|
||||
int host_ID, score;
|
||||
if (!RPL4LocalConsole_GetResult(i, &host_ID, &score))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const char *name = RPL4LocalConsole_GetResultName(host_ID);
|
||||
char entry[80];
|
||||
sprintf(entry, "%d|%d|%.30s;", host_ID, score,
|
||||
(name != NULL) ? name : "");
|
||||
if (strlen(sheet) + strlen(entry) < sizeof(sheet))
|
||||
{
|
||||
strcat(sheet, entry);
|
||||
}
|
||||
}
|
||||
SteamMatchmaking()->SetLobbyData(gLobby, kResultsKey, sheet);
|
||||
gShownResultsNonce = gLastGoNonce; // the owner sees its own screen
|
||||
DEBUG_STREAM << "Lobby: results published (" << sheet << ")\n" << std::flush;
|
||||
}
|
||||
|
||||
void
|
||||
RPL4Lobby_PullRaceResults()
|
||||
{
|
||||
if (!gInLobby || IsOwner() || gLastGoNonce == gShownResultsNonce)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// The owner publishes right after its race teardown - ours may
|
||||
// finish first, so give the sheet a moment to arrive
|
||||
//
|
||||
const char *sheet = NULL;
|
||||
DWORD deadline = GetTickCount() + 8 * 1000;
|
||||
for (;;)
|
||||
{
|
||||
SteamAPI_RunCallbacks();
|
||||
sheet = SteamMatchmaking()->GetLobbyData(gLobby, kResultsKey);
|
||||
if (sheet != NULL && sheet[0] != '\0' && atoi(sheet) == gLastGoNonce)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((LONG)(GetTickCount() - deadline) >= 0)
|
||||
{
|
||||
return; // no sheet for this race - skip the screen
|
||||
}
|
||||
Sleep(100);
|
||||
}
|
||||
gShownResultsNonce = gLastGoNonce;
|
||||
|
||||
RPL4LocalConsole_ClearResults();
|
||||
const char *cursor = strchr(sheet, ':');
|
||||
cursor = (cursor != NULL) ? cursor + 1 : sheet;
|
||||
while (*cursor != '\0')
|
||||
{
|
||||
int host_ID = atoi(cursor);
|
||||
int score = 0;
|
||||
char name[32] = "";
|
||||
while (*cursor != '\0' && *cursor != '|' && *cursor != ';') ++cursor;
|
||||
if (*cursor == '|')
|
||||
{
|
||||
score = atoi(++cursor);
|
||||
while (*cursor != '\0' && *cursor != '|' && *cursor != ';') ++cursor;
|
||||
}
|
||||
if (*cursor == '|')
|
||||
{
|
||||
++cursor;
|
||||
int n = 0;
|
||||
while (cursor[n] != '\0' && cursor[n] != ';' &&
|
||||
n < (int) sizeof(name) - 1)
|
||||
{
|
||||
name[n] = cursor[n];
|
||||
++n;
|
||||
}
|
||||
name[n] = '\0';
|
||||
cursor += n;
|
||||
}
|
||||
while (*cursor != '\0' && *cursor != ';') ++cursor;
|
||||
if (*cursor == ';') ++cursor;
|
||||
|
||||
if (host_ID > 0)
|
||||
{
|
||||
RPL4LocalConsole_InjectResult(host_ID, score, name);
|
||||
}
|
||||
}
|
||||
DEBUG_STREAM << "Lobby: results pulled for race " << gLastGoNonce << "\n" << std::flush;
|
||||
}
|
||||
|
||||
#endif // RP412_STEAM
|
||||
|
||||
@@ -46,3 +46,12 @@ int
|
||||
// Re-enter the room of the lobby we are already in (post-race).
|
||||
int
|
||||
RPL4Lobby_Room(HINSTANCE instance, HWND main_window);
|
||||
|
||||
// Post-race score sheet: the owner publishes its console's results
|
||||
// into lobby data; members pull them into the local results intake so
|
||||
// the same results screen shows everywhere. Both are no-ops when not
|
||||
// in a lobby (or not the respective role).
|
||||
void
|
||||
RPL4Lobby_PushRaceResults();
|
||||
void
|
||||
RPL4Lobby_PullRaceResults();
|
||||
|
||||
Reference in New Issue
Block a user