Commit Graph
4 Commits
Author SHA1 Message Date
Joe DiPrimaandClaude Opus 5 2df1369168 #116 THE REAL STEAM CAUSE: experience never rode the lobby -- joiners' pages were authored by the HOST as the "veteran" fallback
The user's question broke my first story: "did lynx host tho?"  He did (Oracle
joined LYNX's lobby that night) -- but more importantly the affected players'
logs read mode=steam, which gets the FULL menu, so the FeJoinOnly fix in
3109cfc patched a real gap (mode=join) that is NOT the path the affected trio
ran.  Oracle COULD see and cycle the selector; it still didn't matter.  Traced:

  * The steam lobby serialized exactly three member fields: nm / vh / cl.
    Experience never travelled.
  * The steam HOST rebuilds mission.pilots[] from the lobby roster
    (name/vehicle/color only), so every non-self page has EMPTY experience --
    and BTFeMission_WriteEgg stamps the "veteran" fallback on empty.
  * The steam JOINER writes NO egg at all (spec->eggPath[0]=0); his mission
    arrives from the HOST's console feed -- i.e. the host's egg, where HIS
    page says veteran no matter what his own console shows.
  * The host's own page keeps his menu choice only as slot-0 residue of the
    pre-roster self fill -- why BOTH hosts (Sauron AND Lynx) were clean while
    all three joiners heated in "standard".

FIX: experience is now published as lobby member data ("xp") beside nm/vh/cl,
unpacked into BTLobbyMember, and stamped onto each member's egg page in the
host's roster loop.  Both exported lobby entry points + PublishSelf gain the
parameter; the fe passes the local menu selection.  An older client in the
lobby simply has no "xp" -- the veteran fallback applies to THAT member only,
exactly the pre-fix behavior, so mixed-build lobbies do not break.

