Twenty-two Fail sites in L4NET.CPP -- the whole console/mesh transport --
replaced with decomp-verified bodies (part_007.c @004501d4..@00452378),
every error string extracted byte-for-byte from the shipped exe, every
magic number resolved to a macro from the AUTHENTIC 1995 NETNUB.HPP that
survives in the archive (NETCOM_VERSION 11; 0x63c == MAX_SEND_DATA_SIZE).
The real-mode bridge came free: the 1995 netshare.OBJ has been linking
into mungal4.lib all along via the prebuilt fallback -- this file only had
to define the six globals it imports and call it. NetNub::SendCommand is
the gateway (setRMBuff, DPMI int 31h/0300h on the TSR's vector, getRMBuff);
BC4.52's <dos.h> really has int386x -- the binary's own "int386x():ERROR="
text named the RTL call.
The topology, decomp-proven: console listens on 1501, the pod mesh on
1502; hosts before ours in the egg get an OPEN, ours becomes the local
host by address match, hosts after ours get a LISTEN -- and CheckBuffers
heals the ordering race by SWAPPING sockets when a peer lands on the wrong
listen. The console's listen is a wildcard that learns its address; the
console connection SURVIVES mission teardown (Shutdown zeroes both
counters anyway -- reproduced faithfully). Send discipline: direct while
the retry buffer is empty, everything queues behind a backlog in per-host
FIFO, one round-robin drain per idle slot; only a dumped-to-avoid-blocking
send is retried, and RemovePacket is empty in the binary because delivery
already compacted the pad buffer. Internal connect/disconnect events ride
the GetNetworkClientPointer(0)->ReceiveNetworkPacket self-dispatch (the
decomp's FUN_0041d7f0 resolves to the ClientID-0-is-me idiom).
Ghidra had dropped register and trailing arguments at half a dozen call
sites (GetRemoteHost's HostID among them) -- the surviving HPP signatures
arbitrated each.
Stubs: 8 across 8 files -- ALL RUNTIME STUBS ARE NOW CLEAR; what remains
is the authoring-side CreateStreamedSubsystem family, which missions never
call. Single-user regression clean on the rig; the networked path awaits
its console + NetNub-TSR live session (two-agreeing-runs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):
- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
+ the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
(standalone-benign ones no-op, network ones Fail loudly) + NetNub client
globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
(MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
tlink emits static-init records in module pull order, and alphabetical
order booted into a null-vptr crash (IcomManager::ClassDerivations
constructing before parent NetworkClient::ClassDerivations). Also fixed
stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
backfills (audio/gauge/resource/stream TUs) that closed the deep ledger
Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
BattleTech v4.10
BTL4Application::BTL4Application
l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>