From add8963d5d3d0fc4c30923b8848a9951c4b1cc14 Mon Sep 17 00:00:00 2001 From: robert-d-schultz Date: Sun, 9 Aug 2026 03:03:29 -0400 Subject: [PATCH] Add Campaign Animation Set editor Replaces the XML-text view of animations\campaign\database\bin\*.bin with a proper grid editor, and adds one-click generation of a complete campaign animation set from an existing battle animation set. Binary format fixes in Shared.GameFormats (CampaignAnimationBin): - PersistentMeta, PersistentMeta_Pose/_Dock, LocomotionEntry, TransitionEntry and UnknownEntry read their strings as (Animation, AnimationMeta, SoundMeta, Type) when the on-disk order is (Animation, Type, AnimationMeta, SoundMeta), so meta paths landed in the wrong properties. - PersistentMeta_Pose/_Dock had no real Weight field; it was the 4th string misread as a float. - UnknownEntry.Value wrote an int through the float parser. - PortholeEntry Value0-5 identified and named. - LocomotionEntry.Weight renamed BlendTime to match its observed values. Covered by round-trip tests against two real vanilla fixtures; this format had no test coverage before. Also fixes DataGridCell.Foreground app-wide, which pointed at a Background brush and painted cell text the same colour as its background. Co-Authored-By: Claude Opus 5 --- AssetEditor.sln | 33 + AssetEditor/AssetEditor.csproj | 1 + .../Services/DependencyInjectionConfig.cs | 1 + AssetEditor/Themes/Controls.xaml | 2 +- .../CampaignAnimBinToXmlConverter.cs | 78 -- .../DependencyInjectionContainer.cs | 14 - .../DependencyInjectionContainer.cs | 36 + .../Editors.CampaignAnimationSetEditor.csproj | 20 + .../GlobalUsings.cs | 2 + .../CampaignAnimationSetGeneratorService.cs | 367 +++++++++ .../CampaignAnimationSetValidator.cs} | 39 +- .../Services/FreezeRootBoneCommand.cs | 48 ++ .../Services/KnownActionType.cs | 64 ++ .../Services/KnownCampaignStatus.cs | 81 ++ .../Services/KnownPoseId.cs | 48 ++ .../ViewModels/AddStatusViewModel.cs | 26 + .../BattleFragmentPickerViewModel.cs | 57 ++ .../CampaignAnimationSetEditorViewModel.cs | 285 +++++++ .../ViewModels/OpenCampaignBinViewModel.cs | 52 ++ .../ViewModels/SaveCampaignBinAsViewModel.cs | 17 + .../ViewModels/StatusItemViewModel.cs | 141 ++++ .../Views/AddStatusWindow.xaml | 26 + .../Views/AddStatusWindow.xaml.cs | 19 + .../AnimationFragmentDisplayConverter.cs | 19 + .../Views/BattleFragmentPickerWindow.xaml | 45 ++ .../Views/BattleFragmentPickerWindow.xaml.cs | 24 + .../Views/CampaignAnimationSetEditorView.xaml | 726 ++++++++++++++++++ .../CampaignAnimationSetEditorView.xaml.cs | 12 + .../Views/OpenCampaignBinWindow.xaml | 26 + .../Views/OpenCampaignBinWindow.xaml.cs | 24 + .../Views/PathTailConverter.cs | 27 + .../Views/PoseIdDisplayConverter.cs | 23 + .../Views/SaveCampaignBinAsWindow.xaml | 25 + .../Views/SaveCampaignBinAsWindow.xaml.cs | 19 + .../Views/StatusDescriptionConverter.cs | 23 + .../CampaignAnimationBinRoundTripTests.cs | 113 +++ ...mpaignAnimationSetGeneratorServiceTests.cs | 110 +++ .../Fixtures/cam_bi2_dlc27_preyton_boss.bin | Bin 0 -> 3215 bytes .../Fixtures/cam_hu6_gor_axe.bin | Bin 0 -> 4581 bytes .../FreezeRootBoneCommandTests.cs | 102 +++ .../Test.CampaignAnimationSetEditor.csproj | 38 + .../AnimPackFileTypes/Wh3/AnimationBinWh3.cs | 1 + .../AnimationPack/CampaignAnimationBin.cs | 99 ++- .../IAnimationBinGenericFormat.cs | 2 + 44 files changed, 2764 insertions(+), 151 deletions(-) delete mode 100644 Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/DependencyInjectionContainer.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor.csproj create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/GlobalUsings.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/CampaignAnimationSetGeneratorService.cs rename Editors/{AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/Validator.cs => CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/CampaignAnimationSetValidator.cs} (90%) create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/FreezeRootBoneCommand.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/KnownActionType.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/KnownCampaignStatus.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Services/KnownPoseId.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/AddStatusViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/BattleFragmentPickerViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/CampaignAnimationSetEditorViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/OpenCampaignBinViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/SaveCampaignBinAsViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/ViewModels/StatusItemViewModel.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/AddStatusWindow.xaml create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/AddStatusWindow.xaml.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/AnimationFragmentDisplayConverter.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/BattleFragmentPickerWindow.xaml create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/BattleFragmentPickerWindow.xaml.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/CampaignAnimationSetEditorView.xaml create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/CampaignAnimationSetEditorView.xaml.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/OpenCampaignBinWindow.xaml create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/OpenCampaignBinWindow.xaml.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/PathTailConverter.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/PoseIdDisplayConverter.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/SaveCampaignBinAsWindow.xaml create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/SaveCampaignBinAsWindow.xaml.cs create mode 100644 Editors/CampaignAnimationSetEditor/Editors.CampaignAnimationSetEditor/Views/StatusDescriptionConverter.cs create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/CampaignAnimationBinRoundTripTests.cs create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/CampaignAnimationSetGeneratorServiceTests.cs create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/Fixtures/cam_bi2_dlc27_preyton_boss.bin create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/Fixtures/cam_hu6_gor_axe.bin create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/FreezeRootBoneCommandTests.cs create mode 100644 Editors/CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor/Test.CampaignAnimationSetEditor.csproj diff --git a/AssetEditor.sln b/AssetEditor.sln index f32c46102..ac9a5f78b 100644 --- a/AssetEditor.sln +++ b/AssetEditor.sln @@ -134,6 +134,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.CampaignAnimationCreat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.CoreLog", "Shared\Logging\Shared.Core.Logging\Shared.CoreLog.csproj", "{C79EDB14-ED00-4474-B59F-9EED0AF39459}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CampaignAnimationSetEditor", "CampaignAnimationSetEditor", "{AA14F125-E7D2-8CBC-FC94-A1A6F78D9FAF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editors.CampaignAnimationSetEditor", "Editors\CampaignAnimationSetEditor\Editors.CampaignAnimationSetEditor\Editors.CampaignAnimationSetEditor.csproj", "{417FAB39-3269-4D1C-981B-DD9965E1B26C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.CampaignAnimationSetEditor", "Editors\CampaignAnimationSetEditor\Test.CampaignAnimationSetEditor\Test.CampaignAnimationSetEditor.csproj", "{32582784-3E26-44C1-9375-ECE044B4CB4A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -648,6 +654,30 @@ Global {C79EDB14-ED00-4474-B59F-9EED0AF39459}.Release|x64.Build.0 = Release|Any CPU {C79EDB14-ED00-4474-B59F-9EED0AF39459}.Release|x86.ActiveCfg = Release|Any CPU {C79EDB14-ED00-4474-B59F-9EED0AF39459}.Release|x86.Build.0 = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|x64.ActiveCfg = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|x64.Build.0 = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|x86.ActiveCfg = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Debug|x86.Build.0 = Debug|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|Any CPU.Build.0 = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|x64.ActiveCfg = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|x64.Build.0 = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|x86.ActiveCfg = Release|Any CPU + {417FAB39-3269-4D1C-981B-DD9965E1B26C}.Release|x86.Build.0 = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|x64.ActiveCfg = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|x64.Build.0 = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|x86.ActiveCfg = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Debug|x86.Build.0 = Debug|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|Any CPU.Build.0 = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|x64.ActiveCfg = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|x64.Build.0 = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|x86.ActiveCfg = Release|Any CPU + {32582784-3E26-44C1-9375-ECE044B4CB4A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -710,6 +740,9 @@ Global {438E6F1B-F5A9-49F3-8516-CB5E9D316C81} = {ED432A81-F5C7-0469-2ED7-3AF47D036060} {91617891-AD16-423F-B56F-AC0D2CE82B95} = {ED432A81-F5C7-0469-2ED7-3AF47D036060} {C79EDB14-ED00-4474-B59F-9EED0AF39459} = {58F19D12-FE6E-A99A-941B-96C21567964E} + {AA14F125-E7D2-8CBC-FC94-A1A6F78D9FAF} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} + {417FAB39-3269-4D1C-981B-DD9965E1B26C} = {AA14F125-E7D2-8CBC-FC94-A1A6F78D9FAF} + {32582784-3E26-44C1-9375-ECE044B4CB4A} = {AA14F125-E7D2-8CBC-FC94-A1A6F78D9FAF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB5968F3-98ED-4AFF-98EA-0DBEDCACADF2} diff --git a/AssetEditor/AssetEditor.csproj b/AssetEditor/AssetEditor.csproj index 4bba02b08..beb03a165 100644 --- a/AssetEditor/AssetEditor.csproj +++ b/AssetEditor/AssetEditor.csproj @@ -30,6 +30,7 @@ + diff --git a/AssetEditor/Services/DependencyInjectionConfig.cs b/AssetEditor/Services/DependencyInjectionConfig.cs index ebb066dbf..3483c2eef 100644 --- a/AssetEditor/Services/DependencyInjectionConfig.cs +++ b/AssetEditor/Services/DependencyInjectionConfig.cs @@ -37,6 +37,7 @@ public DependencyInjectionConfig(bool loadResources = true) new Editors.Ipc.DependencyInjectionContainer(), new Editors.BmdEditor.DependencyInjectionContainer(), new Editors.CscEditor.DependencyInjectionContainer(), + new Editors.CampaignAnimationSetEditor.DependencyInjectionContainer(), // Host application new DependencyInjectionContainer(), diff --git a/AssetEditor/Themes/Controls.xaml b/AssetEditor/Themes/Controls.xaml index faccf006f..ba3a43a87 100644 --- a/AssetEditor/Themes/Controls.xaml +++ b/AssetEditor/Themes/Controls.xaml @@ -3587,7 +3587,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +