diff --git a/RP_L4/RPL4.CPP b/RP_L4/RPL4.CPP index a0ca74b..42150f7 100644 --- a/RP_L4/RPL4.CPP +++ b/RP_L4/RPL4.CPP @@ -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)) { diff --git a/RP_L4/RPL4CONSOLE.cpp b/RP_L4/RPL4CONSOLE.cpp index a4514a6..3de0906 100644 --- a/RP_L4/RPL4CONSOLE.cpp +++ b/RP_L4/RPL4CONSOLE.cpp @@ -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; + } + } +} diff --git a/RP_L4/RPL4CONSOLE.h b/RP_L4/RPL4CONSOLE.h index f936b42..94d6045 100644 --- a/RP_L4/RPL4CONSOLE.h +++ b/RP_L4/RPL4CONSOLE.h @@ -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); diff --git a/RP_L4/RPL4LOBBY.cpp b/RP_L4/RPL4LOBBY.cpp index 929e871..1264262 100644 --- a/RP_L4/RPL4LOBBY.cpp +++ b/RP_L4/RPL4LOBBY.cpp @@ -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 diff --git a/RP_L4/RPL4LOBBY.h b/RP_L4/RPL4LOBBY.h index 845b910..ccffaa4 100644 --- a/RP_L4/RPL4LOBBY.h +++ b/RP_L4/RPL4LOBBY.h @@ -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();