Diagnostics: pre-launch readiness warning + named friend logs (join.log)
Two additions after the live-session troubleshooting: 1. LAUNCH-SHORT is now VISIBLE (btconsole). Pressing LAUNCH with an empty roster seat previously did NOTHING (eggs_done_at only sets when ALL seats ACK, so the manual-launch arming silently no-op'd -- the 'I pressed launch and nothing happened' confusion). Now the relay logs 'LAUNCH pressed but NOT all seats are filled' + a per-seat readiness line + a WARNING naming the empty seat(s) and the fix (reduce the roster). When all seats DO fill it auto-arms (launch request persists). Verified: 2/3 filled -> clear warning naming seat3. 2. Friend logs are now retrievable (btoperator exporter). join.bat / join_lan.bat set BT_LOG=join.log and their exit message tells the player to send content\join.log to the operator if the game closed unexpectedly -- closes the friend-side-crash blind spot (their log was the generic btl4.log, un-named, easy to miss). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9f1bd8d6d4
commit
954175e44e
+5
-3
@@ -2,10 +2,12 @@
|
||||
rem BT411 -- join 107.202.218.169's game (internet). Your seat/mech
|
||||
rem is assigned automatically by the operator console.
|
||||
set BT_RELAY=107.202.218.169:1500
|
||||
set BT_LOG=join.log
|
||||
cd /d %~dp0content
|
||||
..\build\Release\btl4.exe -egg OPERATOR.EGG -net 1501
|
||||
echo.
|
||||
echo The game has exited. If you did NOT quit on purpose,
|
||||
echo the session may not be running yet or the server was
|
||||
echo unreachable -- check with the operator and try again.
|
||||
echo The game has exited. If you did NOT quit on purpose
|
||||
echo (crash, or it never connected), send the operator the
|
||||
echo file content\join.log so they can see what happened.
|
||||
echo Otherwise the session may not be up yet -- try again.
|
||||
pause
|
||||
|
||||
@@ -3,10 +3,12 @@ rem BT411 -- join the game from the operator's OWN
|
||||
rem network (LAN) -- finds the console automatically.
|
||||
rem Joining over the INTERNET? Use join.bat instead.
|
||||
set BT_RELAY=auto
|
||||
set BT_LOG=join.log
|
||||
cd /d %~dp0content
|
||||
..\build\Release\btl4.exe -egg OPERATOR.EGG -net 1501
|
||||
echo.
|
||||
echo The game has exited. If you did NOT quit on purpose,
|
||||
echo the session may not be running yet or the server was
|
||||
echo unreachable -- check with the operator and try again.
|
||||
echo The game has exited. If you did NOT quit on purpose
|
||||
echo (crash, or it never connected), send the operator the
|
||||
echo file content\join.log so they can see what happened.
|
||||
echo Otherwise the session may not be up yet -- try again.
|
||||
pause
|
||||
|
||||
+36
-7
@@ -284,6 +284,7 @@ class Relay:
|
||||
self.manual_launch = manual_launch
|
||||
self._reserved_tags = set(reserved_tags or ())
|
||||
self.launch_requested = False # set by the operator (stdin)
|
||||
self._launch_blocked_warned = False # warned once about empty seats
|
||||
self.stop_requested = False # operator 'stop' (End Mission)
|
||||
self.mission_length = parse_egg_mission_length(egg_path)
|
||||
self.mission_started_at = None # set when RunMission #2 fires
|
||||
@@ -463,18 +464,46 @@ class Relay:
|
||||
if conn in self.console_conns:
|
||||
self.console_conns.remove(conn)
|
||||
|
||||
def _log_launch_readiness(self):
|
||||
# PRE-LAUNCH READINESS (2026-07-18): make the "launching short" footgun
|
||||
# VISIBLE. A roster seat with no registered pod means the mission will
|
||||
# STALL -- every pod waits on that empty seat's connection and the
|
||||
# All-connections-completed gate never fires. Log filled vs empty
|
||||
# seats so the operator sees it BEFORE the confusion.
|
||||
filled, empty = [], []
|
||||
for i, tag in enumerate(self.roster):
|
||||
host_id = FIRST_GAME_HOST_ID + i
|
||||
(filled if host_id in self.by_host else empty).append(
|
||||
f"seat{i + 1}({tag})")
|
||||
print(f"[relay] LAUNCH readiness: {len(filled)}/{len(self.roster)} "
|
||||
f"seats filled -- {', '.join(filled) or 'NONE'}", flush=True)
|
||||
if empty:
|
||||
print(f"[relay] *** WARNING: {len(empty)} EMPTY seat(s): "
|
||||
f"{', '.join(empty)} -- the mission will STALL (every pod "
|
||||
f"waits on the empty seat). Stop, reduce the roster to the "
|
||||
f"players present, and re-launch.", flush=True)
|
||||
|
||||
def _tick_launch(self):
|
||||
# Manual mode: the operator's 'launch' arms the timer, still honouring
|
||||
# the settle window (pods must reach WaitingForLaunch or the handler
|
||||
# Fail()s -- the same reason the auto timer waits).
|
||||
if (self.manual_launch and self.launch_requested
|
||||
and self.launch_at is None and self.eggs_done_at is not None
|
||||
and self.launches_sent == 0):
|
||||
self.launch_at = max(time.time(),
|
||||
self.eggs_done_at + LAUNCH_SETTLE_SECONDS)
|
||||
wait = max(0.0, self.launch_at - time.time())
|
||||
print(f"[relay] operator LAUNCH received; firing in {wait:.0f}s",
|
||||
flush=True)
|
||||
and self.launch_at is None and self.launches_sent == 0):
|
||||
if self.eggs_done_at is not None:
|
||||
self.launch_at = max(time.time(),
|
||||
self.eggs_done_at + LAUNCH_SETTLE_SECONDS)
|
||||
wait = max(0.0, self.launch_at - time.time())
|
||||
print(f"[relay] operator LAUNCH received; firing in "
|
||||
f"{wait:.0f}s", flush=True)
|
||||
self._log_launch_readiness()
|
||||
elif not self._launch_blocked_warned:
|
||||
# Operator pressed LAUNCH but the gate is NOT ready (not every
|
||||
# roster seat has ACKed its egg) -- previously this did NOTHING
|
||||
# visible ("I pressed launch and nothing happened"). Say WHY.
|
||||
self._launch_blocked_warned = True
|
||||
print("[relay] LAUNCH pressed but NOT all seats are filled:",
|
||||
flush=True)
|
||||
self._log_launch_readiness()
|
||||
if self.launch_at is None or self.launches_sent >= 2:
|
||||
return
|
||||
if time.time() < self.launch_at:
|
||||
|
||||
+6
-3
@@ -756,15 +756,17 @@ class Operator(QMainWindow):
|
||||
# file -- who flies which mech is whoever sits down first, exactly
|
||||
# like walking up to a pod.
|
||||
tail = ("echo.\n"
|
||||
"echo The game has exited. If you did NOT quit on purpose,\n"
|
||||
"echo the session may not be running yet or the server was\n"
|
||||
"echo unreachable -- check with the operator and try again.\n"
|
||||
"echo The game has exited. If you did NOT quit on purpose\n"
|
||||
"echo (crash, or it never connected), send the operator the\n"
|
||||
"echo file content\\join.log so they can see what happened.\n"
|
||||
"echo Otherwise the session may not be up yet -- try again.\n"
|
||||
"pause\n")
|
||||
with open(os.path.join(out_dir, "join.bat"), "w", newline="\r\n") as f:
|
||||
f.write("@echo off\n"
|
||||
"rem BT411 -- join %s's game (internet). Your seat/mech\n"
|
||||
"rem is assigned automatically by the operator console.\n"
|
||||
"set BT_RELAY=%s:%d\n"
|
||||
"set BT_LOG=join.log\n"
|
||||
"cd /d %%~dp0content\n"
|
||||
"..\\build\\Release\\btl4.exe -egg %s -net 1501\n"
|
||||
% (host, host, self.f_port.value(), egg_name) + tail)
|
||||
@@ -775,6 +777,7 @@ class Operator(QMainWindow):
|
||||
"rem network (LAN) -- finds the console automatically.\n"
|
||||
"rem Joining over the INTERNET? Use join.bat instead.\n"
|
||||
"set BT_RELAY=auto\n"
|
||||
"set BT_LOG=join.log\n"
|
||||
"cd /d %%~dp0content\n"
|
||||
"..\\build\\Release\\btl4.exe -egg %s -net 1501\n"
|
||||
% egg_name + tail)
|
||||
|
||||
Reference in New Issue
Block a user