Something went wrong. Try again.
Data management tools for playing BattleTech
Something went wrong. Try again.
Shell
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184#!/usr/bin/env bash# Run the Java bridge: dump MegaMek's computed unit and equipment data as JSON# Lines for `helm build --bridge-dir` to read.## ./bridge/dump.sh <megamek-install> [out-dir]## Why this exists at all: battle value, C-bill cost and the Alpha Strike# conversion are computed when MegaMek loads a design and appear in no .mtf or# .blk file. Everything else helm needs is read natively by helm-unitfile.# When those calculations are reimplemented in Rust, this directory goes away.## bv.jsonl is the exception to that: it is not data helm needs, it is the# oracle helm-bv is measured against, and it earns its keep for exactly as long# as the reimplementation is unfinished.## The JDK runs in a container so no Java has to be installed. Set JDK_IMAGE to# use a different one, or JAVA_HOME to run against a local JDK instead.set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"MM_HOME="${1:?usage: dump.sh <megamek-install> [out-dir]}"OUT_DIR="${2:-$PWD}"JDK_IMAGE="${JDK_IMAGE:-eclipse-temurin:21-jdk}"
MM_HOME="$(cd "$MM_HOME" && pwd)"mkdir -p "$OUT_DIR"OUT_DIR="$(cd "$OUT_DIR" && pwd)"
[ -f "$MM_HOME/MegaMek.jar" ] || { echo "ERROR: no MegaMek.jar in $MM_HOME" >&2; exit 1; }
# MegaMek writes preferences and temp images into its own install. An install# copied out of a container image can have these as symlinks to a runtime path# that does not exist here, and MegaMek fails on the dangling link rather than# recreating it.for p in userdata data/images/temp; do if [ -L "$MM_HOME/$p" ] && [ ! -e "$MM_HOME/$p" ]; then echo "note: replacing dangling symlink $p" rm "$MM_HOME/$p"; mkdir -p "$MM_HOME/$p" fidonemkdir -p "$MM_HOME/logs" "$MM_HOME/mmconf"
# --add-opens: MekSummaryCache deserialises a prebuilt units.cache through# java.util collections.# cwd must be the install - MegaMek resolves data/ relative to it.run() { local src="$1" out="$2" shift 2 if [ -n "${JAVA_HOME:-}" ]; then ( cd "$MM_HOME" && "$JAVA_HOME/bin/java" --source 21 \ -Dlog4j2.configurationFile="$HERE/log4j2-quiet.xml" \ -Dsentry.dsn= -Djava.awt.headless=true \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.util.concurrent=ALL-UNNAMED \ -cp "MegaMek.jar:lib/*" "$HERE/$src" "$OUT_DIR/$out" "$@" ) else docker run --rm \ --user "$(id -u):$(id -g)" \ -v "$HERE:/bridge:ro" -v "$MM_HOME:/mm" -v "$OUT_DIR:/out" \ -w /mm "$JDK_IMAGE" \ java --source 21 \ -Dlog4j2.configurationFile=/bridge/log4j2-quiet.xml \ -Dsentry.dsn= -Djava.awt.headless=true \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.util.concurrent=ALL-UNNAMED \ -cp "MegaMek.jar:lib/*" "/bridge/$src" "/out/$out" "$@" fi}
# Building units.cache from scratch walks ~11k files and takes about 20s;# an install that already has one loads it in about 3s.echo "dumping units ..."run DumpUnits.java units.jsonl
echo "dumping equipment ..."run DumpEquipment.java equipment.jsonl
# The working of the battle value calculation, not just its answer. This one# loads every Entity rather than reading the summary cache, because the# calculator needs a real unit, so it costs about as much again as the units# dump.## `--report` asks for MegaMek's own working as it goes: every weapon with the# heat it cost and what it counted for, every multiplier with the figure either# side of it. A total that is 40 points light says nothing about which half is# wrong; a report says which line.echo "dumping battle value working ..."run DumpBv.java bv.jsonl Mek --report
# The same for combat vehicles, which are the next thing helm-bv scores. Much# cheaper than the Meks: there are fewer of them and a tank has no heat budget# to walk.# Three names for one calculator: everything MegaMek does not recognise as# something else is scored as a combat vehicle, and MekSummary files those# under whichever of Tank, VTOL and Naval the design looks like.echo "dumping battle value working for vehicles ..."run DumpBv.java bv-vehicle.jsonl Tank VTOL Naval --report
# And for battle armour, which is scored one trooper at a time: the report is# the only place the four sections a trooper's weapons fall into are visible.echo "dumping battle value working for battle armour ..."run DumpBv.java bv-ba.jsonl BattleArmor --report
# And for conventional infantry, where the report is the only place the# platoon's own weapons, its towed guns and its ammunition are told apart.echo "dumping battle value working for infantry ..."run DumpBv.java bv-infantry.jsonl Infantry --report
# What a design costs to buy, and the working behind it: the cockpit, the# sensors, each actuator, each weapon. The second of the three figures helm# still borrows from MegaMek, and the oracle `helm-cost` is measured against.echo "dumping cost working ..."run DumpCost.java cost.jsonl
# The same oracle for designs that have been shot at. A .mtf describes a design# as it leaves the factory and nothing else, so what a Mek is worth once its# plate is gone or its magazines are empty has to be asked of MegaMek directly.# A handful of designs is enough: it is the rules that are being checked, not# the library.echo "dumping damaged designs ..."run DumpDamaged.java damaged.jsonl
# And the units in a `.mul`, which is the only oracle for a unit somebody# varied rather than designed: a magazine whose `type` names inferno rounds is# loaded with inferno rounds and scored as such. The fixtures are this# repository's own, because MegaMek ships no file that varies a unit.## Copied into the output directory first: the container is given `bridge/`,# MegaMek and the output directory, and the fixtures are in none of those.echo "dumping the .mul fixtures ..."FIXTURES="$HERE/../crates/helm-bv/tests/mul"if compgen -G "$FIXTURES/*.mul" > /dev/null; then mkdir -p "$OUT_DIR/muls" cp "$FIXTURES"/*.mul "$OUT_DIR/muls/" muls=() for f in "$OUT_DIR"/muls/*.mul; do # The container sees the output directory as /out; a local JDK sees it # where it is. if [ -n "${JAVA_HOME:-}" ]; then muls+=("$f"); else muls+=("/out/muls/$(basename "$f")"); fi done run DumpMul.java mul.jsonl "${muls[@]}"else echo "no .mul fixtures to dump"fi
# The formation blueprints: what makes four Meks a Fire Lance rather than four# Meks. These are Campaign Operations rules that MegaMek holds in code, so they# are read off the shelf here rather than copied. Cheap - no unit is loaded.echo "dumping formations ..."run DumpFormations.java formations.jsonl
# Whether a design meets each requirement, asked of MegaMek one design at a# time. This is what says helm read a requirement's label the way the lambda# behind it behaves; a thousand-odd designs is plenty, since it is the reading# being measured and not the library.run DumpFormations.java matches.jsonl --matches 1200
# And MegaMek's verdict on whole forces, which tests the assembly rules rather# than the requirements - the ideal-role shortcut, the weight bounds, and the# requirements that are alternatives to one another.LANCES="$HERE/../crates/helm-force/tests/lances.txt"if [ -f "$LANCES" ]; then : > "$OUT_DIR/formation_forces.jsonl" while IFS= read -r lance; do case "$lance" in ''|'#'*) continue ;; esac units=() while IFS= read -r unit; do [ -n "$unit" ] && units+=("$unit") done <<< "${lance//|/$'\n'}" run DumpFormations.java one_force.jsonl --force "${units[@]}" # One row per formation per force, with the force written in so a test can # tell them apart. while IFS= read -r row; do printf '{"force":"%s",%s\n' "$lance" "${row#\{}" >> "$OUT_DIR/formation_forces.jsonl" done < "$OUT_DIR/one_force.jsonl" done < "$LANCES" rm -f "$OUT_DIR/one_force.jsonl"fi
echo "wrote $OUT_DIR/units.jsonl, $OUT_DIR/equipment.jsonl, $OUT_DIR/bv.jsonl, $OUT_DIR/bv-vehicle.jsonl, $OUT_DIR/bv-ba.jsonl, $OUT_DIR/bv-infantry.jsonl, $OUT_DIR/cost.jsonl,"echo " $OUT_DIR/damaged.jsonl, $OUT_DIR/mul.jsonl, $OUT_DIR/formations.jsonl,"echo " $OUT_DIR/matches.jsonl and $OUT_DIR/formation_forces.jsonl"