diff --git a/Dockerfile b/Dockerfile index 0941d9c..270e70d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -390,6 +390,7 @@ COPY container/ ${ARENA_HOME}/container/ COPY suramadu/web/ ${ARENA_HOME}/web/ COPY megamek/clientsettings.xml.template ${ARENA_HOME}/config/ +COPY megamek/gameoptions.xml.template ${ARENA_HOME}/config/ COPY megamek/log4j2-quiet.xml ${ARENA_HOME}/config/ COPY suramadu/suramadu.config.template ${ARENA_HOME}/config/ COPY suramadu/jetty.properties.template ${ARENA_HOME}/config/ diff --git a/README.md b/README.md index c76ecee..bb5107e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ a rendering bug, everything MegaMek-shaped is in one directory. | | | |---|---| -| `megamek/` | configuring and patching MegaMek: the nine patches, client settings, logging config, `units.cache` priming, `prune-data.sh` — one documented line per thing removed from the shipped data, and why a match cannot reach it — and `skin/` — `lanceBlueSkin.xml`, the lance.blue board backgrounds and window icons, and the install script that checks every image the skin references exists | +| `megamek/` | configuring and patching MegaMek: the nine patches, client settings, game options, logging config, `units.cache` priming, `prune-data.sh` — one documented line per thing removed from the shipped data, and why a match cannot reach it — and `skin/` — `lanceBlueSkin.xml`, the lance.blue board backgrounds and window icons, and the install script that checks every image the skin references exists | | `suramadu/` | configuring Suramadu: its server config, Jetty properties, the fontconfig generator its toolkit requires, `web/` — the themed loading page served in place of the war's — and `patches/`, applied to the frontend bundle inside the war at build time | | `src/` | our own Java — `MatchHost`, `MatchWatcher`, `TextRenderer` — and the script that jars it | | `container/` | process management inside a running container: `entrypoint.sh`, `init/`, `watch/`, `exit/`, `lib/` | @@ -106,6 +106,25 @@ the lounge nobody starts, and the game everyone left or stopped playing; a finished game is exempt, because the host is deliberately lingering then. A manifest that omits the limit, or sets it to 0, gets no timeout. +## Rules defaults + +Two files are seeded into MegaMek's `mmconf/` before every launch, and they are +the whole of what arena says about how a match plays. +`megamek/clientsettings.xml.template` is one player's client — what is docked, +what is drawn, what makes a noise. `megamek/gameoptions.xml.template` is the +rules, for everyone in the match: MegaMek's game options, listed only where they +differ from upstream's defaults. + +Two differ today. Ejected crews leave the field the moment they get out, rather +than staying as units their owner then moves every round — MegaMek's own +`ejected_pilots_flee`, which some of the shipped scenarios already set for +themselves. And a unit that cannot fire — shut down, crew out — gets no firing +turn, which is the choice MegaMek already makes for the physical phase. + +Both are defaults, not rules arena imposes. A scenario that names a +`GameOptionsFile` of its own is loaded with that file and none of this, so a +scenario author still decides their own match. + ## Patches Nine, in `megamek/patches/patchset/`. Each is a MegaMek bug rather than an diff --git a/TODO.md b/TODO.md index 6a9d4ff..8cff023 100644 --- a/TODO.md +++ b/TODO.md @@ -350,6 +350,27 @@ and the p90 tail fell from ~470ms to ~330ms. The proxy was ruled out early the window icons and the `GUIPreferences` that go with them. What is left is verification of the window icons, tracked under render performance. +- [x] **Matches ran on MegaMek's stock rules** — there was no game options file + at all, so every match got upstream's defaults whether or not they suited + a browser match. `megamek/gameoptions.xml.template` is now seeded into + `mmconf/` beside the client settings, and `ScenarioV1` picks it up for any + scenario that does not name a `GameOptionsFile` of its own. + + Two options differ from stock: `ejected_pilots_flee`, so a dead mek's + MechWarrior does not stay on the board as a unit its owner moves every + round, and `skip_ineligible_firing`, so a shut-down unit gets no firing + turn it can only press Done on. + + Verified by mounting the file into the shipped image and loading with + `ScenarioReport`: MegaMek logs both as set, and all 51 scenarios load + exactly as they did without it. What has not been seen is the effect in + play — a mek ejecting in a hosted match and the MechWarrior not appearing. + + Considered and left alone: `skip_ineligible_movement`, because the + movement phase is where a shut-down mek starts up and where TacOps:AR + abandonment happens; the nag dialogs, which are protective rather than + noise; and turn timers, which are a feature rather than a default worth + correcting. - [ ] **The minimap cannot dock** — unlike the unit display and mini report it has no location preference and is dialog-only. Hidden by default (patch 0003 made that possible at all). Docking it properly needs more patching. diff --git a/container/init/40-render-config.sh b/container/init/40-render-config.sh index 2c2d8fb..c3895fe 100755 --- a/container/init/40-render-config.sh +++ b/container/init/40-render-config.sh @@ -110,6 +110,12 @@ sed -e "s|@PORT_WS@|$PORT_WS|g" \ "$ARENA_HOME/config/jetty.properties.template" > "$ARENA_RUN/suramadu/jetty.properties" cp "$ARENA_HOME/config/clientsettings.xml.template" "$MM_HOME/mmconf/clientsettings.xml" +# The rules half of the same pair, read by the host rather than the client: +# ScenarioV1 loads mmconf/gameoptions.xml for any scenario that does not name a +# GameOptionsFile of its own. Re-seeded per launch for the same reason +# clientsettings.xml is - a player who opens the game options dialog and +# presses OK makes the client write this file back. +cp "$ARENA_HOME/config/gameoptions.xml.template" "$MM_HOME/mmconf/gameoptions.xml" # A leftover placeholder means the client would try to log in as "@PLAYER_NAME@" # and sit in the lobby forever. Easy to catch here, hard to diagnose live. diff --git a/megamek/gameoptions.xml.template b/megamek/gameoptions.xml.template new file mode 100644 index 0000000..639f067 --- /dev/null +++ b/megamek/gameoptions.xml.template @@ -0,0 +1,77 @@ + + + + + + ejected_pilots_flee + true + + + + + skip_ineligible_firing + true + + diff --git a/tests/shell/test-render-config.sh b/tests/shell/test-render-config.sh index c520945..3326168 100755 --- a/tests/shell/test-render-config.sh +++ b/tests/shell/test-render-config.sh @@ -18,6 +18,7 @@ printf 'did:plc:aaa\tTraineeA\n' > "$TMP/run/clients.tsv" cp "$ROOT/suramadu/suramadu.config.template" "$TMP/home/config/" cp "$ROOT/suramadu/jetty.properties.template" "$TMP/home/config/" cp "$ROOT/megamek/clientsettings.xml.template" "$TMP/home/config/" +cp "$ROOT/megamek/gameoptions.xml.template" "$TMP/home/config/" ln -s "$ROOT/container" "$TMP/home/container" ARENA_HOME="$TMP/home" ARENA_RUN="$TMP/run" MM_HOME="$TMP/mm" \ @@ -33,6 +34,7 @@ check() { # CFG="$TMP/run/suramadu/suramadu.config" JETTY="$TMP/run/suramadu/jetty.properties" SETTINGS="$TMP/mm/mmconf/clientsettings.xml" +OPTIONS="$TMP/mm/mmconf/gameoptions.xml" check "suramadu.config is valid JSON" jq -e . "$CFG" check "player name substituted" grep -q 'player_name TraineeA' "$CFG" @@ -92,4 +94,20 @@ check "fov darkening off" grep -q 'name="FovDarken" value="fa # the first unit rather than one that sorts oddly. check "weapons sort by damage, big first" grep -q 'name="DefaultWeaponSortOrder" value="DAMAGE_HIGH_LOW"' "$SETTINGS" +# --- game options ------------------------------------------------------------ +# ScenarioV1 reads mmconf/gameoptions.xml only for scenarios that name no +# GameOptionsFile, and only from the host's working directory. An absent file is +# not an error there - loadOptions() returns quietly - so a render that stopped +# seeding it would give every match MegaMek's stock rules with no sign of it. +check "gameoptions seeded into mmconf" test -f "$OPTIONS" +check "gameoptions is well-formed XML" python3 -c "import sys,xml.etree.ElementTree as E; E.parse(sys.argv[1])" "$OPTIONS" +# The one rule a player would notice going missing: without it a dead mek's +# MechWarrior stays on the board and its owner moves it every round. +check "ejected crews leave the field" bash -c "python3 - '$OPTIONS' <<'PY' +import sys, xml.etree.ElementTree as E +opts = {o.findtext('optionname'): o.findtext('optionvalue') + for o in E.parse(sys.argv[1]).getroot()} +sys.exit(0 if opts.get('ejected_pilots_flee') == 'true' else 1) +PY" + exit "$fail"