Commit Graph
5 Commits
Author SHA1 Message Date
arcattackandClaude Opus 5 ecb9b338bd the X button means QUIT: a user-closed window exits for real instead of relaunching
Operator report (00:30): "my local instance auto-relaunches whenever I stop and
start a session, even if I close my window."  Root cause is the pod's AUTHENTIC
immortality: an arcade cabinet's join loop never exits, so every RunMissions
return relaunches into the join wait -- and a human closing the window was
indistinguishable from a round ending.  On a desktop that made the client
unkillable outside Task Manager, and explains every orphaned-plasma zombie
hunted this week (my own test teardowns included), plus tonight's "eventually
all I could find was my plasma display".

FIX, one flag + one gate:
  * btl4main WndProc WM_CLOSE stamps gBTUserRequestedExit before DestroyWindow
    (covers X, Alt-F4, taskbar close, Task Manager's polite phase).
  * BTFE_RelaunchSelfAndExit -- the single choke point every relaunch path
    funnels through (round end, console-pad lost, round abort, FE loop) --
    exits for real when the flag is set, logging 'window closed by the user
    -- exiting for real (no relaunch)' to the marshal log.

Round-end auto-rejoin is UNTOUCHED: the flag only sets on WM_CLOSE.

VERIFIED both directions on the built exe (4.11.591):
  * WM_CLOSE posted to a live solo instance -> the whole process tree is GONE
    8s later: no relaunched generation, no plasma orphan.  [was: immortal]
  * Offset-port rig, full launch -> StopMission -> both pods AUTO-REJOINED and
    re-ACKed for the next round (2/2 ready, WAITING FOR OPERATOR); zero
    exiting-for-real lines fired (nobody closed a window).

Requires the next zip for players; the operator's running instance keeps the
old behavior until restarted onto this build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 00:38:05 -05:00
CydandClaude Opus 5 8408165d92 Find content\ ourselves: a bare exe launch no longer scatters config and dies
Field report: `.\btl4.exe -fit` from build\Release opens the mission console,
then the mission crashes on Launch.

ROOT CAUSE (pre-existing landmine, newly reachable).  The engine resolves
BTL4.RES, VIDEO\, BTDPL.INI, the eggs AND both player config files
(bindings.txt, environ.ini) RELATIVE TO CWD.  Every launcher .bat does
`cd content` first, so this never showed.  A bare launch of the exe therefore
found no resources ("Resource file btl4.res v1.0.0.0 is obsolete!"), wrote a
stray bindings.txt / environ.ini / btl4.log NEXT TO THE EXE -- so the player's
real ones in content\ looked like they had never been created -- and killed the
mission generation the menu launched (the child inherits the parent's cwd).

Recent work made that path inviting rather than obscure: glass is the desktop
default, a zero-arg launch opens the menu, and -fit is documented as something
you pass on the command line.

FIX: BTEnsureContentDirectory() runs before anything resolves a relative path
(the log file included, so a bare launch logs where the launchers log).  If cwd
has no BTL4.RES, probe from the exe's own directory -- ..\..\content for the
shipped layout, plus the flattened and in-content cases -- and
SetCurrentDirectory there.  Says so in the boot line when it had to go looking.
Belt and braces: the environ.ini writer refuses to write unless BTL4.RES is
beside it, so a failed probe cannot scatter a settings file either.

ALSO: -fit was silently dropped when the menu relaunched into a mission.  The
front end rebuilds the child's command line from scratch, and the flag was
parsed at window creation -- code the menu process exits long before reaching.
Parsed early into gBTFitDisplay now, and appended to the relaunch.

Verified: bare `btl4.exe -fit` from build\Release leaves ZERO files next to the
exe, writes environ.ini + btl4.log into content\, and the mission child's exact
command line (-net 1501 -platform glass) from that same wrong cwd now logs
"cwd: found the content directory from the exe path", loads resources and
enters RunMissions instead of dying.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 02:41:46 -05:00
arcattackandClaude Opus 4.8 d3ede2e635 Issue #33/#34: relaunch-storm + duplicate-seat fixes (pod-grade session stability)
Night-2 capture: one flapping pod cascaded 3 ROUND ABORTs in 8s; every
client relaunch-churned (~1 gen/s) until the D3D device-creation 20s
deadline fired on every machine ('could not connect direct 3d'), and
claim-less restarts minted duplicate roster seats.

Console (relay):
- Round abort clears stale console-conn ACK flags and HOLDS the next
  egg release for an 8s settle window (_tick_settle re-releases when
  quiet) -- the abort->instant-re-release->drop->abort cycle is broken.
- HELLO from a stale identity gets a REJOIN reply (identity resync via
  the seat-request path, 5s/IP rate limit) instead of a bare drop.
- STATIC SEATS: seats remember (IP + callsign); a claim-less restart
  from the same machine+name RECLAIMS its own seat (displacing its
  zombie beacon) instead of minting a duplicate -- the pod contract:
  same box, same seat, always.
- Operator local instances log with BT_LOG_APPEND (the night-2 crash
  loop left a 2-line file; generations now leave a full trail).

Client:
- Relaunch storm damper: a generation that lived <15s sleeps 5s before
  respawning (storm decays to a gentle cadence; normal multi-minute
  round relaunches untouched; menu clicks explicitly never delayed).

Rig-verified: normal round + mid-MISSION drop = no abort (correct);
mid-LOAD kill = exactly ONE abort + 8s hold + seat reclaimed + no
cascade.  The night-2 'host 7' identity-derivation subtlety remains
under forensics (append logs + first-breath line will capture it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 23:35:25 -05:00
CydandClaude Fable 5 f703bb1d56 Steam: the lobby + IDENTITY-TOKEN roster -- internet MP code-complete (step 4c)
NEW gated (BT_STEAM) game/glass/btl4lobby: an ISteamMatchmaking room replacing
the arcade Site-Management screen -- host creates (lobby data btl4=1), members
join by filter, pilots publish name/mech/color, the host ENTER mints the
roster and signals GO.

THE FAKEIP LESSON (live-verified, prior-art assumption DISPROVEN): a fresh
process gets a DIFFERENT FakeIP, so menu-time fake addresses go stale by
mission time -- the first cycle timed out connecting to its own stale address.
Redesign: roster addresses are opaque ipv4-shaped TOKENS (169.254.77.N with
ports 1501/1502) minted by the host at GO, mapped to Steam IDENTITIES;
connections ride ConnectP2P(identity, channel) with console=0/game=1 virtual
ports; the map reaches mission processes via env (BT_FE_MYFAKE +
BT_FE_STEAMMAP); the GetMyAddress seam feeds the pod its own token for roster
self-match; CheckSocket reports peers by token.  L4STEAMNET reworked (no
FakeIP allocation at all); the marshal gained the Steam-wire branch.

Verified single-machine (ON/ON, live Steam): menu -> HOST STEAM LOBBY ->
room -> GO -> token map minted -> egg roster carries the token -> mission
process up with 1 roster token incl. self -> pod self-matches -> stock
console ladder -> mission RUNS (46 ticks).  Remaining: the live 2-account
cross-machine session (docs/STEAM_TEST.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:03:17 -05:00
CydandClaude Fable 5 c4ca87b808 Miniconsole: the front end + LocalConsole marshal -- self-launched missions (step 3)
NEW gated dir game/glass/: btl4fe (green-on-black GDI catalog menu -- map/
time/weather/length/mech/color/pilot/mode/port/peers; egg writer emitting the
FULL console egg shape, golden-tested vs MP.EGG: identical section sequence
at identical line offsets, the 4 static ordinal pages verbatim, GDI-rendered
128x32/64x16 pilot-name plasma bitmaps in MP.EGG framing) and btl4console
(the marshal: a worker-thread console CLIENT speaking the btconsole.py wire
protocol verbatim -- 1040-byte chunked egg, 20s settle, RunMission x2,
STAY CONNECTED, own the clock, StopMission at expiry; logs marshal.log).
The engine sees a real connected console and runs the 100% stock ladder --
NO engine hooks (less invasive than planned: the L4APP.H setters proved
unnecessary; launches go through real argv on relaunch).

WinMain (one gated block): zero-mission-arg glass launch -> menu -> relaunch
self with the mission argv (per-mission process relaunch; BT_FE_* env arms
the marshal); post-RunMissions BT_FE_LOOP tail returns to the menu.  Menu
relaunches CLEAR the BT_FE_* handoff (found live: the inherited env re-armed
a marshal instead of showing the menu).

Verified end-to-end (synthetic menu drive): menu -> frontend.egg -> relaunch
-> marshal feeds self over loopback -> stock console ladder -> mission RUNS
(58+ ticks) -> 60s clock -> StopMission -> clean menu return, no env leak.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:33:39 -05:00