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>
102 lines
4.6 KiB
Python
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()
|