Per-player mixing (the original design, per the user: the sysop set each
user's tier; mixed matches were legal) now works over steam end to end: each
member's OWN choice -> lobby -> the host-authored egg page -> the console feed
-> that node's master player.

VERIFICATION BOUNDARY: builds both configs; the chain is code-traced; the
lobby legs need a real Steam session -- field re-test is a JOINER selecting
Standard and logging [exp] experience=1 heatModelOn=0 (plus the [fe] line on
both sides).  The 3109cfc join-trim selector stays: correct for mode=join.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 10:50:19 -05:00
Joe DiPrimaandClaude Opus 5 1777d5a62e one log per day, and every log says who it sent it -- rotation was eating the crash stacks
Conn Man crashed twice in an Owens on 2026-07-27, kept playing, and by the time
we asked for his logs they no longer existed.  Not a mystery: every launcher did

    if exist content\X.old.log del content\X.old.log
    if exist content\X.log     ren content\X.log X.old.log

which keeps TWO generations.  He relaunched more than twice, so his own bat
deleted both crash sessions.  The player who crashes is exactly the player who
relaunches immediately, so the retention window was aimed at the wrong case.

THE LOG.  BT_LOG set still means "use this path verbatim" -- that contract is
load-bearing (mp_a.log/mp_b.log for 2-node runs from one cwd, btoperator's
operator_N.log, every scratchpad/mp_*.sh that greps the file it named) and is
untouched.  Only when BT_LOG is UNSET does the exe now name the file itself:
content\<stem>_YYYYMMDD.log, appended, one per day, no rotation window to fall
out of.  The stem (solo/join/steam/joyconfig) comes from the gates the bat
already sets, so solo still cannot overwrite the MULTIPLAYER log.

Self-named files append UNCONDITIONALLY.  The default open mode is ios::out --
TRUNCATE -- and the operator GUI's exported bats never set BT_LOG_APPEND, so
they were truncating already; leaving append implicit would have let the second
launch of the day erase the morning.

IDENTITY, because these arrive from many players at once and Discord renames
half of them to message.txt (most of the night-5 evidence had to be
re-identified by hand):

    ===== BT411 SESSION  build=4.11.603 (d64d75f+)  machine=...  user=...
          callsign=Conn Man  mode=solo  pid=13192  local=...  log=... =====

Also the session separator inside a per-day file, and it puts build+hash ABOVE
any [crash] block so btl4+0xNNNN offsets stay matchable to a PDB across builds.

SIZE.  Never delete, but stay sendable: past 8 MB the next launch rolls to
<stem>_YYYYMMDD.1.log.  Checked only at open, so a live session is never split.

CONSOLIDATION.  launch_report.txt is gone, folded into lastrun_<stem>.txt (one
launch record: the exe appends its block at first breath, the bat appends the
exit line).  Per-stem because one shared lastrun.txt let a second launcher's
`del` destroy the first launch's block.  Its ABSENCE after a run is now the
#41 "never reached WinMain" probe -- the old "if not exist X.log" test cannot
work against a per-day file, which survives earlier launches, and would have
reported every healthy run as blocked by antivirus.  marshal.log folded into
the day log too; it keeps its own handle and gained a CRITICAL_SECTION because
it runs on a worker thread while the engine log stream is single-threaded.
play_steam.bat gained a launch bracket it never had -- which is why a Steam
player killed before WinMain previously left no evidence at all.

_putenv_s, not SetEnvironmentVariableA, to pin the resolved name: MSVC's CRT
keeps its own environment copy, so getenv() in-process does NOT see a
SetEnvironmentVariableA write (measured).  btl4console/btl4lobby resolve the
day log via getenv, so with the Win32-only call they silently fell back to
marshal.log and the fold never happened.

logfile.open() is now checked -- a failed open used to rebind cout to a dead
buffer, silently dropping the header, [boot] and any crash stack while
lastrun still claimed log=<name>.

Verified: append across sessions with distinct pids, crash block landing under
its own header, BT_LOG verbatim unmangled, an inherited BT_LOG cleared by the
bats, roll-over at 8 MB, and both forensic verdicts (exe ran / exe blocked).
Console auto-retrieval is unaffected -- it uploads the matchlog, a different
file, and a crashed round never reaches the upload call anyway.

Known gaps, deliberately not in this commit: the setlocal hoist for gate
leakage when two bats share one console (dev-only), and btoperator's exported
bats still lack the lastrun bracket -- do not press Export on a shipped zip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 10:33:07 -05:00
CydandClaude Fable 5 8cf2cc1f07 FE: the RP412 menu + lobby-room pattern; flat single-exe dist (per Cyd)
Menu (btl4fe, modeled on RP412 RP_L4/RPL4FE.cpp): full catalogs as
always-visible clickable LISTS in three columns with friendly names --
8 maps, the canonical 8 certified mechs, colors, times, weather, lengths,
modes -- bright/dim green with a selection chevron, double-buffered paint,
real EDIT controls for pilot name + LAN peers (green-on-black via
WM_CTLCOLOREDIT), framed LAUNCH / HOST STEAM / JOIN STEAM buttons, and the
loadout persisted across the per-mission relaunch (fe_last.ini, gitignored
implicitly by *.ini? no -- plain file beside the eggs).  ENTER/ESC kept.

Lobby room (RP412 RPL4LOBBY look): pilot roster with loadouts (mech, color),
framed L A U N C H  M I S S I O N (owner) + LEAVE LOBBY buttons, clickable.

Dist: FLAT layout (the RP412 convention) -- ONE btl4.exe entry point at the
folder root beside the content tree (the shape TeslaConsole manages), DLLs +
launchers at root, content flattened from git-tracked files.  Verified: the
staged flat tree boots the Mission Console zero-arg from its own root; the
click-driven menu launches a full marshaled mission (row click -> length=60
in the egg, LAUNCH click -> ladder -> 41+ ticks, fe_last.ini written).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:54: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