You are never asked what you own. Two controls cannot simply be watched, so they are asked for differently. Yaw is asked for twice, right then left, and which axis answers is the measurement. The same axis both times is one control covering both directions - a twist grip, a rudder bar, pedals the driver has already mixed - and binds to the signed Pedals axis. Two different axes are two real pedals, one per foot, which is what the pod had, so they bind to the pod's own LeftPedal/RightPedal pair and the game does the mixing: both at once then does what both at once did in the pod. The throttle is zeroed first. A lever sits wherever it was last left, possibly hard against the stop that reads +1, so watching it move says nothing about which end means power. Close it, press SPACE, then open it, and the direction it travels from a known idle is the direction that means throttle. CONTROLS.md, the handbook and the packaged README say all of this, and joyconfig.bat's own header no longer promises "rudder-pedal setup" when racing pedals work too.
388 lines
18 KiB
PowerShell
388 lines
18 KiB
PowerShell
# ============================================================================
|
|
# pack-dist.ps1 - assemble a runnable Red Planet 4.12 package into dist\
|
|
# ============================================================================
|
|
#
|
|
# Collects everything the game needs at run time:
|
|
# - Release\rpl4opt.exe (+ .pdb for crash debugging)
|
|
# - game data from assets\RP411 (AUDIO, GAUGE, VIDEO, INIs, RPL4.RES,
|
|
# TEST.EGG) - but not the arcade launch scripts or the old 4.10 exe
|
|
# - libsndfile-1.dll beside the exe; OpenAL32.dll copied from the system
|
|
# when installed, with oalinst.exe included as the fallback installer
|
|
# (environ.ini is NOT shipped - the exe writes it on first run)
|
|
# - start/joyconfig scripts, HANDBOOK.html, VTV-PRESETS.html, TRACKS.html,
|
|
# CONTROLS.txt and a README
|
|
#
|
|
# Usage: powershell -ExecutionPolicy Bypass -File pack-dist.ps1 [-Zip] [-Fresh]
|
|
#
|
|
param(
|
|
[switch]$Zip,
|
|
# Wipe the player's files too, for testing what a first run does.
|
|
[switch]$Fresh
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$dist = Join-Path $root 'dist'
|
|
$assets = Join-Path $root 'assets\RP411'
|
|
$exe = Join-Path $root 'Release\rpl4opt.exe'
|
|
|
|
if (-not (Test-Path $exe)) {
|
|
throw "Release\rpl4opt.exe not found - build first (see BUILD.md 2)."
|
|
}
|
|
|
|
# --- version ---------------------------------------------------------------
|
|
# Read the stamp the exe was BUILT with rather than asking git again: a
|
|
# commit between the build and the pack would otherwise have the package
|
|
# claiming a version the binary inside it does not report.
|
|
$buildHeader = Join-Path $root 'RP_L4\rpl4build.h'
|
|
if (-not (Test-Path $buildHeader)) {
|
|
throw "RP_L4\rpl4build.h not found - build first, or run stamp-version.ps1."
|
|
}
|
|
$stamp = Get-Content $buildHeader -Raw
|
|
$version = ([regex]::Match($stamp, '#define\s+RP412_VERSION\s+"([^"]+)"')).Groups[1].Value
|
|
$versionLong = ([regex]::Match($stamp, '#define\s+RP412_VERSION_LONG\s+"([^"]+)"')).Groups[1].Value
|
|
if (-not $version) { throw "could not read RP412_VERSION from $buildHeader" }
|
|
if ($stamp -match '#define\s+RP412_BUILD_DIRTY\s+1') {
|
|
Write-Warning "packing a build made from a modified tree ($versionLong)"
|
|
}
|
|
Write-Host "Version $versionLong"
|
|
|
|
# Refuse to touch a dist the game is currently running from.
|
|
$running = Get-Process rpl4opt -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.Path -like "$dist\*" }
|
|
if ($running) {
|
|
throw "rpl4opt.exe is running from $dist (PID $($running.Id)) - close the game first."
|
|
}
|
|
|
|
Write-Host "Packing into $dist"
|
|
|
|
# --- the player's own files ------------------------------------------------
|
|
# None of these ship: the game writes each one the first time it needs it and
|
|
# then leaves it alone, so a new build dropped over a folder keeps every
|
|
# setting. This script rebuilds dist\ from scratch, which would throw exactly
|
|
# those away - the one place the promise did not hold, and it is the folder we
|
|
# do most of our own testing in. Carry them across. -Fresh to start over.
|
|
$keepFiles = @('environ.ini', 'bindings.txt', 'pilot.cfg', 'mfd_layout.cfg')
|
|
$kept = @{}
|
|
if (-not $Fresh) {
|
|
foreach ($name in $keepFiles) {
|
|
$path = Join-Path $dist $name
|
|
if (Test-Path $path) { $kept[$name] = [System.IO.File]::ReadAllBytes($path) }
|
|
}
|
|
if ($kept.Count -gt 0) {
|
|
Write-Host " keeping $($kept.Keys -join ', ')"
|
|
}
|
|
} elseif (Test-Path $dist) {
|
|
Write-Host " -Fresh: the player's files go too"
|
|
}
|
|
|
|
if (Test-Path $dist) { Remove-Item -Recurse -Force $dist }
|
|
New-Item -ItemType Directory -Force "$dist\SPOOLS" | Out-Null
|
|
|
|
# --- game binary -----------------------------------------------------------
|
|
Copy-Item $exe $dist
|
|
$pdb = Join-Path $root 'Release\rpl4opt.pdb'
|
|
if (Test-Path $pdb) { Copy-Item $pdb $dist }
|
|
|
|
# steam_api.dll: the exe imports it (RP412_STEAM build). The Steam wire
|
|
# only activates with RP412STEAM=1; plain desktop runs never touch it.
|
|
Copy-Item (Join-Path $root 'extern\steamworks_sdk_164\sdk\redistributable_bin\steam_api.dll') $dist
|
|
|
|
# steam_appid.txt: until RP412 has its own AppID, Steam testing runs
|
|
# under Spacewar (480). Without this file SteamAPI_Init fails and the
|
|
# game falls back to plain TCP - which is exactly the confusing symptom
|
|
# testers hit when the file goes missing. Delete it once we ship under
|
|
# our own AppID (the Steam client provides it then).
|
|
Set-Content -Path "$dist\steam_appid.txt" -Encoding ascii -Value '480'
|
|
|
|
# --- game data -------------------------------------------------------------
|
|
foreach ($dir in 'AUDIO', 'GAUGE', 'VIDEO') {
|
|
Write-Host " copying $dir..."
|
|
Copy-Item -Recurse (Join-Path $assets $dir) $dist
|
|
}
|
|
|
|
# AUDIO1.RES / AUDIO2.RES are Red Planet's original AWE32 soundbanks. They
|
|
# are the SOURCE the shipped WAVs are generated from (tools/rp_sf2extract.py)
|
|
# and are kept in the repo for that, but nothing reads them at run time - the
|
|
# engine's LoadSBK path died with the sound cards, and AUDIO.INI's
|
|
# [AudioResources] section is commented out along with it. Shipping them adds
|
|
# 7MB to every download for nothing.
|
|
#
|
|
# Named explicitly, NOT matched with a wildcard: 'AUDIO?.RES' also catches
|
|
# AUDIO.RES, because a Windows '?' will happily match zero characters.
|
|
#
|
|
foreach ($bank in 'AUDIO1.RES', 'AUDIO2.RES') {
|
|
Remove-Item "$dist\AUDIO\$bank" -ErrorAction SilentlyContinue
|
|
}
|
|
foreach ($file in 'RPDPL.INI', 'JOYSTICK.INI', 'RPL4.RES', 'TEST.EGG',
|
|
'libsndfile-1.dll', 'oalinst.exe') {
|
|
Copy-Item (Join-Path $assets $file) $dist
|
|
}
|
|
|
|
# The controls half as plain text, for Notepad. Flattened to ASCII so it
|
|
# reads correctly there - the markdown source keeps its typography.
|
|
$controls = Get-Content (Join-Path $root 'docs\CONTROLS.md') -Raw -Encoding UTF8
|
|
foreach ($pair in @(
|
|
@([char]0x2014, '-'), @([char]0x2013, '-'), @([char]0x2018, "'"),
|
|
@([char]0x2019, "'"), @([char]0x201C, '"'), @([char]0x201D, '"'),
|
|
@([char]0x00D7, 'x'), @([char]0x2192, '->'), @([char]0x2026, '...'))) {
|
|
$controls = $controls.Replace([string]$pair[0], [string]$pair[1])
|
|
}
|
|
Set-Content -Path "$dist\CONTROLS.txt" -Encoding ascii -Value $controls
|
|
|
|
# The handbook as a page: the controls map with the diagrams, plus the
|
|
# joystick setup and what every file in the folder is for. Its source is
|
|
# the published artifact, which is a fragment - the publisher supplies
|
|
# the document shell - so wrap it to
|
|
# stand alone: without a doctype the browser drops into quirks mode, and
|
|
# without a charset the typography arrives as mojibake. Written without a
|
|
# BOM so the charset declaration is the only thing speaking.
|
|
$handbookPage = Get-Content (Join-Path $root 'docs\rp412-handbook.html') -Raw -Encoding UTF8
|
|
# Stamp the shipped copy with the build's own version. The source keeps a
|
|
# readable one for publishing; only "4.12.<n>" is touched, which on this
|
|
# page is always the version and never anything else.
|
|
$handbookPage = [regex]::Replace($handbookPage, '4\.12\.\d+', $version)
|
|
$page = @"
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
</head>
|
|
<body>
|
|
$handbookPage
|
|
</body>
|
|
</html>
|
|
"@
|
|
[System.IO.File]::WriteAllText(
|
|
"$dist\HANDBOOK.html", $page, (New-Object System.Text.UTF8Encoding $false))
|
|
|
|
# The VTV roster: every vehicle, its loadout and its six control presets,
|
|
# decoded from RPL4.RES. Unlike the handbook this source is already a
|
|
# complete document - it carries its own doctype, charset and viewport - so
|
|
# it ships verbatim rather than being wrapped. Copied as bytes to keep the
|
|
# UTF-8 exactly as written; Copy-Item would do too, but being explicit here
|
|
# matches the handbook above and survives anyone adding a stamp later.
|
|
[System.IO.File]::WriteAllBytes(
|
|
"$dist\VTV-PRESETS.html",
|
|
[System.IO.File]::ReadAllBytes((Join-Path $root 'docs\vtv-presets.html')))
|
|
|
|
# The tracks, drawn from their own instance streams. Same deal - the
|
|
# source is already a complete document, so it ships verbatim too.
|
|
[System.IO.File]::WriteAllBytes(
|
|
"$dist\TRACKS.html",
|
|
[System.IO.File]::ReadAllBytes((Join-Path $root 'docs\tracks.html')))
|
|
|
|
# --- OpenAL runtime --------------------------------------------------------
|
|
# The exe links OpenAL32.dll (32-bit). Prefer shipping the already-installed
|
|
# runtime beside the exe; oalinst.exe covers machines where that misses.
|
|
$openal = "$env:WINDIR\SysWOW64\OpenAL32.dll"
|
|
if (-not (Test-Path $openal)) { $openal = "$env:WINDIR\System32\OpenAL32.dll" }
|
|
if (Test-Path $openal) {
|
|
Copy-Item $openal $dist
|
|
$wrap = Join-Path (Split-Path $openal) 'wrap_oal.dll'
|
|
if (Test-Path $wrap) { Copy-Item $wrap $dist }
|
|
Write-Host " OpenAL runtime copied from $(Split-Path $openal)"
|
|
} else {
|
|
Write-Warning "OpenAL32.dll not found on this system - dist relies on oalinst.exe"
|
|
}
|
|
|
|
# --- desktop configuration -------------------------------------------------
|
|
# --- desktop configuration -------------------------------------------------
|
|
# environ.ini is NOT shipped. The exe carries the template and writes it on
|
|
# first run (RPL4ENVIRON.cpp), the same way it writes bindings.txt - so a
|
|
# tester can drop a new build over an old folder and keep every setting they
|
|
# have changed. Laying one down here would overwrite their file on every
|
|
# unzip, which is the whole problem.
|
|
|
|
Set-Content -Path "$dist\start-windowed.bat" -Encoding ascii -Value @"
|
|
@echo off
|
|
rem Red Planet 4.12 - desktop prototype. Boots into the game-setup
|
|
rem front end. The cockpit fits itself to the window and keeps 16:9,
|
|
rem so a wider screen letterboxes rather than stretching. -res sets the
|
|
rem 3D render size - raise it to match a big screen for sharper pixels,
|
|
rem e.g. -res 2560 1440.
|
|
rem (Add -egg TEST.EGG to skip the menu and run the canned mission.)
|
|
cd /d "%~dp0"
|
|
start rpl4opt.exe -windowed -res 1920 1080
|
|
"@
|
|
|
|
Set-Content -Path "$dist\start-fullscreen.bat" -Encoding ascii -Value @"
|
|
@echo off
|
|
rem Red Planet 4.12 - borderless over the whole monitor. -fit sizes the
|
|
rem window to the panel AND picks the render size to match the cockpit
|
|
rem canvas it lands in, so no -res guessing: the 3D arrives 1:1 instead
|
|
rem of being stretched. Pass -res yourself to override it.
|
|
rem (Add -egg TEST.EGG to skip the menu and run the canned mission.)
|
|
cd /d "%~dp0"
|
|
start rpl4opt.exe -fit
|
|
"@
|
|
|
|
Set-Content -Path "$dist\joyconfig.bat" -Encoding ascii -Value @"
|
|
@echo off
|
|
rem Red Planet 4.12 - one-time JOYSTICK / HOTAS / PEDAL setup.
|
|
rem A console wizard asks you to move each control (stick, yaw, throttle
|
|
rem lever, fire buttons); it works out what you moved and which way it
|
|
rem reads, and writes the joystick section of bindings.txt. When it
|
|
rem finishes the game carries on into the setup screen so you can try
|
|
rem the bindings straight away.
|
|
rem You are never asked what you own. Yaw is asked for twice, right then
|
|
rem left, and which axis answers tells it what you have: one axis both
|
|
rem ways is a twist grip or rudder bar, two axes are two real pedals,
|
|
rem one per foot, the way the pod itself was. The throttle asks you to
|
|
rem close it and press SPACE first, since a lever sits wherever it was
|
|
rem left and no amount of watching says which end means power.
|
|
rem Xbox-class controllers need NO setup - they work out of the box.
|
|
rem Re-run this any time to redo the bindings; anything you have edited
|
|
rem yourself in bindings.txt is kept.
|
|
cd /d "%~dp0"
|
|
set RP412JOYCONFIG=1
|
|
start /wait rpl4opt.exe -windowed -res 1920 1080
|
|
set RP412JOYCONFIG=
|
|
"@
|
|
|
|
Set-Content -Path "$dist\README.txt" -Encoding ascii -Value @"
|
|
Red Planet $version
|
|
=================
|
|
|
|
Run start-fullscreen.bat for borderless over the whole monitor, or
|
|
start-windowed.bat to keep a title bar. No cockpit hardware needed.
|
|
If there is no sound, run oalinst.exe once.
|
|
|
|
Got a flight stick, HOTAS or pedals? Run joyconfig.bat once. It asks
|
|
you to move each control, works out which axis you moved and which way
|
|
round it reads, and writes the joystick rows of bindings.txt. It never
|
|
asks what you own: yaw is asked for twice, right then left, and one
|
|
axis answering both ways is a twist grip or rudder bar while two axes
|
|
are two real pedals, one per foot, as the pod itself had. The throttle
|
|
asks you to close it and press SPACE before you open it, since a lever
|
|
sits wherever it was left. Xbox-class controllers need none of that -
|
|
they work out of the box.
|
|
|
|
Controls (XInput controller and/or keyboard) - EVERY input is
|
|
rebindable: edit bindings.txt beside the exe (written with the full
|
|
documented default layout on first run; delete it to restore).
|
|
|
|
Left stick / NumPad 8462 joystick (8=fwd 2=back 4=left 6=right)
|
|
LT / RT or NumPad 7,9 left / right pedal
|
|
Right stick Y throttle (holds position)
|
|
Shift / Ctrl throttle up / down
|
|
A / Space / NumPad 0 joystick trigger
|
|
RB / Alt reverse thrust
|
|
DPad / arrow keys joystick hat (look)
|
|
9 / 0 keys config buttons (pad Start/Back left free)
|
|
Number+letter rows MFD bank buttons (as printed on the panel)
|
|
F1-F12 secondary / screen columns
|
|
Alt+Q abort the mission (score banked)
|
|
|
|
The cockpit scales to whatever window you give it - maximise it and it
|
|
grows, keeping its 16:9 shape (an ultrawide gets black bars rather than
|
|
a stretched cockpit).
|
|
|
|
The 3D itself renders at whatever -res says and is then stretched onto
|
|
the cockpit's viewscreen, so a mismatched -res costs sharpness. -fit
|
|
takes care of that for you: it measures the monitor, works out the
|
|
canvas the cockpit will settle on, and asks for exactly that render
|
|
size, so the picture arrives 1:1.
|
|
|
|
rpl4opt.exe -fit borderless, res chosen for you
|
|
rpl4opt.exe -fit -res 1280 720 same window, lighter render
|
|
rpl4opt.exe -windowed -res 2560 1440 pick both yourself
|
|
|
|
(-windowed-fullscreen is accepted as a long spelling of -fit.)
|
|
|
|
The full pod cockpit comes up in a single window: three green MFDs
|
|
across the top, the 3D viewscreen centered with the orange plasma glass
|
|
at its left, and the lower MFDs flanking the portrait map. The red
|
|
buttons around each MFD and the amber buttons beside the map are the
|
|
pod's real button banks: click them with the mouse, and they light up
|
|
as the game commands their lamps.
|
|
environ.ini is self-documenting: the game writes it on first run with
|
|
every option in it and a comment on each (Steam networking, keyboard
|
|
lighting, stick inversion, LAN hosting, developer keys, display scaling
|
|
and radar placement, and more).
|
|
|
|
HANDBOOK.html is the full manual - open it in a browser for the pad,
|
|
keyboard and pod-panel diagrams, the joystick setup, and what every file
|
|
in this folder is for. CONTROLS.txt is the controls half as plain text.
|
|
|
|
VTV-PRESETS.html lists every vehicle you can race: its plan view, what it
|
|
carries, and the six control presets on its stick. The six amber switches
|
|
down the right of the map screen pick between them, and each one is a
|
|
complete factory layout for the four stick buttons - so the same button
|
|
does different jobs depending on which preset is lit.
|
|
|
|
TRACKS.html is every track seen from above. The game has no track maps
|
|
in it - the console had pictures and they did not survive - so each plan
|
|
is drawn from the track's own scenery, placed where the game places it.
|
|
Nearly every track is one wall bar repeated a few hundred times, and at
|
|
this size a bar reads as a line rather than a box, so each is drawn as
|
|
the single line it reads as.
|
|
|
|
Four files here are yours. None of them ship - the game writes each one
|
|
the first time it needs it and then leaves it alone, so a new build
|
|
unzipped over this folder keeps everything you have set. Delete any of
|
|
them to start that part over:
|
|
|
|
environ.ini every engine option, commented in place
|
|
bindings.txt every key, pad button, axis and joystick row
|
|
pilot.cfg your callsign and loadout
|
|
mfd_layout.cfg where you dragged the windows (RP412MFDLAYOUT)
|
|
|
|
Two that catch people out: environ.ini is applied OVER the environment,
|
|
so a variable set in a shell loses to an uncommented line in the file;
|
|
and none of these four is ever overwritten once it exists, which is what
|
|
lets you keep a folder across builds. The trade is that a file carried
|
|
through several updates stops being offered new options - rpl4.log names
|
|
any it has not heard of, and deleting the file brings back the fully
|
|
documented current one.
|
|
|
|
THIS IS A TEST BUILD AND IT GOES STALE. Two weeks after it was built it
|
|
will tell you so and refuse to start, rather than let you spend an
|
|
afternoon on something that was fixed the week before. When that happens,
|
|
ask for the current build.
|
|
|
|
Unzip it over this folder - your environ.ini, bindings.txt, pilot.cfg and
|
|
mfd_layout.cfg all survive.
|
|
|
|
Known prototype notes: pods race untextured (the player1-8 skins come
|
|
from the presets system, not shipped data), and text drawn on the plasma
|
|
glass may appear rotated.
|
|
|
|
Source: https://gitea.mysticmachines.com/VWE/RP412
|
|
"@
|
|
|
|
# --- summary / optional zip ------------------------------------------------
|
|
$size = (Get-ChildItem $dist -Recurse | Measure-Object Length -Sum).Sum
|
|
Write-Host ("dist ready: {0:N1} MB" -f ($size / 1MB))
|
|
|
|
if ($Zip) {
|
|
$zipPath = Join-Path $root "RedPlanet-$version.zip"
|
|
Write-Host "zipping to $zipPath..."
|
|
|
|
# Taken BEFORE the player's files go back, so a release never carries
|
|
# somebody's callsign, key bindings or window positions to everyone who
|
|
# downloads it. A fresh unzip must look like a first run.
|
|
#
|
|
# Everything lives under a single RP412\ folder inside the zip, so
|
|
# unpacking anywhere gives one self-contained game directory instead
|
|
# of scattering files into the extraction folder.
|
|
$stage = Join-Path ([System.IO.Path]::GetTempPath()) 'rp412-zipstage'
|
|
if (Test-Path $stage) { Remove-Item -Recurse -Force $stage }
|
|
New-Item -ItemType Directory -Force "$stage\RP412" | Out-Null
|
|
Copy-Item "$dist\*" "$stage\RP412" -Recurse -Force
|
|
Compress-Archive -Path "$stage\RP412" -DestinationPath $zipPath -Force
|
|
Remove-Item -Recurse -Force $stage
|
|
}
|
|
|
|
# --- the player's own files, back where they were --------------------------
|
|
# Last of all: after the rebuilt tree, so nothing the pack writes can land on
|
|
# top of them, and after the zip, so the release stays clean. Zipping should
|
|
# not cost you your own settings.
|
|
if ($kept.Count -gt 0) {
|
|
foreach ($name in $kept.Keys) {
|
|
[System.IO.File]::WriteAllBytes((Join-Path $dist $name), $kept[$name])
|
|
}
|
|
Write-Host " restored $($kept.Keys -join ', ')"
|
|
}
|