diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml index 86e91ba..8e12f7a 100644 --- a/.github/workflows/build-artifact.yml +++ b/.github/workflows/build-artifact.yml @@ -49,7 +49,7 @@ jobs: echo "version=$version" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Upload artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: OpcodeExtractor-${{ env.version }}-${{ env.artifact_sha }} path: bin/Release/publish/ diff --git a/Program.cs b/Program.cs index cc3ffed..e9f3a2e 100644 --- a/Program.cs +++ b/Program.cs @@ -41,39 +41,63 @@ static async Task Main(string[] args) rootCommand.AddArgument(outputFormatArgument); rootCommand.AddArgument(inputMapKeyArgument); - rootCommand.SetHandler((opcodeMapFile, gameExecutable, dumpAllOpcodes, outputFormat, inputMapKey) => - { - var opcodes = ExtractOpcodes(opcodeMapFile!, gameExecutable!, dumpAllOpcodes, inputMapKey); - OutputOpcodes(opcodes, outputFormat); - }, - opcodeFileMapArgument, gameExecutableArgument, dumpAllOpcodesArgument, outputFormatArgument, inputMapKeyArgument); + rootCommand.SetHandler(CommandHandler, opcodeFileMapArgument, gameExecutableArgument, dumpAllOpcodesArgument, outputFormatArgument, inputMapKeyArgument); return await rootCommand.InvokeAsync(args); } - private static void OutputOpcodes(Dictionary opcodes, OutputFormat outputFormat) + private static void CommandHandler(FileInfo? opcodeMapFile, FileInfo? gameExecutable, bool dumpAllOpcodes, OutputFormat outputFormat, string inputMapKey) + { + var opcodeMapData = JsonSerializer.Deserialize(File.ReadAllText(opcodeMapFile!.FullName), new JsonSerializerOptions() + { + ReadCommentHandling = JsonCommentHandling.Skip, + }); + if (opcodeMapData == null) + { + Console.Error.WriteLine("Invalid opcodes file"); + return; + } + + var opcodes = ExtractOpcodes(opcodeMapData, gameExecutable!, dumpAllOpcodes, inputMapKey); + + var sortOrder = opcodeMapData[inputMapKey]?.AsObject().ToDictionary().Keys.ToArray(); + if (sortOrder == null) + { + Console.Error.WriteLine("Invalid data type for \"map\" in opcodes file"); + sortOrder = []; + } + OutputOpcodes(opcodes, outputFormat, sortOrder); + } + + private static void OutputOpcodes(Dictionary opcodes, OutputFormat outputFormat, string[] sortOrder) { if (outputFormat == OutputFormat.All || outputFormat == OutputFormat.FFXIV_ACT_Plugin) { - OutputOpcodesForFFXIV_ACT_Plugin(opcodes); + OutputOpcodesForFFXIV_ACT_Plugin(opcodes, sortOrder); } if (outputFormat == OutputFormat.All || outputFormat == OutputFormat.OverlayPlugin) { - OutputOpcodesForOverlayPlugin(opcodes); + OutputOpcodesForOverlayPlugin(opcodes, sortOrder); } } - private static void OutputOpcodesForFFXIV_ACT_Plugin(Dictionary opcodes) + private static void OutputOpcodesForFFXIV_ACT_Plugin(Dictionary opcodes, string[] sortOrder) { - foreach (var entry in opcodes) + var entries = opcodes.ToList().OrderBy(x => Array.IndexOf(sortOrder, x.Value)).ToList(); + foreach (var entry in entries) { Console.WriteLine($"{entry.Value}|{entry.Key:x}"); } } - private static void OutputOpcodesForOverlayPlugin(Dictionary opcodes) + private static void OutputOpcodesForOverlayPlugin(Dictionary opcodes, string[] sortOrder) { - Dictionary> overlayPluginMap = []; + Dictionary?> overlayPluginMap = []; + + foreach (var key in sortOrder) + { + overlayPluginMap[key] = null; + } foreach (var entry in opcodes) { @@ -95,17 +119,11 @@ private static void OutputOpcodesForOverlayPlugin(Dictionary opcode /// /// Map opcodes as defined in opcodeMapFile for executable gameExecutable /// - /// The opcode map to use + /// The opcode map to use /// The game executable to map /// Whether to dump all opcodes, or just the mapped opcodes - public static Dictionary ExtractOpcodes(FileInfo opcodeMapFile, FileInfo gameExecutable, bool dumpAllOpcodes, string inputMapKey) + public static Dictionary ExtractOpcodes(JsonNode opcodeMapData, FileInfo gameExecutable, bool dumpAllOpcodes, string inputMapKey) { - var opcodeMapData = JsonSerializer.Deserialize(File.ReadAllText(opcodeMapFile.FullName), new JsonSerializerOptions() - { - ReadCommentHandling = JsonCommentHandling.Skip, - }); - if (opcodeMapData == null) return []; - var opcodeMethod = opcodeMapData["method"]?.ToString() ?? ""; byte[] gameData = File.ReadAllBytes(gameExecutable.FullName); diff --git a/resources/global.jsonc b/resources/global.jsonc index b154dab..b38dbe9 100644 --- a/resources/global.jsonc +++ b/resources/global.jsonc @@ -36,39 +36,39 @@ "FFXIV_ACT_Plugin": { "StatusEffectList": 207, "StatusEffectList2": 209, + "StatusEffectList3": 237, "BossStatusEffectList": 211, + "Ability1": 228, + "Ability8": 231, + "Ability16": 232, + "Ability24": 233, + "Ability32": 234, + "ActorCast": 277, "EffectResult": 213, "EffectResultBasic": 218, "ActorControl": 224, "ActorControlSelf": 225, "ActorControlTarget": 226, "UpdateHpMpTp": 227, - "Ability1": 228, - "Ability8": 231, - "Ability16": 232, - "Ability24": 233, - "Ability32": 234, - "StatusEffectList3": 237, "PlayerSpawn": 268, "NpcSpawn": 269, "NpcSpawn2": 270, "ActorMove": 272, "ActorSetPos": 275, - "ActorCast": 277, - "SystemLogMessage": 408, + "ActorGauge": 585, "PresetWaymark": 534, "Waymark": 535, - "ActorGauge": 585 + "SystemLogMessage": 408 }, "OverlayPlugin": { + "MapEffect": 402, + "CEDirector": 649, "RSVData": 127, + "NpcYell": 448, + "BattleTalk2": 414, "Countdown": 147, "CountdownCancel": 148, "SpawnObject": 284, - "DespawnObject": 285, - "MapEffect": 402, - "BattleTalk2": 414, - "NpcYell": 448, - "CEDirector": 649 + "DespawnObject": 285 } -} \ No newline at end of file +}