Something went wrong. Try again.
Data management tools for playing BattleTech
Something went wrong. Try again.
Java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126import megamek.common.battleValue.BVCalculator;import megamek.common.loaders.MekSummaryCache;import megamek.common.units.Entity;import megamek.common.loaders.MULParser;
import java.io.BufferedWriter;import java.io.File;import java.io.FileOutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.nio.charset.StandardCharsets;
/** * Dump MegaMek's battle value for the units in a `.mul`. * * <p>The other dumps score a design as it leaves the factory, or a design this * program shot at in a way it chose. Neither can answer for a unit somebody * else varied: a `.mul` records what is in every critical slot, and MegaMek * reads those types back - a magazine whose `type` names inferno rounds is * loaded with inferno rounds and scored as such. That is how a player changes * a unit without designing one, and it is the case helm has to agree about. * * <p>Usage: DumpMul out.jsonl file.mul [file.mul ...] * * <p>Must run with MegaMek's install dir as the working directory. The summary * cache has to be up before a `.mul` can name a design. */public final class DumpMul {
public static void main(String[] args) throws Exception { if (args.length < 2) { System.err.println("usage: DumpMul <out.jsonl> <file.mul> [file.mul ...]"); System.exit(2); }
MekSummaryCache cache = MekSummaryCache.getInstance(); long deadline = System.currentTimeMillis() + 600_000L; while (!cache.isInitialized()) { if (System.currentTimeMillis() > deadline) { System.err.println("units.cache did not initialise within 600s"); System.exit(1); } Thread.sleep(250L); }
int written = 0; try (PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(new FileOutputStream(args[0]), StandardCharsets.UTF_8)))) { for (int i = 1; i < args.length; i++) { File file = new File(args[i]); MULParser parser = new MULParser(file, null); for (Entity entity : parser.getEntities()) { BVCalculator calc = BVCalculator.getBVCalculator(entity); // Crew and C3 left out: the crew is arithmetic helm does // itself from a table, and C3 needs a game to see the // other units. What is being asked here is what the unit // itself is worth once somebody has varied it. int bv = calc.calculateBV(true, true); StringBuilder sb = new StringBuilder(256); sb.append("{\"file\":"); quote(sb, file.getName()); sb.append(",\"name\":"); quote(sb, entity.getShortNameRaw()); sb.append(",\"bv\":").append(bv); // Which half is wrong is the first question every // disagreement asks, and the fields are not public. for (String field : new String[] { "defensiveValue", "offensiveValue" }) { try { java.lang.reflect.Field f = findField(calc.getClass(), field); if (f != null) { f.setAccessible(true); sb.append(",\"").append(field).append("\":").append(f.get(calc)); } } catch (Throwable ignored) { // A MegaMek that renames these should lose the // columns rather than fail. } } sb.append('}'); out.println(sb); written++; } String warning = parser.getWarningMessage(); if (warning != null && !warning.isBlank()) { System.err.println(file.getName() + ": " + warning.trim()); } } } System.err.println("wrote " + written + " rows"); }
/** A field on this class or any above it. */ private static java.lang.reflect.Field findField(Class<?> type, String name) { for (Class<?> at = type; at != null; at = at.getSuperclass()) { try { return at.getDeclaredField(name); } catch (NoSuchFieldException ignored) { // Keep walking up. } } return null; }
private static void quote(StringBuilder sb, String value) { sb.append('"'); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); switch (c) { case '"' -> sb.append("\\\""); case '\\' -> sb.append("\\\\"); case '\n' -> sb.append("\\n"); case '\r' -> sb.append("\\r"); case '\t' -> sb.append("\\t"); default -> { if (c < 0x20) { sb.append(String.format("\\u%04x", (int) c)); } else { sb.append(c); } } } } sb.append('"'); }}