Lobby loop: auto-rejoin between rounds + seat reclaim + live mission edits

The between-rounds arcade flow (first-playtest-night field request): at
mission end every pod exited, seats dropped, and every round required
everyone to re-run join.bat with no way to adjust the mission.

1. AUTO-REJOIN: StopMission (operator END / mission clock -- NOT a
   window close) sets gBTMissionStoppedByConsole; after the matchlog
   upload btl4main relaunches the pod into the join wait with the same
   cmdline (BT_CALLSIGN/BT_MECH ride the inherited environment).

2. SEAT RECLAIM: the assigned tag is mirrored file-scope
   (BTRelaySelfTag) and re-presented as the 3rd SEAT_REQUEST payload
   field (BT_SEAT_CLAIM); the relay holds a dropped seat for its tag
   for 90s and a returning player gets their EXACT seat back -- static
   ordering across rounds, the real-pod model.  Non-claim joiners skip
   reclaim-held seats.

3. LIVE MISSION EDITS: the console gains "Apply mission settings"
   (enabled while a session runs) writing arena/time/weather/length
   into the session egg; the relay re-reads the file at round reset and
   egg release (roster shape locked mid-session).

Verified 2-pod 3-round: pods self-relaunched after each clock end; the
SECOND-to-rejoin still reclaimed its original seat (ordering held); the
between-rounds edit landed ("mission length now 75s").  Known edge
noted in the KB: a stale ready flag from a not-yet-exited old conn can
satisfy the launch gate mid-rejoin -- operators launch on green dots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 00:28:56 -05:00
co-authored by Claude Opus 4.8
parent fa935777cc
commit 8368163b04
7 changed files with 178 additions and 11 deletions
+10
View File
@@ -1688,6 +1688,16 @@ void
Check(message);
Verify(message->messageID == StopMissionMessageID);
// AUTO-REJOIN flag (2026-07-23): a StopMission (operator END or the
// mission clock) is the ARCADE end of a round -- distinct from the player
// closing the window. btl4main relaunches into the join wait when set,
// so the same players flow into the next round without re-running
// join.bat (and reclaim their seats -- see L4NET BT_SEAT_CLAIM).
{
extern int gBTMissionStoppedByConsole;
gBTMissionStoppedByConsole = 1;
}
//
//--------------------------------------------------------------------------
// If the application is already stopping then ignore the message
+27 -4
View File
@@ -612,6 +612,21 @@ void BTRelayRememberGameSocket(SOCKET game_socket)
s_relayGameSocketForReady = game_socket;
}
// The assigned seat tag, mirrored file-scope for the between-rounds relaunch
// (the L4NetworkManager -- and its relaySelf -- is gone by then).
static char s_relaySelfTag[64] = "";
void BTRelayRememberSelfTag(const char *tag)
{
strncpy(s_relaySelfTag, tag, sizeof(s_relaySelfTag) - 1);
s_relaySelfTag[sizeof(s_relaySelfTag) - 1] = 0;
}
const char *BTRelaySelfTag(void)
{
return s_relaySelfTag;
}
void BTRelayNotifyReady(void)
{
static int s_ready_sent = 0;
@@ -1777,18 +1792,24 @@ Logical L4NetworkManager::RelayRequestSeat()
// / BT_MECH; they ride the seat request as {callsign NUL mech NUL} and
// the relay writes them into the session egg before it releases eggs.
// Empty payload (no env) = the operator's roster defaults, as before.
char seat_payload[64];
char seat_payload[128];
int seat_payload_length = 0;
{
const char *callsign = getenv("BT_CALLSIGN");
const char *mech_tag = getenv("BT_MECH");
// SEAT RECLAIM (2026-07-23): after a round the auto-rejoin carries
// the previous seat tag -- the relay gives the SAME seat back so
// ordering stays static across rounds (the real-pod model).
const char *claim = getenv("BT_SEAT_CLAIM");
if ((callsign != NULL && callsign[0] != '\0')
|| (mech_tag != NULL && mech_tag[0] != '\0'))
|| (mech_tag != NULL && mech_tag[0] != '\0')
|| (claim != NULL && claim[0] != '\0'))
{
seat_payload_length = _snprintf(seat_payload,
sizeof(seat_payload) - 1, "%s%c%s%c",
sizeof(seat_payload) - 1, "%s%c%s%c%s%c",
callsign != NULL ? callsign : "", 0,
mech_tag != NULL ? mech_tag : "", 0);
mech_tag != NULL ? mech_tag : "", 0,
claim != NULL ? claim : "", 0);
if (seat_payload_length < 0)
seat_payload_length = sizeof(seat_payload) - 1;
}
@@ -1850,6 +1871,8 @@ Logical L4NetworkManager::RelayRequestSeat()
{
memcpy(relaySelf, tag, tag_max);
relaySelf[tag_max] = '\0';
extern void BTRelayRememberSelfTag(const char *);
BTRelayRememberSelfTag(relaySelf);
DEBUG_STREAM << "[relay] seat ASSIGNED: '" << relaySelf
<< "'\n" << std::flush;
got_seat = True;