Leaving early keeps the points earned

From the playtest: a member who Alt+Q's mid-race vanishes from the host's
score sheet, as though they had not raced at all. A pod that leaves never
sends its EndMission score - that message belongs to the buzzer - and the
sheet only ever held what EndMission delivered.

The pods have been telling the console their score all along:
ConsolePlayerVTVScoreUpdate telemetry fed the arcade console's status
board, and this console skipped it ('IDs 2-6 skip through for now'). It
now keeps the last score each pod reported, together with the host ID the
pod itself put in the message - no arithmetic about egg order to get
wrong - and at the buzzer any pod that is not there to answer has its
last telemetry score stood in and named in the log. Leaving early keeps
what was earned; it just stops earning.

Also on the leaver's own machine: RPL4Lobby_PullRaceResults gave every
member eight seconds of frozen window waiting for a score sheet - but an
aborter leaves a race still running everywhere else, whose sheet will not
exist for minutes. Exit_Code carries the abort at that moment (the race
loop resets it after the menu), so the wait becomes one free look. The
sheet's nonce keeps it eligible to show once the race really ends.

The member's drop-to-desktop after Alt+Q is NOT fixed here - it is not
yet diagnosed, and this session has spent enough confident guesses. The
next piece of evidence that names it is the member machine's rpl4.log
tail from right after an abort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-11 23:27:44 -05:00
co-authored by Claude Opus 5
parent bdc5df087e
commit 1e0c412102
2 changed files with 56 additions and 3 deletions
+45 -1
View File
@@ -81,6 +81,9 @@ namespace
NetTransport::Connection
connection;
int state; // last reported application state (-1 unknown)
int lastScore; // last telemetry score heard mid-race
int lastScoreHostID; // the host ID the pod itself reported
Logical haveScore; // any telemetry score at all yet
Logical eggAcknowledged;
DWORD lastQueryTick;
DWORD eggSentTick; // 0 = never sent
@@ -300,7 +303,27 @@ namespace
(int) message->GetFinalScore());
pod->scored = True;
}
// VTV telemetry (IDs 2-6) skips through for now
//
// Running telemetry. The pods have been sending it all
// along (it fed the arcade console's status board); this
// console skipped it - until a player Alt+Q'ed mid-race
// and vanished from the score sheet, because a pod that
// leaves never sends its EndMission score. Keep the last
// score heard, and the host ID the pod itself reported
// with it, so the buzzer can stand it in for a pod that
// is not there to answer. Leaving early keeps the points
// earned; it just stops earning more.
//
else if ((int) base->messageID ==
ConsolePlayerVTVScoreUpdateMessageID)
{
ConsolePlayerVTVScoreUpdateMessage *message =
(ConsolePlayerVTVScoreUpdateMessage *) base;
pod->lastScore = (int) message->GetPlayerScore();
pod->lastScoreHostID = (int) message->GetPlayerHostID();
pod->haveScore = True;
}
// the rest of the telemetry (IDs 2-4, 6) skips through
}
else if ((int) header->clientID == (int) NetworkClient::NetworkManagerClientID)
{
@@ -914,6 +937,27 @@ namespace
else if (AllRemotesScored() ||
(LONG)(GetTickCount() - gRemoteStopTick) >= 5000)
{
//
// Stand in for anyone who is not here to answer. A pod
// that left mid-race - Alt+Q, a crash, a dropped link -
// never sends EndMission, and used to vanish from the
// score sheet as though it had not raced at all. Its
// last telemetry score is the score it left with.
//
for (int i = 0; i < gRemotePodCount; ++i)
{
if (!gRemotePods[i].scored && gRemotePods[i].haveScore)
{
DEBUG_STREAM << "LocalConsole: "
<< gRemotePods[i].address
<< " never reported - keeping its last"
<< " telemetry score\n" << std::flush;
CollectFinalScore(
gRemotePods[i].lastScoreHostID,
gRemotePods[i].lastScore);
gRemotePods[i].scored = True;
}
}
DispatchLocalStop();
DisconnectRemotes();
}
+11 -2
View File
@@ -1604,10 +1604,19 @@ void
//
// The owner publishes right after its race teardown - ours may
// finish first, so give the sheet a moment to arrive
// finish first, so give the sheet a moment to arrive.
//
// Unless WE aborted. An Alt+Q leaves a race that is still running
// everywhere else, and its sheet will not exist for minutes - the
// eight second wait below was eight seconds of frozen window for a
// player who had just asked to leave. Exit_Code carries the abort
// (the race loop resets it after the menu); take one free look and
// otherwise skip - the sheet's nonce keeps it eligible to show
// after the race actually ends.
//
const char *sheet = NULL;
DWORD deadline = GetTickCount() + 8 * 1000;
DWORD deadline = (Exit_Code != 0)
? GetTickCount() : GetTickCount() + 8 * 1000;
for (;;)
{
SteamAPI_RunCallbacks();