diff --git a/faf-commons-data/src/main/java/com/faforever/commons/replay/ReplayDataParser.java b/faf-commons-data/src/main/java/com/faforever/commons/replay/ReplayDataParser.java index 21b0848..8ec76c6 100644 --- a/faf-commons-data/src/main/java/com/faforever/commons/replay/ReplayDataParser.java +++ b/faf-commons-data/src/main/java/com/faforever/commons/replay/ReplayDataParser.java @@ -52,14 +52,14 @@ public class ReplayDataParser { @Getter private Map> mods; @Getter - private final Map> armies = new HashMap<>(); + private final Map> armies = new HashMap<>(); private int randomSeed; @Getter - private final List chatMessages = new ArrayList<>(); + private final List chatMessages = new ArrayList<>(); @Getter - private final List moderatorEvents = new ArrayList<>(); + private final List moderatorEvents = new ArrayList<>(); @Getter - private final Map> commandsPerMinuteByPlayer = new HashMap<>(); + private final Map> commandsPerMinuteByPlayer = new HashMap<>(); private int ticks; @@ -368,8 +368,8 @@ private void parseGiveResourcesToPlayer(LuaData.Table lua) { return; } - int fromArmy = (int)(luaFromArmy - 1); - if ((int) fromArmy == -2) { + int fromArmy = (int) luaFromArmy - 1; + if (fromArmy == -2) { return; } @@ -410,7 +410,7 @@ void parseModeratorEvent(LuaData.Table lua, Integer player) { } if (lua.value().get("From") instanceof LuaData.Number(float luaFrom)) { - fromArmy = (int)luaFrom - 1; + fromArmy = (int) luaFrom - 1; if (fromArmy != -2) { @@ -441,10 +441,10 @@ private Duration tickToTime(int tick) { private void parse() throws IOException, CompressorException { readReplayData(path); - LittleEndianDataInputStream dataStream = new LittleEndianDataInputStream(new ByteArrayInputStream(data)); - parseHeader(dataStream); - - tokens = Tokenizer.tokenize(dataStream); + try (LittleEndianDataInputStream dataStream = new LittleEndianDataInputStream(new ByteArrayInputStream(data))) { + parseHeader(dataStream); + tokens = Tokenizer.tokenize(dataStream); + } events = Parser.parseTokens(tokens); interpretEvents(events); } diff --git a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/EventCommandType.java b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/EventCommandType.java index 0d6482d..a2a70d4 100644 --- a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/EventCommandType.java +++ b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/EventCommandType.java @@ -1,6 +1,10 @@ package com.faforever.commons.replay.body.event; +import lombok.Getter; + +@Getter public enum EventCommandType { + // Order is crucial NONE("NONE"), STOP("Stop"), MOVE("Move"), diff --git a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/LuaData.java b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/LuaData.java index 8d2a626..e48aa91 100644 --- a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/LuaData.java +++ b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/LuaData.java @@ -4,10 +4,10 @@ public sealed interface LuaData { - public record Number(float value) implements LuaData {} - public record String(java.lang.String value) implements LuaData {} - public record Nil() implements LuaData {} - public record Table(Map value) implements LuaData {} - public record Bool(boolean value) implements LuaData {} + record Number(float value) implements LuaData {} + record String(java.lang.String value) implements LuaData {} + record Nil() implements LuaData {} + record Table(Map value) implements LuaData {} + record Bool(boolean value) implements LuaData {} } diff --git a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/Parser.java b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/Parser.java index 78235c9..3668b09 100644 --- a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/Parser.java +++ b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/event/Parser.java @@ -10,7 +10,7 @@ import java.util.*; public class Parser { - public static List parseTokens (List tokens) throws IOException { + public static List parseTokens(List tokens) throws IOException { return tokens.stream().parallel().map((token) -> { try { return parseToken(token); @@ -149,7 +149,7 @@ private static LuaData parseLua(LittleEndianDataInputStream dataStream) throws I while (peek(dataStream) != LUA_TABLE_END) { LuaData key = parseLua(dataStream); - switch(key) { + switch (key) { case LuaData.String(String str) -> value.put(str, parseLua(dataStream)); case LuaData.Number(float num) -> value.put(String.valueOf(num), parseLua(dataStream)); @@ -167,163 +167,164 @@ private static LuaData parseLua(LittleEndianDataInputStream dataStream) throws I } } - private static Event parseToken(Token token) throws IOException { + private static Event parseToken(Token token) throws IOException { - LittleEndianDataInputStream stream = new LittleEndianDataInputStream((new ByteArrayInputStream(token.tokenContent()))); - - return switch (token.tokenId()) { - case CMDST_ADVANCE -> { - int ticks = stream.readInt(); - yield new Event.Advance(ticks); - } - - case CMDST_SET_COMMAND_SOURCE -> { - int playerIndex = stream.readByte(); - yield new Event.SetCommandSource(playerIndex); - } + try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream((new ByteArrayInputStream(token.tokenContent())))) { + return switch (token.tokenId()) { + case CMDST_ADVANCE -> { + int ticks = stream.readInt(); + yield new Event.Advance(ticks); + } - case CMDST_COMMAND_SOURCE_TERMINATED -> new Event.CommandSourceTerminated(); + case CMDST_SET_COMMAND_SOURCE -> { + int playerIndex = stream.readByte(); + yield new Event.SetCommandSource(playerIndex); + } - case CMDST_VERIFY_CHECKSUM -> { - String hash = HexFormat.of().formatHex(stream.readNBytes(16)); - int tick = stream.readInt(); + case CMDST_COMMAND_SOURCE_TERMINATED -> new Event.CommandSourceTerminated(); - yield new Event.VerifyChecksum(hash, tick); - } + case CMDST_VERIFY_CHECKSUM -> { + String hash = HexFormat.of().formatHex(stream.readNBytes(16)); + int tick = stream.readInt(); - case CMDST_REQUEST_PAUSE -> new Event.RequestPause(); + yield new Event.VerifyChecksum(hash, tick); + } - case CMDST_RESUME -> new Event.RequestResume(); + case CMDST_REQUEST_PAUSE -> new Event.RequestPause(); - case CMDST_SINGLE_STEP -> new Event.SingleStep(); + case CMDST_RESUME -> new Event.RequestResume(); - case CMDST_CREATE_UNIT -> { - int playerIndex = stream.readByte(); - String blueprintId = parseString(stream); - float px = stream.readFloat(); - float pz = stream.readFloat(); - float heading = stream.readFloat(); + case CMDST_SINGLE_STEP -> new Event.SingleStep(); - yield new Event.CreateUnit(playerIndex, blueprintId, px, pz, heading); - } + case CMDST_CREATE_UNIT -> { + int playerIndex = stream.readByte(); + String blueprintId = parseString(stream); + float px = stream.readFloat(); + float pz = stream.readFloat(); + float heading = stream.readFloat(); - case CMDST_CREATE_PROP -> { - String blueprintId = parseString(stream); - float px = stream.readFloat(); - float pz = stream.readFloat(); - float heading = stream.readFloat(); + yield new Event.CreateUnit(playerIndex, blueprintId, px, pz, heading); + } - yield new Event.CreateProp(blueprintId, px, pz, heading); - } + case CMDST_CREATE_PROP -> { + String blueprintId = parseString(stream); + float px = stream.readFloat(); + float pz = stream.readFloat(); + float heading = stream.readFloat(); - case CMDST_DESTROY_ENTITY -> { - int entityId = stream.readInt(); - yield new Event.DestroyEntity(entityId); - } + yield new Event.CreateProp(blueprintId, px, pz, heading); + } - case CMDST_WARP_ENTITY -> { - int entityId = stream.readInt(); - float px = stream.readFloat(); - float py = stream.readFloat(); - float pz = stream.readFloat(); - yield new Event.WarpEntity(entityId, px, py, pz); - } + case CMDST_DESTROY_ENTITY -> { + int entityId = stream.readInt(); + yield new Event.DestroyEntity(entityId); + } - case CMDST_PROCESS_INFO_PAIR -> { - int entityId = stream.read(); - String arg1 = parseString(stream); - String arg2 = parseString(stream); - yield new Event.ProcessInfoPair(entityId, arg1, arg2); - } + case CMDST_WARP_ENTITY -> { + int entityId = stream.readInt(); + float px = stream.readFloat(); + float py = stream.readFloat(); + float pz = stream.readFloat(); + yield new Event.WarpEntity(entityId, px, py, pz); + } - case CMDST_ISSUE_COMMAND -> { - Event.CommandUnits commandUnits = parseCommandUnits(stream); - Event.CommandData commandData = parseCommandData(stream); + case CMDST_PROCESS_INFO_PAIR -> { + int entityId = stream.read(); + String arg1 = parseString(stream); + String arg2 = parseString(stream); + yield new Event.ProcessInfoPair(entityId, arg1, arg2); + } - yield new Event.IssueCommand(commandUnits, commandData); - } + case CMDST_ISSUE_COMMAND -> { + Event.CommandUnits commandUnits = parseCommandUnits(stream); + Event.CommandData commandData = parseCommandData(stream); - case CMDST_ISSUE_FACTORY_COMMAND -> { - Event.CommandUnits commandUnits = parseCommandUnits(stream); - Event.CommandData commandData = parseCommandData(stream); + yield new Event.IssueCommand(commandUnits, commandData); + } - yield new Event.IssueFactoryCommand(commandUnits, commandData); - } + case CMDST_ISSUE_FACTORY_COMMAND -> { + Event.CommandUnits commandUnits = parseCommandUnits(stream); + Event.CommandData commandData = parseCommandData(stream); - case CMDST_INCREASE_COMMAND_COUNT -> { - int commandId = stream.readInt(); - int delta = stream.readInt(); - yield new Event.IncreaseCommandCount(commandId, delta); - } + yield new Event.IssueFactoryCommand(commandUnits, commandData); + } - case CMDST_DECRASE_COMMAND_COUNT -> { - int commandId = stream.readInt(); - int delta = stream.readInt(); - yield new Event.DecreaseCommandCount(commandId, delta); - } + case CMDST_INCREASE_COMMAND_COUNT -> { + int commandId = stream.readInt(); + int delta = stream.readInt(); + yield new Event.IncreaseCommandCount(commandId, delta); + } - case CMDST_SET_COMMAND_TARGET -> { - int commandId = stream.readInt(); - Event.CommandTarget commandTarget = parseCommandTarget(stream); - yield new Event.SetCommandTarget(commandId, commandTarget); - } + case CMDST_DECRASE_COMMAND_COUNT -> { + int commandId = stream.readInt(); + int delta = stream.readInt(); + yield new Event.DecreaseCommandCount(commandId, delta); + } - case CMDST_SET_COMMAND_TYPE -> { - int commandId = stream.readInt(); - int targetCommandType = stream.readInt(); - yield new Event.SetCommandType(commandId, targetCommandType); - } + case CMDST_SET_COMMAND_TARGET -> { + int commandId = stream.readInt(); + Event.CommandTarget commandTarget = parseCommandTarget(stream); + yield new Event.SetCommandTarget(commandId, commandTarget); + } - case CMDST_SET_COMMAND_CELLS -> { - int commandId = stream.readInt(); - LuaData parametersLua = parseLua(stream); - if (!(parametersLua instanceof LuaData.Nil)) { - stream.readNBytes(1); + case CMDST_SET_COMMAND_TYPE -> { + int commandId = stream.readInt(); + int targetCommandType = stream.readInt(); + yield new Event.SetCommandType(commandId, targetCommandType); } - float px = stream.readFloat(); - float py = stream.readFloat(); - float pz = stream.readFloat(); + case CMDST_SET_COMMAND_CELLS -> { + int commandId = stream.readInt(); + LuaData parametersLua = parseLua(stream); + if (!(parametersLua instanceof LuaData.Nil)) { + stream.readNBytes(1); + } - yield new Event.SetCommandCells(commandId, parametersLua, px, py, pz); - } + float px = stream.readFloat(); + float py = stream.readFloat(); + float pz = stream.readFloat(); - case CMDST_REMOVE_COMMAND_FROM_QUEUE -> { - int commandId = stream.readInt(); - int unitId = stream.readInt(); - yield new Event.RemoveCommandFromQueue(commandId, unitId); - } + yield new Event.SetCommandCells(commandId, parametersLua, px, py, pz); + } - case CMDST_DEBUG_COMMAND -> new Event.Unprocessed(token, "CMDST_DEBUG_COMMAND"); + case CMDST_REMOVE_COMMAND_FROM_QUEUE -> { + int commandId = stream.readInt(); + int unitId = stream.readInt(); + yield new Event.RemoveCommandFromQueue(commandId, unitId); + } - case CMDST_EXECUTE_LUA_IN_SIM -> { - String luaCode = parseString(stream); - yield new Event.ExecuteLuaInSim(luaCode); - } + case CMDST_DEBUG_COMMAND -> new Event.Unprocessed(token, "CMDST_DEBUG_COMMAND"); - case CMDST_LUA_SIM_CALLBACK -> { - String func = parseString(stream); - LuaData args = parseLua(stream); - Event.CommandUnits commandUnits = null; - - // suspicion that this is just flat out wrong! Whether there's a selection in the data is not related to whether there are Lua arguments - if (args != null) { - commandUnits = parseCommandUnits(stream); - } else { - // the '4' we read here is the size, I suspect the 3 bytes are maybe to align the data somehow? No idea - stream.readNBytes(4 + 3); + case CMDST_EXECUTE_LUA_IN_SIM -> { + String luaCode = parseString(stream); + yield new Event.ExecuteLuaInSim(luaCode); } - yield new Event.LuaSimCallback(func, args, commandUnits); - } + case CMDST_LUA_SIM_CALLBACK -> { + String func = parseString(stream); + LuaData args = parseLua(stream); + Event.CommandUnits commandUnits = null; + + // suspicion that this is just flat out wrong! Whether there's a selection in the data is not related to whether there are Lua arguments + if (!(args instanceof LuaData.Nil)) { + commandUnits = parseCommandUnits(stream); + } else { + // the '4' we read here is the size, I suspect the 3 bytes are maybe to align the data somehow? No idea + stream.readNBytes(4 + 3); + } - case CMDST_END_GAME -> new Event.EndGame(); + yield new Event.LuaSimCallback(func, args, commandUnits); + } + + case CMDST_END_GAME -> new Event.EndGame(); - default -> new Event.Unprocessed(token, "Unknown"); - }; + case null -> new Event.Unprocessed(token, "Unknown"); + }; + } } private enum CommandTargetType { + // Order is crucial NONE, ENTITY, POSITION diff --git a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/token/Token.java b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/token/Token.java index 4f1a28b..01943d1 100644 --- a/faf-commons-data/src/main/java/com/faforever/commons/replay/body/token/Token.java +++ b/faf-commons-data/src/main/java/com/faforever/commons/replay/body/token/Token.java @@ -3,6 +3,7 @@ public record Token(TokenId tokenId, int tokenSize, byte[] tokenContent) { public enum TokenId { + // Order is crucial CMDST_ADVANCE, CMDST_SET_COMMAND_SOURCE, CMDST_COMMAND_SOURCE_TERMINATED,