Files
TeslaRel410/dpl3-revive/patha/run_game.py
T
CydandClaude Fable 5 afc3fd839e Vendor dpl3-revive: the Division/DPL3 renderer, now ours
Bring the graphics-dev collaborator's dpl3-revive into the repo as first-class
project code (they've handed it off; it's ours now). This is the proven
Division renderer that our in-process rt_draw has been trying to be.

What's here:
- parser/  B2Z/V2Z/SVT/SCN/SPL/BGF/BMF/BSL decoders (pure Python).
- spec/    reverse-engineered format + the definitive VelociRender wire
           protocol (from the original DIVISION source, matches our live
           VPX node/action tables exactly).
- source-ref/  read-only copies of the original DIVISION C (BIZREAD.C,
           DPLTYPES.H, DPL.H) that define the formats.
- patha/   the "virtual VelociRender board": vrboard.py (24-action protocol
           server), vrview.py (numpy software rasterizer, the reference),
           vrview_gl.py (moderngl GPU backend, 832x512@60Hz), plus the
           run/replay/regress tooling and evidence renders. Drives FLYK/BLADE/
           Star Trek demos AND our btl4opt/rpl4opt game binaries.
- viewer/  WebGL archive generators (.py); prebuilt HTML/data regeneratable.
- samples/ small test models/textures.
- bt*.raw.bin  real BTL4OPT arena wire captures (kept for offline renderer
           testing/regression against OUR game).

.gitignore keeps the multi-hundred-MB demo capture dumps + debug logs +
regeneratable viewer bundles out of history (they stay on disk).

Phase 0 of the integration is validated: their board decodes our bt8 capture
with zero errors (3748 nodes, 507 instances, 4 mechs) and renders our arena
(terrain/dome/sky, correct Division DAC gamma). Plan + status in memory;
integration continues in emulator/RENDERER-COLLAB.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 22:06:25 -05:00

102 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""
run_game.py -- MUNGA game launcher: run the real Red Planet (rpl4opt) /
BattleTech (btl4opt) game binaries against the virtual VelociRender board.
Mirrors sda4's RP.BAT: `setenv t s n n` (THRUSTMASTER controls, slow clock,
nosound, no gauges), 32RTM.EXE -x (Borland DPMI host -- the game binaries are
PE images, not Watcom LE), <exe> -egg <egg>.egg, 32rtm -u.
python run_game.py # RPDAVE rpl4opt -egg test.egg
python run_game.py --egg last # a different .EGG
python run_game.py --dir BTDAVE --exe btl4opt
python run_game.py --setenv "t s n g" # e.g. g = gauges on
python run_game.py --controls KEYBOARD # exact L4CONTROLS value (setenv's
# presets: t=THRUSTMASTER,KEYBOARD
# r=RIO,KEYBOARD; RIO = the pod's
# serial board, dead hardware)
python run_game.py --soft # software renderer reference
Board loop runs inline (vrrun --view); the wire log is the primary instrument:
unknown actions log as `EXTRA action 0x??`, and a stall right after one means
that action expects a reply (this is how the FLYK protocol was decoded).
"""
import os, sys, subprocess, threading, atexit
HERE = os.path.dirname(os.path.abspath(__file__))
STAGE = r"c:\temp\flykc"
DOSBOX = r"G:\DOSBox-X\dosbox-x-vrlink.exe"
CONF = os.path.join(HERE, "flyk_vr.conf")
def main():
proddir, exe, egg, prefix, senv = "RPDAVE", "rpl4opt", "test", "game", "t s n n"
controls = None
for i, a in enumerate(sys.argv):
if a == "--dir" and i + 1 < len(sys.argv): proddir = sys.argv[i + 1]
if a == "--exe" and i + 1 < len(sys.argv): exe = sys.argv[i + 1]
if a == "--egg" and i + 1 < len(sys.argv): egg = sys.argv[i + 1]
if a == "--prefix" and i + 1 < len(sys.argv): prefix = sys.argv[i + 1]
if a == "--setenv" and i + 1 < len(sys.argv): senv = sys.argv[i + 1]
if a == "--controls" and i + 1 < len(sys.argv): controls = sys.argv[i + 1]
if controls is not None:
# pre-set L4CONTROLS and give SETENV a neutral first arg (anything but
# t/r keeps a pre-existing value -- see SETENV.BAT's CONTROLSDONE path)
senv = "k " + " ".join(senv.split()[1:])
root = os.path.join(STAGE, proddir)
for need in (f"{exe}.exe", "32RTM.EXE", f"{egg}.egg", "SETENV.BAT"):
if not any(f.lower() == need.lower() for f in os.listdir(root)):
raise SystemExit(f"{proddir}\\{need} not staged -- run "
f"stage_assets.py --game {proddir} first")
with open(os.path.join(STAGE, "RUNSCN.BAT"), "w") as fp:
fp.write(f"cd \\{proddir}\r\n")
if controls is not None:
fp.write(f"set L4CONTROLS={controls}\r\n")
fp.write(f"call SETENV.BAT {senv}\r\n"
f"32RTM.EXE -x\r\n")
if "--netnub" in sys.argv:
# pod-network hub wrapper (BTNET.BAT): netnub hosts the wattcp
# net and launches the game with -net; -a forwards the egg args.
# It hard-requires a packet driver ("NO PACKET DRIVER FOUND"):
# load the drive's ODI stack against the emulated NE2000
# (LSL -> NE2000 ODI -> ODIPKT shim on int 0x60), WATTCP.CFG
# gives the pod Milo's IP 200.0.0.86 from the egg
# DOSBox-X embeds the Crynwr NE2000 packet driver on Z: --
# no ODI stack needed (the era-authentic LSL/ODIPKT combo's FTP
# shim can't see Novell MLIDs under DOSBox anyway)
fp.write("Z:\\SYSTEM\\NE2000.COM 0x60 3 0x300\r\n"
f"set WATTCP.CFG=C:\\{proddir}\r\n"
f"NETNUB.EXE -f {exe}.exe -a -egg {egg}.egg\r\n")
else:
fp.write(f"{exe}.exe -egg {egg}.egg\r\n")
fp.write(f"32RTM.EXE -u\r\n")
print(f"game: {proddir}\\{exe} -egg {egg}.egg setenv {senv}"
+ (f" L4CONTROLS={controls}" if controls else "")
+ f" (capture prefix: {prefix})")
proc = []
def launch_dosbox():
env = dict(os.environ, VRLINK='1')
p = subprocess.Popen([DOSBOX, "-conf", CONF], env=env,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
proc.append(p)
print(f"dosbox launched (pid {p.pid})")
threading.Timer(2.0, launch_dosbox).start()
atexit.register(lambda: [p.kill() for p in proc if p.poll() is None])
sys.argv = ["vrrun.py", prefix, "--view"] + (
["--soft"] if "--soft" in sys.argv else [])
import vrrun
try:
vrrun.main()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()