diff --git a/AssetEditor.sln b/AssetEditor.sln index e97fb1a03..c0993978a 100644 --- a/AssetEditor.sln +++ b/AssetEditor.sln @@ -29,8 +29,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{17E1BB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.Shared.Core", "Editors\Shared\Editors.Shared.Core\Editors.Shared.Core.csproj", "{C130109A-1D52-4F5E-A760-24AEF648CE93}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.AnimationTextEditors", "Editors\SimpleAnimationEditors\Editors.AnimationTextEditors.csproj", "{CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.Reports", "Editors\Reports\Editors.Reports.csproj", "{EAFBC3D8-A146-4BA3-8024-DE4E20D3C884}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.TextureEditor", "Editors\TextureEditor\Editors.TextureEditor.csproj", "{8E55B123-C8E5-4D65-AAAA-C4DC4713CB8E}" @@ -92,6 +90,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.ByteParsing", "Share EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.ByteParsingTest", "Shared\ByteParsing\Shared.ByteParsingTest\Shared.ByteParsingTest.csproj", "{328485AF-4B94-47CE-B9EF-5D267F9E3F74}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnimationFragmentEditor", "AnimationFragmentEditor", "{9859545E-76FC-4790-AF99-E1BCB1D4739D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editors.AnimationFragmentEditor", "Editors\AnimationFragmentEditor\Editor.AnimationFragmentEditor\Editors.AnimationFragmentEditor.csproj", "{37C9C29E-1353-1519-BBC0-D7827A8AF636}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -130,10 +132,6 @@ Global {C130109A-1D52-4F5E-A760-24AEF648CE93}.Debug|Any CPU.Build.0 = Debug|Any CPU {C130109A-1D52-4F5E-A760-24AEF648CE93}.Release|Any CPU.ActiveCfg = Release|Any CPU {C130109A-1D52-4F5E-A760-24AEF648CE93}.Release|Any CPU.Build.0 = Release|Any CPU - {CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B}.Release|Any CPU.Build.0 = Release|Any CPU {EAFBC3D8-A146-4BA3-8024-DE4E20D3C884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAFBC3D8-A146-4BA3-8024-DE4E20D3C884}.Debug|Any CPU.Build.0 = Debug|Any CPU {EAFBC3D8-A146-4BA3-8024-DE4E20D3C884}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -218,6 +216,10 @@ Global {328485AF-4B94-47CE-B9EF-5D267F9E3F74}.Debug|Any CPU.Build.0 = Debug|Any CPU {328485AF-4B94-47CE-B9EF-5D267F9E3F74}.Release|Any CPU.ActiveCfg = Release|Any CPU {328485AF-4B94-47CE-B9EF-5D267F9E3F74}.Release|Any CPU.Build.0 = Release|Any CPU + {37C9C29E-1353-1519-BBC0-D7827A8AF636}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37C9C29E-1353-1519-BBC0-D7827A8AF636}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37C9C29E-1353-1519-BBC0-D7827A8AF636}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37C9C29E-1353-1519-BBC0-D7827A8AF636}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -231,7 +233,6 @@ Global {13EB0C34-99A7-49B2-BA93-B93073A43F45} = {7070A990-1A62-46A9-ABDF-BE030E3A4336} {17E1BB4D-00DF-4323-80C7-B8A8EDF2A5AA} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} {C130109A-1D52-4F5E-A760-24AEF648CE93} = {17E1BB4D-00DF-4323-80C7-B8A8EDF2A5AA} - {CAEB33BF-48DF-4388-BE6B-7D7ABBB9414B} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} {EAFBC3D8-A146-4BA3-8024-DE4E20D3C884} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} {8E55B123-C8E5-4D65-AAAA-C4DC4713CB8E} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} {410AC3F4-021C-4993-BCCA-1810D153075D} = {4D35FFE2-8490-4694-8981-654016F2BD3D} @@ -260,6 +261,8 @@ Global {786DB586-5DF5-4CF9-A485-A20A7BC184F7} = {7070A990-1A62-46A9-ABDF-BE030E3A4336} {BE02D945-E70C-4A0E-A16D-8BFA3CB1A877} = {786DB586-5DF5-4CF9-A485-A20A7BC184F7} {328485AF-4B94-47CE-B9EF-5D267F9E3F74} = {786DB586-5DF5-4CF9-A485-A20A7BC184F7} + {9859545E-76FC-4790-AF99-E1BCB1D4739D} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0} + {37C9C29E-1353-1519-BBC0-D7827A8AF636} = {9859545E-76FC-4790-AF99-E1BCB1D4739D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB5968F3-98ED-4AFF-98EA-0DBEDCACADF2} diff --git a/AssetEditor/App.xaml.cs b/AssetEditor/App.xaml.cs index 81ddb36ee..457fc048a 100644 --- a/AssetEditor/App.xaml.cs +++ b/AssetEditor/App.xaml.cs @@ -24,6 +24,7 @@ public partial class App : Application protected override void OnStartup(StartupEventArgs e) { ApplicationStateRecorder.Initialize(); + PackFileLog.IsLoggingEnabled = false; ShutdownMode = ShutdownMode.OnExplicitShutdown; VersionChecker.CheckVersion(); diff --git a/AssetEditor/AssetEditor.csproj b/AssetEditor/AssetEditor.csproj index 4b8f2463c..ee8486051 100644 --- a/AssetEditor/AssetEditor.csproj +++ b/AssetEditor/AssetEditor.csproj @@ -14,6 +14,7 @@ + diff --git a/AssetEditor/Properties/launchSettings.json b/AssetEditor/Properties/launchSettings.json index 65126f01e..4b1f55de6 100644 --- a/AssetEditor/Properties/launchSettings.json +++ b/AssetEditor/Properties/launchSettings.json @@ -9,6 +9,11 @@ "commandLineArgs": "-devcfg Kitbash_Karl", "nativeDebugging": false }, + "AE-AnimPack_Wh3": { + "commandName": "Project", + "commandLineArgs": "-devcfg AnimPack_WH3", + "nativeDebugging": false + }, "AE-KitbashRat": { "commandName": "Project", "commandLineArgs": "-devcfg Kitbash_Rat", diff --git a/AssetEditor/Services/DependencyInjectionConfig.cs b/AssetEditor/Services/DependencyInjectionConfig.cs index ccc060de6..470e40da1 100644 --- a/AssetEditor/Services/DependencyInjectionConfig.cs +++ b/AssetEditor/Services/DependencyInjectionConfig.cs @@ -23,7 +23,7 @@ public DependencyInjectionConfig(bool loadResources = true) // Domains new Editors.Shared.Core.DependencyInjectionContainer(), - new Editors.AnimationTextEditors.DependencyInjectionContainer(), + new Editors.AnimationFragmentEditor.DependencyInjectionContainer(), new Editors.Reports.DependencyInjectionContainer(), new Editors.KitbasherEditor.DependencyInjectionContainer(), new Editors.AnimationMeta.DependencyInjectionContainer(), diff --git a/AssetEditor/ViewModels/MenuBarViewModel.cs b/AssetEditor/ViewModels/MenuBarViewModel.cs index e5fcce568..135532b40 100644 --- a/AssetEditor/ViewModels/MenuBarViewModel.cs +++ b/AssetEditor/ViewModels/MenuBarViewModel.cs @@ -5,8 +5,8 @@ using System.Linq; using AssetEditor.UiCommands; using CommonControls.BaseDialogs; -using CommonControls.Editors.AnimationPack; using CommunityToolkit.Mvvm.Input; +using Editors.AnimationFragmentEditor.AnimationPack.Commands; using Editors.Reports.Animation; using Editors.Reports.Audio; using Editors.Reports.DeepSearch; @@ -79,9 +79,9 @@ [RelayCommand] private void CreateNewPackFile() _packfileService.SetEditablePack(newPackFile); } } - - [RelayCommand] private void CreateAnimPackWarhammer3() => AnimationPackSampleDataCreator.CreateAnimationDbWarhammer3(_packFileSaveService, _packfileService); - [RelayCommand] private void CreateAnimPack3k() => AnimationPackSampleDataCreator.CreateAnimationDb3k(_packfileService, _packFileSaveService); + + [RelayCommand] private void CreateAnimPackWarhammer3() => _uiCommandFactory.Create().CreateAnimationDbWarhammer3(); + [RelayCommand] private void CreateAnimPack3k() => _uiCommandFactory.Create().CreateAnimationDb3k(); [RelayCommand] private void SaveActivePack() => _uiCommandFactory.Create().Execute(); [RelayCommand] private void OpenWh2AnimpackUpdater() => new AnimPackUpdaterService(_packfileService).Process(); [RelayCommand] private void GenerateRmv2Report() => _uiCommandFactory.Create().Execute(); diff --git a/Editors/AnimationEditor/MountAnimationCreator/Services/BatchProcessorService.cs b/Editors/AnimationEditor/MountAnimationCreator/Services/BatchProcessorService.cs index c41fd8870..bf9808620 100644 --- a/Editors/AnimationEditor/MountAnimationCreator/Services/BatchProcessorService.cs +++ b/Editors/AnimationEditor/MountAnimationCreator/Services/BatchProcessorService.cs @@ -30,7 +30,7 @@ class BatchProcessorService IAnimationBinGenericFormat _riderFragment; uint _animationOutputFormat; - AnimationPackFile _outAnimPack; + AnimationPackFileDatabase _outAnimPack; AnimationBinWh3 _riderOutputBin; @@ -204,7 +204,7 @@ List GetAnimationsThatRequireNoChanges() void CreateAnimPackFile() { - _outAnimPack = new AnimationPackFile("Placeholder"); + _outAnimPack = new AnimationPackFileDatabase("Placeholder"); _riderOutputBin = new AnimationBinWh3(@"animations/database/battle/bin/" + _animBinName) { SkeletonName = _riderFragment.SkeletonName, diff --git a/Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportView.xaml b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportView.xaml similarity index 100% rename from Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportView.xaml rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportView.xaml diff --git a/Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportView.xaml.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportView.xaml.cs similarity index 100% rename from Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportView.xaml.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportView.xaml.cs diff --git a/Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportViewModel.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportViewModel.cs similarity index 100% rename from Editors/SimpleAnimationEditors/AnimationBatchExporter/AnimationBatchExportViewModel.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationBatchExporter/AnimationBatchExportViewModel.cs diff --git a/Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/AnimFileToTextConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/AnimFileToTextConverter.cs similarity index 98% rename from Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/AnimFileToTextConverter.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/AnimFileToTextConverter.cs index c81a4aaf2..25b8e6efd 100644 --- a/Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/AnimFileToTextConverter.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/AnimFileToTextConverter.cs @@ -5,7 +5,7 @@ using Shared.GameFormats.Animation; using Shared.Ui.Editors.TextEditor; -namespace CommonControls.Editors.AnimationFilePreviewEditor +namespace Editors.AnimationFragmentEditor.AnimationFilePreviewEditor { class AnimFileToTextConverter : ITextConverter { diff --git a/Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs similarity index 96% rename from Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs index 1820202e5..7a44f33f7 100644 --- a/Editors/SimpleAnimationEditors/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationFilePreviewEditor/InvMatrixToTextConverter.cs @@ -5,7 +5,7 @@ using Shared.GameFormats.Animation; using Shared.Ui.Editors.TextEditor; -namespace CommonControls.Editors.AnimationFilePreviewEditor +namespace Editors.AnimationFragmentEditor.AnimationFilePreviewEditor { public class InvMatrixToTextConverter : ITextConverter { diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs new file mode 100644 index 000000000..c26d754a1 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs @@ -0,0 +1,182 @@ +using System.Windows; +using CommunityToolkit.Mvvm.Input; +using Editors.AnimationFragmentEditor.AnimationPack.Commands; +using Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinConverter; +using Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinWh3Converter; +using Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationFragmentConverter; +using GameWorld.Core.Services; +using Shared.Core.Events; +using Shared.Core.Misc; +using Shared.Core.PackFiles; +using Shared.Core.PackFiles.Models; +using Shared.Core.Services; +using Shared.Core.Settings; +using Shared.Core.ToolCreation; +using Shared.GameFormats.AnimationMeta.Parsing; +using Shared.GameFormats.AnimationPack; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3; +using Shared.Ui.Common; +using Shared.Ui.Editors.TextEditor; + +namespace CommonControls.Editors.AnimationPack +{ + public partial class AnimPackViewModel : NotifyPropertyChangedImpl, IEditorInterface, ISaveableEditor, IFileEditor + { + private readonly IUiCommandFactory _uiCommandFactory; + private readonly IPackFileService _pfs; + private readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper; + private ITextConverter? _activeConverter; + private readonly ApplicationSettingsService _appSettings; + private readonly IFileSaveService _packFileSaveService; + private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + + public string DisplayName { get; set; } = "Not set"; + + PackFile _packFile; + + public FilterCollection AnimationPackItems { get; set; } + + SimpleTextEditorViewModel _selectedItemViewModel; + public SimpleTextEditorViewModel SelectedItemViewModel { get => _selectedItemViewModel; set => SetAndNotify(ref _selectedItemViewModel, value); } + + public AnimPackViewModel(IUiCommandFactory uiCommandFactory, IPackFileService pfs, ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, ApplicationSettingsService appSettings, IFileSaveService packFileSaveService, MetaDataTagDeSerializer metaDataTagDeSerializer) + { + _uiCommandFactory = uiCommandFactory; + _pfs = pfs; + _skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper; + _appSettings = appSettings; + _packFileSaveService = packFileSaveService; + _metaDataTagDeSerializer = metaDataTagDeSerializer; + + AnimationPackItems = new FilterCollection(new List(), OnItemSelected, BeforeItemSelected) + { + SearchFilter = (value, rx) => { return rx.Match(value.FileName).Success; } + }; + } + + [RelayCommand] private void RenameAction() => _uiCommandFactory.Create().Execute(this); + [RelayCommand] private void RemoveAction() => _uiCommandFactory.Create().Execute(this); + [RelayCommand] private void CopyFullPathAction() => Clipboard.SetText(AnimationPackItems.SelectedItem.FileName); + [RelayCommand] private void CreateEmptyWarhammer3AnimSetFileAction() => _uiCommandFactory.Create().Execute(this); + [RelayCommand] private void ExportAnimationSlotsWh3Action() => _uiCommandFactory.Create().Warhammer3(); + [RelayCommand] private void ExportAnimationSlotsWh2Action() => _uiCommandFactory.Create().Warhammer2(); + + bool BeforeItemSelected(IAnimationPackFile item) + { + if (SelectedItemViewModel != null && SelectedItemViewModel.HasUnsavedChanges()) + { + if (MessageBox.Show("Editor has unsaved changes that will be lost.\nContinue?", "", MessageBoxButton.YesNo) == MessageBoxResult.No) + return false; + } + + return true; + } + + void OnItemSelected(IAnimationPackFile seletedFile) + { + _activeConverter = null; + if (seletedFile is AnimationFragmentFile typedFragment) + _activeConverter = new AnimationFragmentFileToXmlConverter(_skeletonAnimationLookUpHelper, _appSettings.CurrentSettings.CurrentGame); + else if (seletedFile is AnimationBin typedBin) + _activeConverter = new AnimationBinFileToXmlConverter(); + else if (seletedFile is AnimationBinWh3 wh3Bin) + _activeConverter = new AnimationBinWh3FileToXmlConverter(_skeletonAnimationLookUpHelper, _metaDataTagDeSerializer, CurrentFile); + + if (seletedFile == null || _activeConverter == null || seletedFile.IsUnknownFile) + { + SelectedItemViewModel = new SimpleTextEditorViewModel(); + SelectedItemViewModel.SaveCommand = null; + SelectedItemViewModel.TextEditor?.ShowLineNumbers(true); + SelectedItemViewModel.TextEditor?.SetSyntaxHighlighting("XML"); + SelectedItemViewModel.Text = ""; + SelectedItemViewModel.ResetChangeLog(); + } + else + { + SelectedItemViewModel = new SimpleTextEditorViewModel(); + SelectedItemViewModel.SaveCommand = new RelayCommand(() => SaveActiveFile()); + SelectedItemViewModel.TextEditor?.ShowLineNumbers(true); + SelectedItemViewModel.TextEditor?.SetSyntaxHighlighting(_activeConverter.GetSyntaxType()); + SelectedItemViewModel.Text = _activeConverter.GetText(seletedFile.ToByteArray()); + SelectedItemViewModel.ResetChangeLog(); + } + + } + public void Close() { } + public bool HasUnsavedChanges { get; set; } + + public PackFile CurrentFile => _packFile; + + public bool SaveActiveFile() + { + if (_packFile == null) + { + MessageBox.Show("Can not save in this mode - Open the file normally"); + return false; + } + + var fileName = AnimationPackItems.SelectedItem.FileName; + var bytes = _activeConverter.ToBytes(SelectedItemViewModel.Text, fileName, _pfs, out var error); + + if (bytes == null || error != null) + { + SelectedItemViewModel.TextEditor.HightLightText(error.ErrorLineNumber, error.ErrorPosition, error.ErrorLength); + MessageBox.Show(error.Text, "Error"); + return false; + } + + var seletedFile = AnimationPackItems.SelectedItem; + seletedFile.CreateFromBytes(bytes); + seletedFile.IsChanged.Value = true; + + SelectedItemViewModel.ResetChangeLog(); + HasUnsavedChanges = true; + + return true; + } + + + public bool Save() + { + if (_packFile == null) + { + MessageBox.Show("Can not save in this mode - Open the file normally"); + return false; + } + + if (SelectedItemViewModel != null && SelectedItemViewModel.HasUnsavedChanges()) + { + if (MessageBox.Show("Editor has unsaved changes.\nSave anyway?", "", MessageBoxButton.YesNo) == MessageBoxResult.No) + return false; + } + + var newAnimPack = new AnimationPackFileDatabase(_pfs.GetFullPath(_packFile)); + + foreach (var file in AnimationPackItems.PossibleValues) + newAnimPack.AddFile(file); + + var savePath = _pfs.GetFullPath(_packFile); + + var result = _packFileSaveService.Save(savePath, AnimationPackSerializer.ConvertToBytes(newAnimPack), false); + if (result != null) + { + HasUnsavedChanges = false; + foreach (var file in AnimationPackItems.PossibleValues) + file.IsChanged.Value = false; + } + + return true; + } + + + public void LoadFile(PackFile file) + { + _packFile = file; + var animPack = AnimationPackSerializer.Load(_packFile, _pfs); + var itemNames = animPack.Files.ToList(); + AnimationPackItems.UpdatePossibleValues(itemNames); + DisplayName = animPack.FileName; + } + } +} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackView.xaml b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimationPackView.xaml similarity index 91% rename from Editors/SimpleAnimationEditors/AnimationPack/AnimationPackView.xaml rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimationPackView.xaml index 685e8de9c..2c8c38aa0 100644 --- a/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackView.xaml +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimationPackView.xaml @@ -23,13 +23,12 @@ - + - - + - - + + @@ -71,9 +70,9 @@ - - - + + + diff --git a/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackView.xaml.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimationPackView.xaml.cs similarity index 100% rename from Editors/SimpleAnimationEditors/AnimationPack/AnimationPackView.xaml.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimationPackView.xaml.cs diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateEmptyWarhammer3AnimSetFileCommand.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateEmptyWarhammer3AnimSetFileCommand.cs new file mode 100644 index 000000000..12b9cefce --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateEmptyWarhammer3AnimSetFileCommand.cs @@ -0,0 +1,102 @@ +using CommonControls.BaseDialogs; +using CommonControls.Editors.AnimationPack; +using Shared.Core.Events; +using Shared.Core.Misc; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3; +using static Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry; +using AnimationBinEntry = Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Commands +{ + public class CreateEmptyWarhammer3AnimSetFileCommand : IUiCommand + { + public void Execute(AnimPackViewModel editor) + { + var fileName = GetAnimSetFileName(); + if (fileName == null) + return; + + var animSet = CreateExampleWarhammer3AnimSet(fileName); + editor.AnimationPackItems.PossibleValues.Add(animSet); + editor.AnimationPackItems.UpdatePossibleValues(editor.AnimationPackItems.PossibleValues); + } + + string? GetAnimSetFileName() + { + var window = new TextInputWindow("Fragment name", ""); + if (window.ShowDialog() == true) + { + var filename = SaveUtility.EnsureEnding(window.TextValue, ".frg"); + return filename; + } + + return null; + } + + static IAnimationPackFile CreateExampleWarhammer3AnimSet(string binName) + { + var filename = SaveUtility.EnsureEnding(binName, ".bin"); + var filePath = @"animations/database/battle/bin/" + filename; + var outputFile = new AnimationBinWh3(filePath) + { + TableVersion = 4, + TableSubVersion = 3, + Name = binName, + Unknown = "", + MountBin = "", + SkeletonName = "humanoid01", + LocomotionGraph = "animations/locomotion_graphs/entity_locomotion_graph.xml", + UnknownValue1 = 0, + }; + + outputFile.AnimationTableEntries.Add(new AnimationBinEntry() + { + AnimationId = 1, // STAND + BlendIn = 0.5f, + SelectionWeight = 1, + WeaponBools = 1, + Unk = false, + + AnimationRefs = new List() + { + new AnimationRef() + { + AnimationFile = @"animations/battle/humanoid01/sword_and_shield/stand/hu1_sws_stand_01.anim", + AnimationMetaFile = @"", + AnimationSoundMetaFile = @"" , + }, + } + }); + + outputFile.AnimationTableEntries.Add(new AnimationBinEntry() + { + AnimationId = 453,// Attack_1 + BlendIn = 0.3f, + SelectionWeight = 1, + WeaponBools = 1, + Unk = false, + + AnimationRefs = new List() + { + new AnimationRef() + { + AnimationFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.anim", + AnimationMetaFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.meta", + AnimationSoundMetaFile = @"animations/audio/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.{27tsfy}.snd.meta", + }, + new AnimationRef() + { + AnimationFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.anim", + AnimationMetaFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.anm.meta", + AnimationSoundMetaFile = @"animations/audio/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.{1o2asvr}.snd.meta", + } + } + }); + + return outputFile; + } + + } + +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateExampleAnimationDbCommand.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateExampleAnimationDbCommand.cs new file mode 100644 index 000000000..f4a25be15 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/CreateExampleAnimationDbCommand.cs @@ -0,0 +1,75 @@ +using System.Windows; +using CommonControls.BaseDialogs; +using Shared.Core.Events; +using Shared.Core.Misc; +using Shared.Core.PackFiles; +using Shared.Core.PackFiles.Models; +using Shared.Core.Services; +using Shared.GameFormats.AnimationPack; + + +namespace Editors.AnimationFragmentEditor.AnimationPack.Commands +{ + public class CreateExampleAnimationDbCommand : IUiCommand + { + private readonly IFileSaveService _saveHelper; + private readonly IPackFileService _pfs; + + public CreateExampleAnimationDbCommand(IFileSaveService saveHelper, IPackFileService pfs) + { + _saveHelper = saveHelper; + _pfs = pfs; + } + + public PackFile? CreateAnimationDbWarhammer3() + { + var window = new TextInputWindow("New AnimPack name", ""); + if (window.ShowDialog() == true) + return CreateAnimationDbWarhammer3(window.TextValue); + return null; + } + + static string GenerateWh3AnimPackName(string name) + { + var fileName = SaveUtility.EnsureEnding(name, ".animpack"); + var filePath = @"animations/database/battle/bin/" + fileName; + return filePath; + } + + PackFile? CreateAnimationDbWarhammer3(string name) + { + var filePath = GenerateWh3AnimPackName(name); + + if (!SaveUtility.IsFilenameUnique(_pfs, filePath)) + { + MessageBox.Show("Filename is not unique"); + return null; + } + + var animPack = new AnimationPackFileDatabase("Placeholder"); + return _saveHelper.Save(filePath, AnimationPackSerializer.ConvertToBytes(animPack), false); + } + + public void CreateAnimationDb3k() + { + var window = new TextInputWindow("New AnimPack name", ""); + if (window.ShowDialog() == true) + { + var fileName = SaveUtility.EnsureEnding(window.TextValue, ".animpack"); + var filePath = @"animations/database/battle/bin/" + fileName; + if (!SaveUtility.IsFilenameUnique(_pfs, filePath)) + { + MessageBox.Show("Filename is not unique"); + return; + } + + // Create dummy data + var animPack = new AnimationPackFileDatabase("Placeholder"); + _saveHelper.Save(filePath, AnimationPackSerializer.ConvertToBytes(animPack), false); + } + } + + + + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/ExportAnimationSlotCommand.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/ExportAnimationSlotCommand.cs new file mode 100644 index 000000000..bf4460975 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/ExportAnimationSlotCommand.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Text; +using Shared.Core.Events; +using Shared.GameFormats.AnimationPack; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Commands +{ + public class ExportAnimationSlotCommand : IUiCommand + { + public void Warhammer3() + { + var slots = AnimationSlotTypeHelperWh3.Values.Select(x => x.Id + "\t\t" + x.Value).ToList(); + SaveAnimationSlotsToFile(slots); + } + + public void Warhammer2() + { + var slots = DefaultAnimationSlotTypeHelper.Values.Select(x => x.Id + "\t\t" + x.Value).ToList(); + SaveAnimationSlotsToFile(slots); + } + + void SaveAnimationSlotsToFile(List slots) + { + using var dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.Filter = "Text files(*.txt) | *.txt | All files(*.*) | *.* "; + if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) + return; + string path = dlg.FileName; + + StringBuilder sb = new StringBuilder(); + foreach (var slot in slots) + sb.AppendLine(slot); + + File.WriteAllText(path, sb.ToString()); + } + + } + +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RemoveSelectedFileCommand.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RemoveSelectedFileCommand.cs new file mode 100644 index 000000000..edf511334 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RemoveSelectedFileCommand.cs @@ -0,0 +1,16 @@ +using CommonControls.Editors.AnimationPack; +using Shared.Core.Events; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Commands +{ + public class RemoveSelectedFileCommand : IUiCommand + { + public void Execute(AnimPackViewModel editor) + { + editor.AnimationPackItems.PossibleValues.Remove(editor.AnimationPackItems.SelectedItem); + editor.AnimationPackItems.RefreshFilter(); + } + + } + +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RenameSelectedFileCommand.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RenameSelectedFileCommand.cs new file mode 100644 index 000000000..6eb9952ae --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Commands/RenameSelectedFileCommand.cs @@ -0,0 +1,24 @@ +using CommonControls.BaseDialogs; +using CommonControls.Editors.AnimationPack; +using Shared.Core.Events; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Commands +{ + public class RenameSelectedFileCommand : IUiCommand + { + public void Execute(AnimPackViewModel editor) + { + var animFile = editor.AnimationPackItems.PossibleValues.FirstOrDefault(file => file == editor.AnimationPackItems.SelectedItem); + if (animFile == null) + return; + + var window = new TextInputWindow("Rename Anim File", animFile.FileName); + if (window.ShowDialog() == true) + animFile.FileName = window.TextValue; + + // way to refresh the view + editor.AnimationPackItems.RefreshFilter(); + } + } + +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/AnimationBinFileToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/AnimationBinFileToXmlConverter.cs new file mode 100644 index 000000000..12377cef9 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/AnimationBinFileToXmlConverter.cs @@ -0,0 +1,63 @@ +using Editors.Shared.Core.Editors.TextEditor; +using Shared.Core.PackFiles; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes; +using Shared.Ui.Editors.TextEditor; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinConverter +{ + public partial class AnimationBinFileToXmlConverter : XmlToBinaryConverter + { + protected override string CleanUpXml(string xmlText) + { + xmlText = xmlText.Replace("", "\n"); + xmlText = xmlText.Replace("", "\n"); + return xmlText; + } + + protected override Bin ConvertBinaryToXml(byte[] bytes) + { + AnimationBin binFile = new AnimationBin("", bytes); + var outputBin = new Bin(); + outputBin.BinEntry = new List(); + + foreach (var item in binFile.AnimationTableEntries) + { + var entry = new BinEntry(); + entry.Name = item.Name; + entry.Fragments = string.Join(", ", item.FragmentReferences.Select(x => x.Name)); + entry.Skeleton = new Skeleton() { Value = item.SkeletonName }; + entry.MountSkeleton = new MountSkeleton() { Value = item.MountName }; + entry.Unknown = new Unknown() { Value = item.Unknown }; + outputBin.BinEntry.Add(entry); + } + + return outputBin; + } + + protected override byte[] ConvertXmlToBinary(Bin bin, string fileName) + { + var output = new AnimationBin(fileName); + foreach (var item in bin.BinEntry) + { + var entry = new AnimationBinEntry(item.Name, item.Skeleton.Value, item.MountSkeleton.Value) + { + Unknown = item.Unknown.Value + }; + + var refs = item.Fragments.Split(","); + foreach (var refInstance in refs) + { + var str = refInstance.Trim(); + if (string.IsNullOrEmpty(str) == false) + entry.FragmentReferences.Add(new AnimationBinEntry.FragmentReference() { Name = str, Unknown = 0 }); + } + + output.AnimationTableEntries.Add(entry); + } + return output.ToByteArray(); + } + + + protected override ITextConverter.SaveError Validate(Bin type, string s, IPackFileService pfs, string filepath) => null; + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/XmlFormat.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/XmlFormat.cs new file mode 100644 index 000000000..7bb983eb6 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinConverter/XmlFormat.cs @@ -0,0 +1,51 @@ +using System.Xml; +using System.Xml.Serialization; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinConverter +{ + [XmlRoot(ElementName = "Skeleton")] + public class Skeleton + { + [XmlAttribute(AttributeName = "value")] + public string Value { get; set; } + } + + [XmlRoot(ElementName = "MountSkeleton")] + public class MountSkeleton + { + [XmlAttribute(AttributeName = "value")] + public string Value { get; set; } + } + + [XmlRoot(ElementName = "Unknown")] + public class Unknown + { + [XmlAttribute(AttributeName = "value")] + public short Value { get; set; } + } + + [XmlRoot(ElementName = "BinEntry")] + public class BinEntry + { + [XmlElement(ElementName = "Skeleton")] + public Skeleton Skeleton { get; set; } + [XmlElement(ElementName = "MountSkeleton")] + public MountSkeleton MountSkeleton { get; set; } + [XmlElement(ElementName = "Fragments")] + public string Fragments { get; set; } + [XmlElement(ElementName = "Unknown")] + public Unknown Unknown { get; set; } + [XmlAttribute(AttributeName = "name")] + public string Name { get; set; } + } + + public partial class AnimationBinFileToXmlConverter + { + [XmlRoot(ElementName = "Bin")] + public class Bin + { + [XmlElement(ElementName = "BinEntry")] + public List BinEntry { get; set; } + } + } +} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinWh3FileToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs similarity index 89% rename from Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinWh3FileToXmlConverter.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs index 0a19399a1..12e8289dc 100644 --- a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinWh3FileToXmlConverter.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs @@ -1,7 +1,5 @@ -using System.Xml; -using System.Xml.Serialization; -using CommonControls.BaseDialogs.ErrorListDialog; -using CommonControls.Editors.AnimationPack.Converters; +using CommonControls.BaseDialogs.ErrorListDialog; +using Editors.Shared.Core.Editors.TextEditor; using GameWorld.Core.Services; using Shared.Core.ErrorHandling; using Shared.Core.PackFiles; @@ -13,9 +11,9 @@ using Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3; using Shared.Ui.Editors.TextEditor; -namespace Editors.AnimationTextEditors.AnimationPack.Converters +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinWh3Converter { - public class AnimationBinWh3FileToXmlConverter : BaseAnimConverter + public class AnimationBinWh3FileToXmlConverter : XmlToBinaryConverter { private readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper; private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; @@ -23,10 +21,13 @@ public class AnimationBinWh3FileToXmlConverter : BaseAnimConverter _animationsVersionFoundInPersistenceMeta = []; - public AnimationBinWh3FileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, MetaDataTagDeSerializer metaDataTagDeSerializer) + private readonly PackFile _animPackToValidate; + + public AnimationBinWh3FileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, MetaDataTagDeSerializer metaDataTagDeSerializer, PackFile animPackToValidate) { _skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper; _metaDataTagDeSerializer = metaDataTagDeSerializer; + _animPackToValidate = animPackToValidate; } protected override string CleanUpXml(string xmlText) @@ -37,7 +38,7 @@ protected override string CleanUpXml(string xmlText) return xmlText; } - protected override XmlFormat ConvertBytesToXmlClass(byte[] bytes) + protected override XmlFormat ConvertBinaryToXml(byte[] bytes) { var binFile = new AnimationBinWh3("", bytes); var outputBin = new XmlFormat(); @@ -69,7 +70,7 @@ protected override XmlFormat ConvertBytesToXmlClass(byte[] bytes) BlendId = animation.BlendIn, BlendOut = animation.SelectionWeight, Unk = animation.Unk, - WeaponBone = ConvertIntToBoolArray((int)animation.WeaponBools), + WeaponBone = ValueConverterHelper.ConvertIntToBoolArray((int)animation.WeaponBools), }); foreach (var animationRef in animation.AnimationRefs) @@ -86,7 +87,7 @@ protected override XmlFormat ConvertBytesToXmlClass(byte[] bytes) return outputBin; } - protected override byte[] ConvertToAnimClassBytes(XmlFormat xmlBin, string fileName) + protected override byte[] ConvertXmlToBinary(XmlFormat xmlBin, string fileName) { var binFile = new AnimationBinWh3("", null); @@ -108,7 +109,7 @@ protected override byte[] ConvertToAnimClassBytes(XmlFormat xmlBin, string fileN AnimationId = (uint)slotHelper.GetfromValue(animationEntry.Slot).Id, BlendIn = animationEntry.BlendId, SelectionWeight = animationEntry.BlendOut, - WeaponBools = CreateWeaponFlagInt(animationEntry.WeaponBone), + WeaponBools = ValueConverterHelper.CreateWeaponFlagInt(animationEntry.WeaponBone), Unk = animationEntry.Unk, }); @@ -208,7 +209,7 @@ protected override ITextConverter.SaveError Validate(XmlFormat type, string s, I } var mountBin = type.Data.MountBin; - CheckForRiderAndHisMountAnimationsVersion(mountBin, AnimPackToValidate, animation.Slot, animationRef.File, pfs, errorList); + CheckForRiderAndHisMountAnimationsVersion(mountBin, _animPackToValidate, animation.Slot, animationRef.File, pfs, errorList); if (pfs.FindFile(animationRef.Sound) == null) errorList.Warning(animation.Slot, $"Sound file {animationRef.Sound} is not found"); @@ -409,7 +410,7 @@ private bool CheckForRiderAndHisMountAnimationsVersion(string mountBinReference, var mountBinBytes = findMountBinReference.ToByteArray(); - var parsedBin = ConvertBytesToXmlClass(mountBinBytes); + var parsedBin = ConvertBinaryToXml(mountBinBytes); var animations = parsedBin.Animations; var riderAnimationSlotWithoutPrefix = animationSlot.Substring(6); @@ -503,59 +504,5 @@ private bool CheckForRiderAndHisMountAnimationsVersion(string mountBinReference, - [XmlRoot(ElementName = "Instance")] - public class Instance - { - [XmlAttribute(AttributeName = "File")] - public string File { get; set; } - [XmlAttribute(AttributeName = "Meta")] - public string Meta { get; set; } - [XmlAttribute(AttributeName = "Sound")] - public string Sound { get; set; } - } - - [XmlRoot(ElementName = "Animation")] - public class Animation - { - [XmlElement(ElementName = "Instance")] - public List Ref { get; set; } = new List(); - [XmlAttribute(AttributeName = "Slot")] - public string Slot { get; set; } - [XmlAttribute(AttributeName = "BlendId")] - public float BlendId { get; set; } - [XmlAttribute(AttributeName = "SelectionWeight")] - public float BlendOut { get; set; } - [XmlAttribute(AttributeName = "WeaponBone")] - public string WeaponBone { get; set; } - [XmlAttribute(AttributeName = "Unk")] - public bool Unk { get; set; } - } - - - [XmlRoot(ElementName = "GeneralBinData")] - public class GeneralBinData - { - public uint TableVersion { get; set; } - public uint TableSubVersion { get; set; } - - public string Name { get; set; } - public string MountBin { get; set; } - public string SkeletonName { get; set; } - public string LocomotionGraph { get; set; } - public short UnknownValue1_RelatedToFlight { get; set; } - } - - [XmlRoot(ElementName = "Bin")] - public class XmlFormat - { - [XmlElement(ElementName = "Version")] - public string Version { get; set; } - - [XmlElement(ElementName = "GeneralBinData")] - public GeneralBinData Data { get; set; } - - [XmlElement(ElementName = "Animation")] - public List Animations { get; set; } = new List(); - } } } diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/XmlFormat.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/XmlFormat.cs new file mode 100644 index 000000000..3a0f6e244 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/XmlFormat.cs @@ -0,0 +1,64 @@ +using System.Xml; +using System.Xml.Serialization; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinWh3Converter +{ + + + [XmlRoot(ElementName = "Instance")] + public class Instance + { + [XmlAttribute(AttributeName = "File")] + public string File { get; set; } + [XmlAttribute(AttributeName = "Meta")] + public string Meta { get; set; } + [XmlAttribute(AttributeName = "Sound")] + public string Sound { get; set; } + } + + [XmlRoot(ElementName = "Animation")] + public class Animation + { + [XmlElement(ElementName = "Instance")] + public List Ref { get; set; } = new List(); + [XmlAttribute(AttributeName = "Slot")] + public string Slot { get; set; } + [XmlAttribute(AttributeName = "BlendId")] + public float BlendId { get; set; } + [XmlAttribute(AttributeName = "SelectionWeight")] + public float BlendOut { get; set; } + [XmlAttribute(AttributeName = "WeaponBone")] + public string WeaponBone { get; set; } + [XmlAttribute(AttributeName = "Unk")] + public bool Unk { get; set; } + } + + + [XmlRoot(ElementName = "GeneralBinData")] + public class GeneralBinData + { + public uint TableVersion { get; set; } + public uint TableSubVersion { get; set; } + + public string Name { get; set; } + public string MountBin { get; set; } + public string SkeletonName { get; set; } + public string LocomotionGraph { get; set; } + public short UnknownValue1_RelatedToFlight { get; set; } + } + + + [XmlRoot(ElementName = "Bin")] + public class XmlFormat + { + [XmlElement(ElementName = "Version")] + public string Version { get; set; } + + [XmlElement(ElementName = "GeneralBinData")] + public GeneralBinData Data { get; set; } + + [XmlElement(ElementName = "Animation")] + public List Animations { get; set; } = new List(); + } + +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/AnimationFragmentFileToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/AnimationFragmentFileToXmlConverter.cs new file mode 100644 index 000000000..d3b32cc8b --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/AnimationFragmentFileToXmlConverter.cs @@ -0,0 +1,85 @@ +using Editors.Shared.Core.Editors.TextEditor; +using GameWorld.Core.Services; +using Shared.Core.PackFiles; +using Shared.Core.Settings; +using Shared.GameFormats.AnimationPack; +using Shared.GameFormats.AnimationPack.AnimPackFileTypes; +using Shared.GameFormats.DB; +using Shared.Ui.Editors.TextEditor; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationFragmentConverter +{ + public class AnimationFragmentFileToXmlConverter : XmlToBinaryConverter + { + readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper; + readonly GameTypeEnum _preferedGame; + + public AnimationFragmentFileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, GameTypeEnum preferedGame) + { + _skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper; + _preferedGame = preferedGame; + } + + protected override ITextConverter.SaveError Validate(Animation xmlAnimation, string text, IPackFileService pfs, string filepath) => Validator.Validate(_skeletonAnimationLookUpHelper, xmlAnimation, text, pfs, filepath); + + protected override Animation ConvertBinaryToXml(byte[] bytes) + { + var fragmentFile = new AnimationFragmentFile("", bytes, _preferedGame); + var outputBin = new Animation(); + outputBin.AnimationFragmentEntry = new List(); + outputBin.Skeleton = fragmentFile.Skeletons.Values.FirstOrDefault(); + + foreach (var item in fragmentFile.Fragments) + { + var entry = new AnimationEntry(); + entry.Slot = item.Slot.Value; + entry.File = new ValueItem() { Value = item.AnimationFile }; + entry.Meta = new ValueItem() { Value = item.MetaDataFile }; + entry.Sound = new ValueItem() { Value = item.SoundMetaDataFile }; + entry.BlendInTime = new BlendInTime() { Value = item.BlendInTime }; + entry.SelectionWeight = new SelectionWeight() { Value = item.SelectionWeight }; + entry.Unknown = item.Unknown0; + entry.WeaponBone = ValueConverterHelper.ConvertIntToBoolArray(item.WeaponBone); + + outputBin.AnimationFragmentEntry.Add(entry); + } + + return outputBin; + } + + protected override string CleanUpXml(string xmlText) => xmlText.Replace("", "\n"); + + protected override byte[] ConvertXmlToBinary(Animation animation, string fileName) + { + var output = new AnimationFragmentFile(fileName, null, _preferedGame); + output.Skeletons = new StringArrayTable(animation.Skeleton, animation.Skeleton); + + foreach (var item in animation.AnimationFragmentEntry) + { + var entry = new AnimationSetEntry() + { + AnimationFile = item.File.Value, + MetaDataFile = item.Meta.Value, + SoundMetaDataFile = item.Sound.Value, + Comment = "", + BlendInTime = item.BlendInTime.Value, + Ignore = false, + SelectionWeight = item.SelectionWeight.Value, + Slot = _preferedGame == GameTypeEnum.Troy ? AnimationSlotTypeHelperTroy.GetfromValue(item.Slot) : DefaultAnimationSlotTypeHelper.GetfromValue(item.Slot), + Skeleton = animation.Skeleton, + Unknown0 = item.Unknown, + }; + + var unknown1Flags = item.WeaponBone.Split(","); + for (int i = 0; i < 6; i++) + entry.SetWeaponBoneFlags(i, bool.Parse(unknown1Flags[i])); + + output.Fragments.Add(entry); + } + + return output.ToByteArray(); + } + + + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/Validator.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/Validator.cs new file mode 100644 index 000000000..a2eb7e63d --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationFragmentConverter/Validator.cs @@ -0,0 +1,78 @@ +using CommonControls.BaseDialogs.ErrorListDialog; +using GameWorld.Core.Services; +using Shared.Core.ErrorHandling; +using Shared.Core.PackFiles; +using Shared.GameFormats.AnimationPack; +using Shared.Ui.Editors.TextEditor; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationFragmentConverter +{ + public static class Validator + { + public static ITextConverter.SaveError Validate(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, Animation xmlAnimation, string text, IPackFileService pfs, string filepath) + { + if (string.IsNullOrWhiteSpace(xmlAnimation.Skeleton)) + return new ITextConverter.SaveError() { ErrorLength = 0, ErrorLineNumber = 1, ErrorPosition = 0, Text = "Missing skeleton item on root" }; + + var lastIndex = 0; + + for (int i = 0; i < xmlAnimation.AnimationFragmentEntry.Count; i++) + { + var item = xmlAnimation.AnimationFragmentEntry[i]; + lastIndex = text.IndexOf(" AnimationFragmentEntry { get; set; } + [XmlAttribute(AttributeName = "skeleton")] + public string Skeleton { get; set; } + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/ValueConverterHelper.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/ValueConverterHelper.cs new file mode 100644 index 000000000..3a7c66a49 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/ValueConverterHelper.cs @@ -0,0 +1,51 @@ +using System.Collections; + +namespace Editors.AnimationFragmentEditor.AnimationPack.Converters +{ + public static class ValueConverterHelper + { + public static bool ValidateBoolArray(string value) + { + if (string.IsNullOrWhiteSpace(value)) + return false; + + var parts = value.Split(","); + if (parts.Length != 6) + return false; + + for (int i = 0; i < 6; i++) + { + var str = parts[i].Trim(); + if (bool.TryParse(str, out _) == false) + return false; + } + return true; + } + + public static string ConvertIntToBoolArray(int value) + { + var bitArray = new BitArray(new int[] { value }); + var bits = new bool[bitArray.Count]; + bitArray.CopyTo(bits, 0); + + string[] strArray = new string[6]; + for (int i = 0; i < 6; i++) + strArray[i] = bits[i].ToString(); + + return string.Join(", ", strArray); + } + + public static int CreateWeaponFlagInt(string strArray) + { + var values = strArray.Split(",").Select(x => bool.Parse(x)).ToArray(); + BitArray b = new BitArray(new int[] { 0 }); + for (int i = 0; i < 6; i++) + b[i] = values[i]; + + int[] array = new int[1]; + b.CopyTo(array, 0); + return array[0]; + } + + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs new file mode 100644 index 000000000..ab16b9e9a --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs @@ -0,0 +1,78 @@ +using System.IO; +using System.Windows; +using System.Xml; +using System.Xml.Serialization; +using Shared.ByteParsing; +using Shared.Core.ErrorHandling.Exceptions; +using Shared.Core.PackFiles; +using Shared.GameFormats.AnimationPack; +using Shared.Ui.Editors.TextEditor; + +namespace Editors.AnimationFragmentEditor.CampaignAnimBin +{ + class CampaignAnimBinToXmlConverter : ITextConverter + { + public string GetText(byte[] bytes) + { + try + { + var bin = CampaignAnimationBinLoader.Load(new ByteChunk(bytes)); + var xmlserializer = new XmlSerializer(typeof(CampaignAnimationBin)); + var stringWriter = new StringWriter(); + using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Indent = true })) + { + xmlserializer.Serialize(writer, bin); + var str = stringWriter.ToString(); + return str; + } + } + catch (Exception e) + { + MessageBox.Show("Unable to open file\n" + e.Message); + return ""; + } + } + + public byte[] ToBytes(string text, string filePath, IPackFileService pfs, out ITextConverter.SaveError error) + { + try + { + var xmlserializer = new XmlSerializer(typeof(CampaignAnimationBin)); + using var stringReader = new StringReader(text); + var reader = XmlReader.Create(stringReader); + + var errorHandler = new XmlSerializationErrorHandler(); + + var obj = xmlserializer.Deserialize(reader, errorHandler.EventHandler); + var typedObject = obj as CampaignAnimationBin; + var fileName = Path.GetFileNameWithoutExtension(filePath); + + var bytes = CampaignAnimationBinLoader.Write(typedObject, fileName); + + Validator.ValidateAnimationData(typedObject, pfs, filePath); + if (errorHandler.Error != null) + { + error = errorHandler.Error; + return null; + } + error = null; + return bytes; + + } + catch (Exception e) + { + var inner = ExceptionHelper.GetInnerMostException(e); + if (inner is XmlException xmlException) + error = new ITextConverter.SaveError() { Text = xmlException.Message, ErrorLineNumber = xmlException.LineNumber, ErrorPosition = xmlException.LinePosition, ErrorLength = 0 }; + else + error = new ITextConverter.SaveError() { Text = e.Message }; + + return null; + } + } + + public bool ShouldShowLineNumbers() => true; + public string GetSyntaxType() => "XML"; + public bool CanSaveOnError() => false; + } +} diff --git a/Editors/SimpleAnimationEditors/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/Validator.cs similarity index 80% rename from Editors/SimpleAnimationEditors/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/Validator.cs index 633c41473..b5e3d12d5 100644 --- a/Editors/SimpleAnimationEditors/CampaignAnimBin/CampaignAnimBinToXmlConverter.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/CampaignAnimBin/Validator.cs @@ -1,46 +1,14 @@ using System.IO; -using System.Windows; -using System.Xml; -using System.Xml.Serialization; using CommonControls.BaseDialogs.ErrorListDialog; -using Shared.ByteParsing; using Shared.Core.ErrorHandling; -using Shared.Core.ErrorHandling.Exceptions; using Shared.Core.PackFiles; using Shared.GameFormats.AnimationPack; -using Shared.Ui.Editors.TextEditor; -namespace CommonControls.Editors.CampaignAnimBin +namespace Editors.AnimationFragmentEditor.CampaignAnimBin { - class CampaignAnimBinToXmlConverter : ITextConverter + static class Validator { - public string GetText(byte[] bytes) - { - try - { - var bin = CampaignAnimationBinLoader.Load(new ByteChunk(bytes)); - var xmlserializer = new XmlSerializer(typeof(CampaignAnimationBin)); - var stringWriter = new StringWriter(); - using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Indent = true })) - { - xmlserializer.Serialize(writer, bin); - var str = stringWriter.ToString(); - return str; - } - } - catch (Exception e) - { - MessageBox.Show("Unable to open file\n" + e.Message); - return ""; - } - } - - void DisplayValidateDialog(ErrorList list) - { - if (list == null || !list.HasData) return; - ErrorListWindow.ShowDialog("Potential problems", list); - } - private bool ValidateAnimationData(CampaignAnimationBin campaignAnimation, IPackFileService pfs, string path) + public static bool ValidateAnimationData(CampaignAnimationBin campaignAnimation, IPackFileService pfs, string path) { var IsSkeletonExist = pfs.FindFile($"animations/skeletons/{campaignAnimation.SkeletonName}.anim") != null; @@ -272,46 +240,5 @@ private bool ValidateAnimationData(CampaignAnimationBin campaignAnimation, IPack return false; } - public byte[] ToBytes(string text, string filePath, IPackFileService pfs, out ITextConverter.SaveError error) - { - try - { - var xmlserializer = new XmlSerializer(typeof(CampaignAnimationBin)); - using var stringReader = new StringReader(text); - var reader = XmlReader.Create(stringReader); - - var errorHandler = new XmlSerializationErrorHandler(); - - var obj = xmlserializer.Deserialize(reader, errorHandler.EventHandler); - var typedObject = obj as CampaignAnimationBin; - var fileName = Path.GetFileNameWithoutExtension(filePath); - - var bytes = CampaignAnimationBinLoader.Write(typedObject, fileName); - - ValidateAnimationData(typedObject, pfs, filePath); - if (errorHandler.Error != null) - { - error = errorHandler.Error; - return null; - } - error = null; - return bytes; - - } - catch (Exception e) - { - var inner = ExceptionHelper.GetInnerMostException(e); - if (inner is XmlException xmlException) - error = new ITextConverter.SaveError() { Text = xmlException.Message, ErrorLineNumber = xmlException.LineNumber, ErrorPosition = xmlException.LinePosition, ErrorLength = 0 }; - else - error = new ITextConverter.SaveError() { Text = e.Message }; - - return null; - } - } - - public bool ShouldShowLineNumbers() => true; - public string GetSyntaxType() => "XML"; - public bool CanSaveOnError() => false; } } diff --git a/Editors/SimpleAnimationEditors/DependencyInjectionContainer.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DependencyInjectionContainer.cs similarity index 82% rename from Editors/SimpleAnimationEditors/DependencyInjectionContainer.cs rename to Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DependencyInjectionContainer.cs index 849c0d041..4a8ca87d4 100644 --- a/Editors/SimpleAnimationEditors/DependencyInjectionContainer.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DependencyInjectionContainer.cs @@ -1,14 +1,16 @@ using CommonControls.Editors.AnimationBatchExporter; -using CommonControls.Editors.AnimationFilePreviewEditor; using CommonControls.Editors.AnimationPack; -using CommonControls.Editors.CampaignAnimBin; using CommonControls.Editors.TextEditor; +using Editors.AnimationFragmentEditor.AnimationFilePreviewEditor; +using Editors.AnimationFragmentEditor.AnimationPack.Commands; +using Editors.AnimationFragmentEditor.CampaignAnimBin; using Microsoft.Extensions.DependencyInjection; using Shared.Core.DependencyInjection; +using Shared.Core.DevConfig; using Shared.Core.ToolCreation; using Shared.Ui.Editors.TextEditor; -namespace Editors.AnimationTextEditors +namespace Editors.AnimationFragmentEditor { public class DependencyInjectionContainer : DependencyContainer { @@ -18,10 +20,18 @@ public DependencyInjectionContainer() public override void Register(IServiceCollection services) { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + RegisterAnimPack(services); RegisterCampaignAnimBin(services); RegisterAnimFileViewer(services); RegisterBatchConverter(services); + + RegisterAllAsInterface(services, ServiceLifetime.Transient); } public override void RegisterTools(IEditorDatabase database) diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs new file mode 100644 index 000000000..7a36a52f2 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs @@ -0,0 +1,42 @@ +using Shared.Core.DevConfig; +using Shared.Core.Events; +using Shared.Core.PackFiles; +using Shared.Core.PackFiles.Utility; +using Shared.Core.Settings; +using Shared.Core.ToolCreation; +using Shared.EmbeddedResources; +using Shared.Ui.Events.UiCommands; + +namespace Editors.AnimationFragmentEditor.DevConfig +{ + internal class AnimPack_WH3 : IDeveloperConfiguration + { + private readonly IPackFileService _packFileService; + private readonly IPackFileContainerLoader _packFileContainerLoader; + private readonly IUiCommandFactory _uiCommandFactory; + + public AnimPack_WH3(IPackFileService packFileService, IPackFileContainerLoader packFileContainerLoader, IUiCommandFactory uiCommandFactory) + { + _packFileService = packFileService; + _packFileContainerLoader = packFileContainerLoader; + _uiCommandFactory = uiCommandFactory; + } + + public void OpenFileOnLoad() + { + var file = _packFileService.FindFile(@"animations\database\battle\bin\animation_tables.animpack"); + _uiCommandFactory.Create().Execute(file, EditorEnums.AnimationPack_Editor); + } + + public void OverrideSettings(ApplicationSettings currentSettings) + { + currentSettings.CurrentGame = GameTypeEnum.Warhammer3; + currentSettings.LoadCaPacksByDefault = true; + var packFile = ResourceLoader.GetDevelopmentDataFolder() + "\\Karl_and_celestialgeneral.pack"; + + //var container = _packFileContainerLoader.Load(packFile); + //container.IsCaPackFile = true; + //_packFileService.AddContainer(container); + } + } +} diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/Editors.AnimationFragmentEditor.csproj b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/Editors.AnimationFragmentEditor.csproj new file mode 100644 index 000000000..833166ad9 --- /dev/null +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/Editors.AnimationFragmentEditor.csproj @@ -0,0 +1,16 @@ + + + + net10.0-windows + true + enable + enable + + + + + + + + + diff --git a/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs b/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs index c7b5cbfef..6db88e7f1 100644 --- a/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs +++ b/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using System.Windows; -using Editors.AnimationTextEditors.AnimationPack.Converters; +using Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinWh3Converter; using Newtonsoft.Json; using Serilog; using Shared.Core.ErrorHandling; @@ -65,7 +65,7 @@ public void Create() var animPack = packFileContainer[0].FileList["animations\\database\\battle\\bin\\animation_tables.animpack"]; var animPackFile = AnimationPackSerializer.Load(animPack, _pfs); - var converter = new AnimationBinWh3FileToXmlConverter(null, _metaDataTagDeSerializer); + var converter = new AnimationBinWh3FileToXmlConverter(null, _metaDataTagDeSerializer, null); foreach (var animFile in animPackFile.Files) { if (animFile is AnimationBinWh3) diff --git a/Editors/Reports/Editors.Reports.csproj b/Editors/Reports/Editors.Reports.csproj index 2eb780511..91f5ae695 100644 --- a/Editors/Reports/Editors.Reports.csproj +++ b/Editors/Reports/Editors.Reports.csproj @@ -9,8 +9,8 @@ + - diff --git a/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/ITextConverter.cs b/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/ITextConverter.cs index 3facb6e46..b094dd96a 100644 --- a/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/ITextConverter.cs +++ b/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/ITextConverter.cs @@ -18,6 +18,20 @@ public class SaveError string GetSyntaxType(); bool CanSaveOnError(); byte[] ToBytes(string text, string filePath, IPackFileService pfs, out SaveError error); + + + public static ITextConverter.SaveError GenerateError(string wholeText, int lastIndex, string errorMessage) + { + var array = wholeText.ToCharArray(); + var lineCount = 0; + for (var strIndex = 0; strIndex < lastIndex; strIndex++) + { + if (array[strIndex] == '\n') + lineCount++; + } + + return new ITextConverter.SaveError() { ErrorLength = 40, ErrorPosition = 0, ErrorLineNumber = lineCount, Text = errorMessage }; + } } diff --git a/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/XmlToBinaryConverter.cs b/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/XmlToBinaryConverter.cs new file mode 100644 index 000000000..97b8fe15b --- /dev/null +++ b/Editors/Shared/Editors.Shared.Core/Editors/TextEditor/XmlToBinaryConverter.cs @@ -0,0 +1,82 @@ +using System.IO; +using System.Windows; +using System.Xml; +using System.Xml.Serialization; +using Shared.Core.ErrorHandling.Exceptions; +using Shared.Core.PackFiles; +using Shared.Ui.Editors.TextEditor; + +namespace Editors.Shared.Core.Editors.TextEditor +{ + public abstract class XmlToBinaryConverter : ITextConverter + where BinaryType : class + where XmlType : class + { + public bool ShouldShowLineNumbers() => true; + public string GetSyntaxType() => "XML"; + public bool CanSaveOnError() => false; + + protected abstract ITextConverter.SaveError Validate(XmlType type, string s, IPackFileService pfs, string filepath); + protected abstract XmlType ConvertBinaryToXml(byte[] bytes); + protected abstract byte[] ConvertXmlToBinary(XmlType xmlType, string path); + protected virtual string CleanUpXml(string xmlText) => xmlText; + + public string GetText(byte[] bytes) + { + try + { + var xmlFrg = ConvertBinaryToXml(bytes); + + var xmlserializer = new XmlSerializer(typeof(XmlType)); + using var stringWriter = new StringWriter(); + var ns = new XmlSerializerNamespaces(); + ns.Add("", ""); + using var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Indent = true, OmitXmlDeclaration = true }); + xmlserializer.Serialize(writer, xmlFrg, ns); + var str = stringWriter.ToString(); + str = CleanUpXml(str); + return str; + } + catch (Exception e) + { + MessageBox.Show("Unable to open file\n" + e.Message); + return ""; + } + } + + public byte[] ToBytes(string text, string filePath, IPackFileService pfs, out ITextConverter.SaveError error) + { + var xmlserializer = new XmlSerializer(typeof(XmlType)); + using var sr = new StringReader(text); + using var reader = XmlReader.Create(sr); + + try + { + var errorHandler = new XmlSerializationErrorHandler(); + var obj = xmlserializer.Deserialize(reader, errorHandler.EventHandler) as XmlType; + + if (errorHandler.Error != null) + { + error = errorHandler.Error; + return null; + } + + error = Validate(obj, text, pfs, filePath); + if (error != null) + return null; + + return ConvertXmlToBinary(obj, filePath); + } + catch (Exception e) + { + var inner = ExceptionHelper.GetInnerMostException(e); + if (inner is XmlException xmlException) + error = new ITextConverter.SaveError() { Text = xmlException.Message, ErrorLineNumber = xmlException.LineNumber, ErrorPosition = xmlException.LinePosition, ErrorLength = 0 }; + else + throw; + + return null; + } + } + } +} diff --git a/Editors/Shared/Editors.Shared.Core/Services/AnimPackUpdaterService.cs b/Editors/Shared/Editors.Shared.Core/Services/AnimPackUpdaterService.cs index 739b651fc..080e7c9d5 100644 --- a/Editors/Shared/Editors.Shared.Core/Services/AnimPackUpdaterService.cs +++ b/Editors/Shared/Editors.Shared.Core/Services/AnimPackUpdaterService.cs @@ -43,7 +43,7 @@ public void Process(GameTypeEnum existingPackVersion = GameTypeEnum.Warhammer2, foreach (var animPack in animPacks) { - var outputWh3AnimPack = new AnimationPackFile("Placeholder"); + var outputWh3AnimPack = new AnimationPackFileDatabase("Placeholder"); var unknownFilesCount = animPack.Files.Count(x => x is IMatchedCombatBin || x is UnknownAnimFile); if (unknownFilesCount != 0) diff --git a/Editors/SimpleAnimationEditors/AnimationPack/AnimPackViewModel.cs b/Editors/SimpleAnimationEditors/AnimationPack/AnimPackViewModel.cs deleted file mode 100644 index 91978d1d5..000000000 --- a/Editors/SimpleAnimationEditors/AnimationPack/AnimPackViewModel.cs +++ /dev/null @@ -1,341 +0,0 @@ -using System.IO; -using System.Text; -using System.Windows; -using System.Windows.Input; -using CommonControls.BaseDialogs; -using CommonControls.Editors.AnimationPack.Converters; -using CommunityToolkit.Mvvm.Input; -using Editors.AnimationTextEditors.AnimationPack.Converters; -using GameWorld.Core.Services; -using Shared.Core.Misc; -using Shared.Core.PackFiles; -using Shared.Core.PackFiles.Models; -using Shared.Core.Services; -using Shared.Core.Settings; -using Shared.Core.ToolCreation; -using Shared.GameFormats.AnimationMeta.Parsing; -using Shared.GameFormats.AnimationPack; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3; -using Shared.Ui.Common; -using Shared.Ui.Editors.TextEditor; - -namespace CommonControls.Editors.AnimationPack -{ - public class AnimPackViewModel : NotifyPropertyChangedImpl, IEditorInterface, ISaveableEditor, IFileEditor - { - private readonly IPackFileService _pfs; - private readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper; - private ITextConverter _activeConverter; - private readonly ApplicationSettingsService _appSettings; - private readonly IFileSaveService _packFileSaveService; - private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; - - public string DisplayName { get; set; } = "Not set"; - - PackFile _packFile; - - public FilterCollection AnimationPackItems { get; set; } - - SimpleTextEditorViewModel _selectedItemViewModel; - public SimpleTextEditorViewModel SelectedItemViewModel { get => _selectedItemViewModel; set => SetAndNotify(ref _selectedItemViewModel, value); } - - - public ICommand RemoveCommand { get; set; } - public ICommand RenameCommand { get; set; } - public ICommand CopyFullPathCommand { get; set; } - - public AnimPackViewModel(IPackFileService pfs, ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, ApplicationSettingsService appSettings, IFileSaveService packFileSaveService, MetaDataTagDeSerializer metaDataTagDeSerializer) - { - _pfs = pfs; - _skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper; - _appSettings = appSettings; - _packFileSaveService = packFileSaveService; - _metaDataTagDeSerializer = metaDataTagDeSerializer; - - AnimationPackItems = new FilterCollection(new List(), ItemSelected, BeforeItemSelected) - { - SearchFilter = (value, rx) => { return rx.Match(value.FileName).Success; } - }; - - RemoveCommand = new RelayCommand(Remove); - RenameCommand = new RelayCommand(Rename); - CopyFullPathCommand = new RelayCommand(CopyFullPath); - } - - private void Rename() - { - var animFile = AnimationPackItems.PossibleValues.FirstOrDefault(file => file == AnimationPackItems.SelectedItem); - if (animFile == null) - return; - - var window = new TextInputWindow("Rename Anim File", animFile.FileName); - if (window.ShowDialog() == true) - animFile.FileName = window.TextValue; - - // way to refresh the view - AnimationPackItems.RefreshFilter(); - } - - private void Remove() - { - AnimationPackItems.PossibleValues.Remove(AnimationPackItems.SelectedItem); - - // way to refresh the view - AnimationPackItems.RefreshFilter(); - } - - private void CopyFullPath() - { - Clipboard.SetText(AnimationPackItems.SelectedItem.FileName); - } - - public void Load() - { - var animPack = AnimationPackSerializer.Load(_packFile, _pfs); - var itemNames = animPack.Files.ToList(); - AnimationPackItems.UpdatePossibleValues(itemNames); - DisplayName = animPack.FileName; - } - - string? GetAnimSetFileName() - { - var window = new TextInputWindow("Fragment name", ""); - if (window.ShowDialog() == true) - { - var filename = SaveUtility.EnsureEnding(window.TextValue, ".frg"); - return filename; - } - - return null; - } - - public void CreateEmptyWarhammer3AnimSetFile() - { - var fileName = GetAnimSetFileName(); - if (fileName == null) - return; - - var animSet = AnimationPackSampleDataCreator.CreateExampleWarhammer3AnimSet(fileName); - AnimationPackItems.PossibleValues.Add(animSet); - AnimationPackItems.UpdatePossibleValues(AnimationPackItems.PossibleValues); - } - - public void SetSelectedFile(string path) - { - AnimationPackItems.SelectedItem = AnimationPackItems.PossibleValues.FirstOrDefault(x => x.FileName == path); - } - - bool BeforeItemSelected(IAnimationPackFile item) - { - if (SelectedItemViewModel != null && SelectedItemViewModel.HasUnsavedChanges()) - { - if (MessageBox.Show("Editor has unsaved changes that will be lost.\nContinue?", "", MessageBoxButton.YesNo) == MessageBoxResult.No) - return false; - } - - return true; - } - - void ItemSelected(IAnimationPackFile seletedFile) - { - _activeConverter = null; - if (seletedFile is AnimationFragmentFile typedFragment) - _activeConverter = new AnimationFragmentFileToXmlConverter(_skeletonAnimationLookUpHelper, _appSettings.CurrentSettings.CurrentGame); - else if (seletedFile is Shared.GameFormats.AnimationPack.AnimPackFileTypes.AnimationBin typedBin) - _activeConverter = new AnimationBinFileToXmlConverter(); - else if (seletedFile is AnimationBinWh3 wh3Bin) - _activeConverter = new AnimationBinWh3FileToXmlConverter(_skeletonAnimationLookUpHelper, _metaDataTagDeSerializer); - - if (seletedFile == null || _activeConverter == null || seletedFile.IsUnknownFile) - { - SelectedItemViewModel = new SimpleTextEditorViewModel(); - SelectedItemViewModel.SaveCommand = null; - SelectedItemViewModel.TextEditor?.ShowLineNumbers(true); - SelectedItemViewModel.TextEditor?.SetSyntaxHighlighting("XML"); - SelectedItemViewModel.Text = ""; - SelectedItemViewModel.ResetChangeLog(); - } - else - { - SelectedItemViewModel = new SimpleTextEditorViewModel(); - SelectedItemViewModel.SaveCommand = new RelayCommand(() => SaveActiveFile()); - SelectedItemViewModel.TextEditor?.ShowLineNumbers(true); - SelectedItemViewModel.TextEditor?.SetSyntaxHighlighting(_activeConverter.GetSyntaxType()); - SelectedItemViewModel.Text = _activeConverter.GetText(seletedFile.ToByteArray()); - SelectedItemViewModel.ResetChangeLog(); - } - - } - public void Close() { } - public bool HasUnsavedChanges { get; set; } - - public PackFile CurrentFile => _packFile; - - public bool SaveActiveFile() - { - if (_packFile == null) - { - MessageBox.Show("Can not save in this mode - Open the file normally"); - return false; - } - var converter = (AnimationBinWh3FileToXmlConverter)_activeConverter; - converter.AnimPackToValidate = _packFile; - - var fileName = AnimationPackItems.SelectedItem.FileName; - var bytes = _activeConverter.ToBytes(SelectedItemViewModel.Text, fileName, _pfs, out var error); - - if (bytes == null || error != null) - { - SelectedItemViewModel.TextEditor.HightLightText(error.ErrorLineNumber, error.ErrorPosition, error.ErrorLength); - MessageBox.Show(error.Text, "Error"); - return false; - } - - var seletedFile = AnimationPackItems.SelectedItem; - seletedFile.CreateFromBytes(bytes); - seletedFile.IsChanged.Value = true; - - SelectedItemViewModel.ResetChangeLog(); - HasUnsavedChanges = true; - - - return true; - } - - - public bool Save() - { - if (_packFile == null) - { - MessageBox.Show("Can not save in this mode - Open the file normally"); - return false; - } - - if (SelectedItemViewModel != null && SelectedItemViewModel.HasUnsavedChanges()) - { - if (MessageBox.Show("Editor has unsaved changes.\nSave anyway?", "", MessageBoxButton.YesNo) == MessageBoxResult.No) - return false; - } - - var newAnimPack = new AnimationPackFile(_pfs.GetFullPath(_packFile)); - - foreach (var file in AnimationPackItems.PossibleValues) - newAnimPack.AddFile(file); - - var savePath = _pfs.GetFullPath(_packFile); - - var result = _packFileSaveService.Save(savePath, AnimationPackSerializer.ConvertToBytes(newAnimPack), false); - if (result != null) - { - HasUnsavedChanges = false; - foreach (var file in AnimationPackItems.PossibleValues) - file.IsChanged.Value = false; - } - - return true; - } - - public bool ViewSelectedAsTable() - { - throw new System.Exception("TODO"); - //var selectedItem = AnimationPackItems.SelectedItem; - //if (selectedItem == null) - // return false; - // - //if (_animPack.GetFileType(selectedItem) == AnimationPackFile.AnimationPackFileType.Bin) - //{ - // var data = new ObservableCollection(); - // - // var bin = _animPack.GetAnimBin(selectedItem); - // foreach (var item in bin.AnimationTableEntries) - // data.Add(item); - // - // AnimTablePreviewWindow window = new AnimTablePreviewWindow() - // { - // DataContext = data - // }; - // - // window.ShowDialog(); - //} - //else - //{ - // var data = new ObservableCollection(); - // - // var frag = _animPack.GetAnimFragment(selectedItem); - // foreach (var item in frag.Fragments) - // data.Add(item); - // - // AnimTablePreviewWindow window = new AnimTablePreviewWindow() - // { - // DataContext = data - // }; - // - // window.ShowDialog(); - //} - // - //return true; - } - - public void ExportAnimationSlotsWh3Action() - { - var slots = AnimationSlotTypeHelperWh3.Values.Select(x => x.Id + "\t\t" + x.Value).ToList(); - SaveAnimationSlotsToFile(slots); - } - - public void ExportAnimationSlotsWh2Action() - { - var slots = DefaultAnimationSlotTypeHelper.Values.Select(x => x.Id + "\t\t" + x.Value).ToList(); - SaveAnimationSlotsToFile(slots); - } - - void SaveAnimationSlotsToFile(List slots) - { - using var dlg = new System.Windows.Forms.SaveFileDialog(); - dlg.Filter = "Text files(*.txt) | *.txt | All files(*.*) | *.* "; - if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) - return; - string path = dlg.FileName; - - StringBuilder sb = new StringBuilder(); - foreach (var slot in slots) - sb.AppendLine(slot); - - File.WriteAllText(path, sb.ToString()); - } - - //public static void ShowPreviewWinodow(PackFile animationPackFile, PackFileService pfs, SkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, string selectedFileName, ApplicationSettingsService applicationSettings) - //{ - // if (animationPackFile == null) - // { - // MessageBox.Show("Unable to resolve packfile"); - // return; - // } - // - // var controller = new AnimPackViewModel(pfs, skeletonAnimationLookUpHelper, applicationSettings); - // controller._packFile = animationPackFile; - // controller.Load(); - // - // var containingWindow = new Window(); - // containingWindow.Title = animationPackFile.Name; - // - // - // containingWindow.DataContext = controller; - // containingWindow.Content = new AnimationPackView(); - // - // containingWindow.Width = 1200; - // containingWindow.Height = 1100; - // - // - // containingWindow.Loaded += (sender, e) => controller.SetSelectedFile(selectedFileName); - // - // containingWindow.ShowDialog(); - //} - - public void LoadFile(PackFile file) - { - _packFile = file; - Load(); - } - } -} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackSampleDataCreator.cs b/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackSampleDataCreator.cs deleted file mode 100644 index 0afa5e2ba..000000000 --- a/Editors/SimpleAnimationEditors/AnimationPack/AnimationPackSampleDataCreator.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Windows; -using CommonControls.BaseDialogs; -using Shared.Core.Misc; -using Shared.Core.PackFiles; -using Shared.Core.PackFiles.Models; -using Shared.Core.Services; -using Shared.GameFormats.AnimationPack; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3; - -namespace CommonControls.Editors.AnimationPack -{ - public class AnimationPackSampleDataCreator - { - public static PackFile? CreateAnimationDbWarhammer3(IFileSaveService saveHelper, IPackFileService pfs) - { - TextInputWindow window = new TextInputWindow("New AnimPack name", ""); - if (window.ShowDialog() == true) - return CreateAnimationDbWarhammer3(saveHelper, pfs, window.TextValue); - return null; - } - - public static string GenerateWh3AnimPackName(string name) - { - var fileName = SaveUtility.EnsureEnding(name, ".animpack"); - var filePath = @"animations/database/battle/bin/" + fileName; - return filePath; - } - - public static PackFile? CreateAnimationDbWarhammer3(IFileSaveService saveHelper, IPackFileService pfs, string name) - { - var filePath = GenerateWh3AnimPackName(name); - - if (!SaveUtility.IsFilenameUnique(pfs, filePath)) - { - MessageBox.Show("Filename is not unique"); - return null; - } - - var animPack = new AnimationPackFile("Placeholder"); - return saveHelper.Save(filePath, AnimationPackSerializer.ConvertToBytes(animPack), false); - } - - public static void CreateAnimationDb3k(IPackFileService pfs, IFileSaveService saveHelper) - { - TextInputWindow window = new TextInputWindow("New AnimPack name", ""); - if (window.ShowDialog() == true) - { - var fileName = SaveUtility.EnsureEnding(window.TextValue, ".animpack"); - var filePath = @"animations/database/battle/bin/" + fileName; - if (!SaveUtility.IsFilenameUnique(pfs, filePath)) - { - MessageBox.Show("Filename is not unique"); - return; - } - - // Create dummy data - var animPack = new AnimationPackFile("Placeholder"); - saveHelper.Save(filePath, AnimationPackSerializer.ConvertToBytes(animPack), false); - } - } - - - public static IAnimationPackFile CreateExampleWarhammer3AnimSet(string binName) - { - var filename = SaveUtility.EnsureEnding(binName, ".bin"); - var filePath = @"animations/database/battle/bin/" + filename; - var outputFile = new AnimationBinWh3(filePath) - { - TableVersion = 4, - TableSubVersion = 3, - Name = binName, - Unknown = "", - MountBin = "", - SkeletonName = "humanoid01", - LocomotionGraph = "animations/locomotion_graphs/entity_locomotion_graph.xml", - UnknownValue1 = 0, - }; - - outputFile.AnimationTableEntries.Add(new Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry() - { - AnimationId = 1, // STAND - BlendIn = 0.5f, - SelectionWeight = 1, - WeaponBools = 1, - Unk = false, - - AnimationRefs = new List() - { - new Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry.AnimationRef() - { - AnimationFile = @"animations/battle/humanoid01/sword_and_shield/stand/hu1_sws_stand_01.anim", - AnimationMetaFile = @"", - AnimationSoundMetaFile = @"" , - }, - } - }); - - outputFile.AnimationTableEntries.Add(new Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry() - { - AnimationId = 453,// Attack_1 - BlendIn = 0.3f, - SelectionWeight = 1, - WeaponBools = 1, - Unk = false, - - AnimationRefs = new List() - { - new Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry.AnimationRef() - { - AnimationFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.anim", - AnimationMetaFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.meta", - AnimationSoundMetaFile = @"animations/audio/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_01.{27tsfy}.snd.meta", - }, - new Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3.AnimationBinEntry.AnimationRef() - { - AnimationFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.anim", - AnimationMetaFile = @"animations/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.anm.meta", - AnimationSoundMetaFile = @"animations/audio/battle/humanoid01/sword_and_shield/attacks/hu1_sws_attack_02.{1o2asvr}.snd.meta", - } - } - }); - - return outputFile; - } - } -} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinFileToXmlConverter.cs b/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinFileToXmlConverter.cs deleted file mode 100644 index 83c9c782d..000000000 --- a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationBinFileToXmlConverter.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System.Xml; -using System.Xml.Serialization; -using Shared.Core.PackFiles; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes; -using Shared.Ui.Editors.TextEditor; - -namespace CommonControls.Editors.AnimationPack.Converters -{ - public class AnimationBinFileToXmlConverter : BaseAnimConverter - { - protected override string CleanUpXml(string xmlText) - { - xmlText = xmlText.Replace("", "\n"); - xmlText = xmlText.Replace("", "\n"); - return xmlText; - } - - protected override Bin ConvertBytesToXmlClass(byte[] bytes) - { - Shared.GameFormats.AnimationPack.AnimPackFileTypes.AnimationBin binFile = new Shared.GameFormats.AnimationPack.AnimPackFileTypes.AnimationBin("", bytes); - var outputBin = new Bin(); - outputBin.BinEntry = new List(); - - foreach (var item in binFile.AnimationTableEntries) - { - var entry = new BinEntry(); - entry.Name = item.Name; - entry.Fragments = string.Join(", ", item.FragmentReferences.Select(x => x.Name)); - entry.Skeleton = new Skeleton() { Value = item.SkeletonName }; - entry.MountSkeleton = new MountSkeleton() { Value = item.MountName }; - entry.Unknown = new Unknown() { Value = item.Unknown }; - outputBin.BinEntry.Add(entry); - } - - return outputBin; - } - - protected override byte[] ConvertToAnimClassBytes(Bin bin, string fileName) - { - var output = new Shared.GameFormats.AnimationPack.AnimPackFileTypes.AnimationBin(fileName); - foreach (var item in bin.BinEntry) - { - var entry = new AnimationBinEntry(item.Name, item.Skeleton.Value, item.MountSkeleton.Value) - { - Unknown = item.Unknown.Value - }; - - var refs = item.Fragments.Split(","); - foreach (var refInstance in refs) - { - var str = refInstance.Trim(); - if (string.IsNullOrEmpty(str) == false) - entry.FragmentReferences.Add(new AnimationBinEntry.FragmentReference() { Name = str, Unknown = 0 }); - } - - output.AnimationTableEntries.Add(entry); - } - return output.ToByteArray(); - } - - - protected override ITextConverter.SaveError Validate(Bin type, string s, IPackFileService pfs, string filepath) - { - return null; - } - - [XmlRoot(ElementName = "Skeleton")] - public class Skeleton - { - [XmlAttribute(AttributeName = "value")] - public string Value { get; set; } - } - - [XmlRoot(ElementName = "MountSkeleton")] - public class MountSkeleton - { - [XmlAttribute(AttributeName = "value")] - public string Value { get; set; } - } - - [XmlRoot(ElementName = "Unknown")] - public class Unknown - { - [XmlAttribute(AttributeName = "value")] - public short Value { get; set; } - } - - [XmlRoot(ElementName = "BinEntry")] - public class BinEntry - { - [XmlElement(ElementName = "Skeleton")] - public Skeleton Skeleton { get; set; } - [XmlElement(ElementName = "MountSkeleton")] - public MountSkeleton MountSkeleton { get; set; } - [XmlElement(ElementName = "Fragments")] - public string Fragments { get; set; } - [XmlElement(ElementName = "Unknown")] - public Unknown Unknown { get; set; } - [XmlAttribute(AttributeName = "name")] - public string Name { get; set; } - } - - [XmlRoot(ElementName = "Bin")] - public class Bin - { - [XmlElement(ElementName = "BinEntry")] - public List BinEntry { get; set; } - } - } -} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationFragmentFileToXmlConverter.cs b/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationFragmentFileToXmlConverter.cs deleted file mode 100644 index 6cf0e4599..000000000 --- a/Editors/SimpleAnimationEditors/AnimationPack/Converters/AnimationFragmentFileToXmlConverter.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System.Xml; -using System.Xml.Serialization; -using CommonControls.BaseDialogs.ErrorListDialog; -using GameWorld.Core.Services; -using Shared.Core.ErrorHandling; -using Shared.Core.PackFiles; -using Shared.Core.Settings; -using Shared.GameFormats.AnimationPack; -using Shared.GameFormats.AnimationPack.AnimPackFileTypes; -using Shared.GameFormats.DB; -using Shared.Ui.Editors.TextEditor; - -namespace CommonControls.Editors.AnimationPack.Converters -{ - - public class AnimationFragmentFileToXmlConverter - : BaseAnimConverter - { - private ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper; - GameTypeEnum _preferedGame; - - public AnimationFragmentFileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, GameTypeEnum preferedGame) - { - _skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper; - _preferedGame = preferedGame; - } - - protected override ITextConverter.SaveError Validate(Animation xmlAnimation, string text, IPackFileService pfs, string filepath) - { - if (string.IsNullOrWhiteSpace(xmlAnimation.Skeleton)) - return new ITextConverter.SaveError() { ErrorLength = 0, ErrorLineNumber = 1, ErrorPosition = 0, Text = "Missing skeleton item on root" }; - - var lastIndex = 0; - - for (int i = 0; i < xmlAnimation.AnimationFragmentEntry.Count; i++) - { - var item = xmlAnimation.AnimationFragmentEntry[i]; - lastIndex = text.IndexOf("(); - outputBin.Skeleton = fragmentFile.Skeletons.Values.FirstOrDefault(); - - foreach (var item in fragmentFile.Fragments) - { - var entry = new AnimationEntry(); - entry.Slot = item.Slot.Value; - entry.File = new ValueItem() { Value = item.AnimationFile }; - entry.Meta = new ValueItem() { Value = item.MetaDataFile }; - entry.Sound = new ValueItem() { Value = item.SoundMetaDataFile }; - entry.BlendInTime = new BlendInTime() { Value = item.BlendInTime }; - entry.SelectionWeight = new SelectionWeight() { Value = item.SelectionWeight }; - entry.Unknown = item.Unknown0; - entry.WeaponBone = ConvertIntToBoolArray(item.WeaponBone); - - outputBin.AnimationFragmentEntry.Add(entry); - } - - return outputBin; - } - - protected override string CleanUpXml(string xmlText) => xmlText.Replace("", "\n"); - - protected override byte[] ConvertToAnimClassBytes(Animation animation, string fileName) - { - var output = new AnimationFragmentFile(fileName, null, _preferedGame); - output.Skeletons = new StringArrayTable(animation.Skeleton, animation.Skeleton); - - foreach (var item in animation.AnimationFragmentEntry) - { - var entry = new AnimationSetEntry() - { - AnimationFile = item.File.Value, - MetaDataFile = item.Meta.Value, - SoundMetaDataFile = item.Sound.Value, - Comment = "", - BlendInTime = item.BlendInTime.Value, - Ignore = false, - SelectionWeight = item.SelectionWeight.Value, - Slot = _preferedGame == GameTypeEnum.Troy ? AnimationSlotTypeHelperTroy.GetfromValue(item.Slot) : DefaultAnimationSlotTypeHelper.GetfromValue(item.Slot), - Skeleton = animation.Skeleton, - Unknown0 = item.Unknown, - }; - - var unknown1Flags = item.WeaponBone.Split(","); - for (int i = 0; i < 6; i++) - entry.SetWeaponBoneFlags(i, bool.Parse(unknown1Flags[i])); - - output.Fragments.Add(entry); - } - - return output.ToByteArray(); - } - - - [XmlRoot(ElementName = "BlendInTime")] - public class BlendInTime - { - [XmlAttribute(AttributeName = "Value")] - public float Value { get; set; } - } - - [XmlRoot(ElementName = "SelectionWeight")] - public class SelectionWeight - { - [XmlAttribute(AttributeName = "Value")] - public float Value { get; set; } - } - - public class ValueItem - { - [XmlAttribute(AttributeName = "Value")] - public string Value { get; set; } - } - - [XmlRoot(ElementName = "AnimationEntry")] - public class AnimationEntry - { - [XmlElement(ElementName = "File")] - public ValueItem File { get; set; } - - [XmlElement(ElementName = "Meta")] - public ValueItem Meta { get; set; } - - [XmlElement(ElementName = "Sound")] - public ValueItem Sound { get; set; } - - - [XmlElement(ElementName = "BlendInTime")] - public BlendInTime BlendInTime { get; set; } - [XmlElement(ElementName = "SelectionWeight")] - public SelectionWeight SelectionWeight { get; set; } - - [XmlElement(ElementName = "Unknown")] - public int Unknown { get; set; } - - [XmlElement(ElementName = "WeaponBone")] - public string WeaponBone { get; set; } - - [XmlAttribute(AttributeName = "Slot")] - public string Slot { get; set; } - } - - [XmlRoot(ElementName = "Animation")] - public class Animation - { - [XmlElement(ElementName = "AnimationFragmentEntry")] - public List AnimationFragmentEntry { get; set; } - [XmlAttribute(AttributeName = "skeleton")] - public string Skeleton { get; set; } - } - } -} diff --git a/Editors/SimpleAnimationEditors/AnimationPack/Converters/BaseAnimConverter.cs b/Editors/SimpleAnimationEditors/AnimationPack/Converters/BaseAnimConverter.cs deleted file mode 100644 index 6ad64974c..000000000 --- a/Editors/SimpleAnimationEditors/AnimationPack/Converters/BaseAnimConverter.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System.Collections; -using System.IO; -using System.Windows; -using System.Xml; -using System.Xml.Serialization; -using Shared.Core.ErrorHandling.Exceptions; -using Shared.Core.PackFiles; -using Shared.Core.PackFiles.Models; -using Shared.Ui.Editors.TextEditor; - -namespace CommonControls.Editors.AnimationPack.Converters -{ - public abstract class BaseAnimConverter : ITextConverter - where AnimType : class - where XmlType : class - { - public bool ShouldShowLineNumbers() => true; - public string GetSyntaxType() => "XML"; - public bool CanSaveOnError() => false; - - public PackFile AnimPackToValidate = null; - - protected abstract ITextConverter.SaveError Validate(XmlType type, string s, IPackFileService pfs, string filepath); - protected abstract XmlType ConvertBytesToXmlClass(byte[] bytes); - protected abstract byte[] ConvertToAnimClassBytes(XmlType xmlType, string path); - protected virtual string CleanUpXml(string xmlText) => xmlText; - - - public string GetText(byte[] bytes) - { - try - { - var xmlFrg = ConvertBytesToXmlClass(bytes); - - var xmlserializer = new XmlSerializer(typeof(XmlType)); - var stringWriter = new StringWriter(); - XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); - ns.Add("", ""); - using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Indent = true, OmitXmlDeclaration = true })) - { - xmlserializer.Serialize(writer, xmlFrg, ns); - var str = stringWriter.ToString(); - str = CleanUpXml(str); - return str; - } - } - catch (Exception e) - { - MessageBox.Show("Unable to open file\n" + e.Message); - return ""; - } - } - - public byte[] ToBytes(string text, string filePath, IPackFileService pfs, out ITextConverter.SaveError error) - { - var xmlserializer = new XmlSerializer(typeof(XmlType)); - using var sr = new StringReader(text); - using var reader = XmlReader.Create(sr); - - try - { - var errorHandler = new XmlSerializationErrorHandler(); - var obj = xmlserializer.Deserialize(reader, errorHandler.EventHandler) as XmlType; - - if (errorHandler.Error != null) - { - error = errorHandler.Error; - return null; - } - - error = Validate(obj, text, pfs, filePath); - if (error != null) - return null; - - return ConvertToAnimClassBytes(obj, filePath); - } - catch (Exception e) - { - var inner = ExceptionHelper.GetInnerMostException(e); - if (inner is XmlException xmlException) - error = new ITextConverter.SaveError() { Text = xmlException.Message, ErrorLineNumber = xmlException.LineNumber, ErrorPosition = xmlException.LinePosition, ErrorLength = 0 }; - else - throw; - - return null; - } - } - - protected ITextConverter.SaveError GenerateError(string wholeText, int lastIndex, string errorMessage) - { - var array = wholeText.ToCharArray(); - var lineCount = 0; - for (int strIndex = 0; strIndex < lastIndex; strIndex++) - { - if (array[strIndex] == '\n') - lineCount++; - } - - return new ITextConverter.SaveError() { ErrorLength = 40, ErrorPosition = 0, ErrorLineNumber = lineCount, Text = errorMessage }; - } - - protected bool ValidateBoolArray(string value) - { - if (string.IsNullOrWhiteSpace(value)) - return false; - - var parts = value.Split(","); - if (parts.Length != 6) - return false; - - for (int i = 0; i < 6; i++) - { - var str = parts[i].Trim(); - if (bool.TryParse(str, out _) == false) - return false; - } - return true; - } - - protected string ConvertIntToBoolArray(int value) - { - var bitArray = new BitArray(new int[] { value }); - var bits = new bool[bitArray.Count]; - bitArray.CopyTo(bits, 0); - - string[] strArray = new string[6]; - for (int i = 0; i < 6; i++) - strArray[i] = bits[i].ToString(); - - return string.Join(", ", strArray); - } - - protected int CreateWeaponFlagInt(string strArray) - { - var values = strArray.Split(",").Select(x => bool.Parse(x)).ToArray(); - BitArray b = new BitArray(new int[] { 0 }); - for (int i = 0; i < 6; i++) - b[i] = values[i]; - - int[] array = new int[1]; - b.CopyTo(array, 0); - return array[0]; - } - } -} diff --git a/Editors/SimpleAnimationEditors/Editors.AnimationTextEditors.csproj b/Editors/SimpleAnimationEditors/Editors.AnimationTextEditors.csproj deleted file mode 100644 index ce3f8f36a..000000000 --- a/Editors/SimpleAnimationEditors/Editors.AnimationTextEditors.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - net10.0-windows - true - enable - enable - - - - - - - - - diff --git a/GameWorld/View3D/Commands/ICommand.cs b/GameWorld/View3D/Commands/ICommand.cs index 4b6c1cb12..e5accb5a0 100644 --- a/GameWorld/View3D/Commands/ICommand.cs +++ b/GameWorld/View3D/Commands/ICommand.cs @@ -1,6 +1,5 @@ using GameWorld.Core.Services; using Microsoft.Extensions.DependencyInjection; -using System; namespace GameWorld.Core.Commands { diff --git a/GameWorld/View3D/Services/CommandExecutor.cs b/GameWorld/View3D/Services/CommandExecutor.cs index 055a92b49..c9b34123b 100644 --- a/GameWorld/View3D/Services/CommandExecutor.cs +++ b/GameWorld/View3D/Services/CommandExecutor.cs @@ -2,20 +2,18 @@ using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.Events; -using System; -using System.Collections.Generic; namespace GameWorld.Core.Services { public class CommandStackChangedEvent { - public string HintText { get; internal set; } + public string HintText { get; internal set; } = ""; public bool IsMutation { get; internal set; } } public class CommandStackUndoEvent { - public string HintText { get; set; } + public string HintText { get; set; } = ""; } public class CommandExecutor diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationBin.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationBin.cs index 84251790a..e1a949e30 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationBin.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationBin.cs @@ -6,7 +6,7 @@ namespace Shared.GameFormats.AnimationPack.AnimPackFileTypes public class AnimationBin : IAnimationPackFile { public string FileName { get; set; } - public AnimationPackFile Parent { get; set; } + public AnimationPackFileDatabase Parent { get; set; } public bool IsUnknownFile { get; set; } = false; public NotifyAttr IsChanged { get; set; } = new NotifyAttr(false); diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationFragmentFile.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationFragmentFile.cs index db389762c..94665b1c2 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationFragmentFile.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/AnimationFragmentFile.cs @@ -13,7 +13,7 @@ public class AnimationFragmentFile : IAnimationPackFile GameTypeEnum _preferedGame = GameTypeEnum.Warhammer2; public string FileName { get; set; } - public AnimationPackFile Parent { get; set; } + public AnimationPackFileDatabase Parent { get; set; } public bool IsUnknownFile { get; set; } = false; public NotifyAttr IsChanged { get; set; } = new NotifyAttr(false); diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/IAnimationPackFile.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/IAnimationPackFile.cs index 6b8b7d472..66a5e217d 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/IAnimationPackFile.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/IAnimationPackFile.cs @@ -4,7 +4,7 @@ namespace Shared.GameFormats.AnimationPack.AnimPackFileTypes { public interface IAnimationPackFile { - AnimationPackFile Parent { get; set; } + AnimationPackFileDatabase Parent { get; set; } string FileName { get; set; } public bool IsUnknownFile { get; set; } diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/MatchedAnimFile.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/MatchedAnimFile.cs index 607e81b33..fe288a56f 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/MatchedAnimFile.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/MatchedAnimFile.cs @@ -6,7 +6,7 @@ namespace Shared.GameFormats.AnimationPack.AnimPackFileTypes { public class MatchedAnimFile : IAnimationPackFile { - public AnimationPackFile Parent { get; set; } + public AnimationPackFileDatabase Parent { get; set; } public string FileName { get; set; } public bool IsUnknownFile { get; set; } = false; public NotifyAttr IsChanged { get; set; } = new NotifyAttr(false); diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/UnknownAnimFile.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/UnknownAnimFile.cs index b7b947221..20a01a177 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/UnknownAnimFile.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/UnknownAnimFile.cs @@ -4,7 +4,7 @@ namespace Shared.GameFormats.AnimationPack.AnimPackFileTypes { public class UnknownAnimFile : IAnimationPackFile { - public AnimationPackFile Parent { get; set; } + public AnimationPackFileDatabase Parent { get; set; } public string FileName { get; set; } public bool IsUnknownFile { get; set; } = true; public NotifyAttr IsChanged { get; set; } = new NotifyAttr(false); diff --git a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/Wh3/AnimationBinWh3.cs b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/Wh3/AnimationBinWh3.cs index 308f994ea..8befe5354 100644 --- a/Shared/GameFiles/AnimationPack/AnimPackFileTypes/Wh3/AnimationBinWh3.cs +++ b/Shared/GameFiles/AnimationPack/AnimPackFileTypes/Wh3/AnimationBinWh3.cs @@ -6,7 +6,7 @@ namespace Shared.GameFormats.AnimationPack.AnimPackFileTypes.Wh3 public class AnimationBinWh3 : IAnimationPackFile, IAnimationBinGenericFormat { public string FileName { get; set; } - public AnimationPackFile Parent { get; set; } + public AnimationPackFileDatabase Parent { get; set; } public bool IsUnknownFile { get; set; } = false; public NotifyAttr IsChanged { get; set; } = new NotifyAttr(false); public List AnimationTableEntries { get; set; } = new List(); @@ -193,7 +193,7 @@ List IAnimationBinGenericFormat.Entries string IAnimationBinGenericFormat.FullPath => FileName; - AnimationPackFile IAnimationBinGenericFormat.PackFileReference => Parent; + AnimationPackFileDatabase IAnimationBinGenericFormat.PackFileReference => Parent; } public class AnimationBinEntry diff --git a/Shared/GameFiles/AnimationPack/AnimationPackFile.cs b/Shared/GameFiles/AnimationPack/AnimationPackFileDatabase.cs similarity index 89% rename from Shared/GameFiles/AnimationPack/AnimationPackFile.cs rename to Shared/GameFiles/AnimationPack/AnimationPackFileDatabase.cs index d6aeb35d8..b774ff5a3 100644 --- a/Shared/GameFiles/AnimationPack/AnimationPackFile.cs +++ b/Shared/GameFiles/AnimationPack/AnimationPackFileDatabase.cs @@ -2,14 +2,14 @@ namespace Shared.GameFormats.AnimationPack { - public class AnimationPackFile + public class AnimationPackFileDatabase { public string FileName { get; private set; } private readonly List _files = new(); public IEnumerable Files { get => _files; } - public AnimationPackFile(string fileName) + public AnimationPackFileDatabase(string fileName) { FileName = fileName; } diff --git a/Shared/GameFiles/AnimationPack/AnimationPackSerializer.cs b/Shared/GameFiles/AnimationPack/AnimationPackSerializer.cs index d29986fcf..5b9883d2d 100644 --- a/Shared/GameFiles/AnimationPack/AnimationPackSerializer.cs +++ b/Shared/GameFiles/AnimationPack/AnimationPackSerializer.cs @@ -67,9 +67,9 @@ static IAnimFileSerializer DeterminePossibleSerializers(string fullPath) return new UnknownAnimFileSerializer(); } - public static AnimationPackFile Load(PackFile pf, IPackFileService pfs, GameTypeEnum preferedGame = GameTypeEnum.Unknown) + public static AnimationPackFileDatabase Load(PackFile pf, IPackFileService pfs, GameTypeEnum preferedGame = GameTypeEnum.Unknown) { - var output = new AnimationPackFile(pfs.GetFullPath(pf)); + var output = new AnimationPackFileDatabase(pfs.GetFullPath(pf)); var dataChunk = pf.DataSource.ReadDataAsChunk(); var files = FindAllSubFiles(dataChunk); @@ -84,7 +84,7 @@ public static AnimationPackFile Load(PackFile pf, IPackFileService pfs, GameType return output; } - public static byte[] ConvertToBytes(AnimationPackFile animPack) + public static byte[] ConvertToBytes(AnimationPackFileDatabase animPack) { using var memStream = new MemoryStream(); diff --git a/Shared/GameFiles/AnimationPack/IAnimationBinGenericFormat.cs b/Shared/GameFiles/AnimationPack/IAnimationBinGenericFormat.cs index 5eb5c49d2..7a1815431 100644 --- a/Shared/GameFiles/AnimationPack/IAnimationBinGenericFormat.cs +++ b/Shared/GameFiles/AnimationPack/IAnimationBinGenericFormat.cs @@ -2,7 +2,7 @@ { public interface IAnimationBinGenericFormat { - public AnimationPackFile PackFileReference { get; } + public AnimationPackFileDatabase PackFileReference { get; } public string Name { get; } public string FullPath { get; } public string SkeletonName { get; } diff --git a/Shared/SharedCore/ErrorHandling/PackFileLog.cs b/Shared/SharedCore/ErrorHandling/PackFileLog.cs index e6ed7fab1..d1e82dcea 100644 --- a/Shared/SharedCore/ErrorHandling/PackFileLog.cs +++ b/Shared/SharedCore/ErrorHandling/PackFileLog.cs @@ -18,10 +18,14 @@ public void Add(CompressionInformation compressionInformation) public static class PackFileLog { private static readonly ILogger s_logger = Logging.CreateStatic(typeof(PackFileLog)); + public static bool IsLoggingEnabled { get; set; } = true; public static Dictionary GetCompressionInformation(PackFileContainer container) { var compressionInformation = new Dictionary(); + if(IsLoggingEnabled == false) + return compressionInformation; + foreach (var packFile in container.FileList.Values) { @@ -44,6 +48,9 @@ public static Dictionary GetCompressi public static void LogPackCompression(PackFileContainer container) { + if (IsLoggingEnabled == false) + return; + var compressionInformation = GetCompressionInformation(container); var totalFiles = container.FileList.Count; var packSize = FormatSize(container.OriginalLoadByteSize); @@ -110,6 +117,9 @@ public static void LogPackCompression(PackFileContainer container) public static void LogPacksCompression(IDictionary allCompressionInformation) { + if (IsLoggingEnabled == false) + return; + var segments = new List(); foreach (var compressionEntry in allCompressionInformation.OrderBy(compressionEntry => compressionEntry.Key)) diff --git a/Shared/SharedCore/PackFiles/Models/PackFileContainer.cs b/Shared/SharedCore/PackFiles/Models/PackFileContainer.cs index 031d39a8f..a19ef182b 100644 --- a/Shared/SharedCore/PackFiles/Models/PackFileContainer.cs +++ b/Shared/SharedCore/PackFiles/Models/PackFileContainer.cs @@ -1,9 +1,5 @@ -using Shared.Core.PackFiles.Utility; - -namespace Shared.Core.PackFiles.Models +namespace Shared.Core.PackFiles.Models { - - public class PackFileContainer { public string Name { get; set; } diff --git a/Shared/SharedCore/PackFiles/PackFileService.cs b/Shared/SharedCore/PackFiles/PackFileService.cs index 8f3475218..9676f4f10 100644 --- a/Shared/SharedCore/PackFiles/PackFileService.cs +++ b/Shared/SharedCore/PackFiles/PackFileService.cs @@ -278,7 +278,7 @@ public void SavePackContainer(PackFileContainer pf, string path, bool createBack using (var memoryStream = new FileStream(path + "_temp", FileMode.Create)) { using var writer = new BinaryWriter(memoryStream); - PackFileSerializerWriter.SaveToByteArray(pf, writer, gameInformation); + PackFileSerializerWriter.SaveToByteArray(path, pf, writer, gameInformation); } File.Delete(path); diff --git a/Shared/SharedCore/PackFiles/Serialization/PackFileSerializerWriter.cs b/Shared/SharedCore/PackFiles/Serialization/PackFileSerializerWriter.cs index bb0342ec1..256f29d2f 100644 --- a/Shared/SharedCore/PackFiles/Serialization/PackFileSerializerWriter.cs +++ b/Shared/SharedCore/PackFiles/Serialization/PackFileSerializerWriter.cs @@ -17,7 +17,7 @@ class PackFileWriteInformation(PackFile pf, string fullFileName, long sizePositi static class PackFileSerializerWriter { - public static void SaveToByteArray(PackFileContainer container, BinaryWriter writer, GameInformation currentGameInformation) + public static void SaveToByteArray(string outputFileName, PackFileContainer container, BinaryWriter writer, GameInformation currentGameInformation) { if (container.Header.HasEncryptedData || container.Header.HasEncryptedIndex) throw new InvalidOperationException("Saving encrypted packs is not supported."); @@ -33,7 +33,7 @@ public static void SaveToByteArray(PackFileContainer container, BinaryWriter wri // Write the core of the file var fileMetaDataTable = BuildMetaDataTable(sortedFiles, container, currentGameInformation); SerializeFileTable(fileMetaDataTable, container, writer); - SerializeFileBlob(fileMetaDataTable, container, writer); + SerializeFileBlob(outputFileName, fileMetaDataTable, container, writer); } public static void WriteHeader(PFHeader header, uint fileContentSize, BinaryWriter writer) @@ -193,7 +193,7 @@ public static void SerializeFileTable(List fileMetaDat } } - public static void SerializeFileBlob(List fileMetaDataTabel, PackFileContainer container, BinaryWriter writer) + public static void SerializeFileBlob(string outputFileName, List fileMetaDataTabel, PackFileContainer container, BinaryWriter writer) { foreach (var fileMetaData in fileMetaDataTabel) { @@ -235,7 +235,7 @@ public static void SerializeFileBlob(List fileMetaData writer.BaseStream.Position = currentPosition; // Update DataSource - var packedFileSourceParent = new PackedFileSourceParent { FilePath = container.SystemFilePath }; + var packedFileSourceParent = new PackedFileSourceParent { FilePath = outputFileName }; packFile.DataSource = new PackedFileSource( packedFileSourceParent, offset, diff --git a/Shared/SharedCore/Services/VersionChecker.cs b/Shared/SharedCore/Services/VersionChecker.cs index 2fe4e3b61..8222ab087 100644 --- a/Shared/SharedCore/Services/VersionChecker.cs +++ b/Shared/SharedCore/Services/VersionChecker.cs @@ -8,7 +8,7 @@ namespace Shared.Core.Services public class VersionChecker { private static readonly string GitHubLink = @"https://github.com/donkeyProgramming/TheAssetEditor/releases/latest"; - public static string CurrentVersion { get => "0.63"; } + public static string CurrentVersion { get => "0.64"; } public static void CheckVersion() { diff --git a/Testing/Shared.Core.Test/PackFiles/Serialization/PackFileSerializerWriterTests.cs b/Testing/Shared.Core.Test/PackFiles/Serialization/PackFileSerializerWriterTests.cs index dac92df30..bdc2a2162 100644 --- a/Testing/Shared.Core.Test/PackFiles/Serialization/PackFileSerializerWriterTests.cs +++ b/Testing/Shared.Core.Test/PackFiles/Serialization/PackFileSerializerWriterTests.cs @@ -52,6 +52,7 @@ public void PackFileSerializerWriterTests_GameWithoutCompression( }; // Create packfile with the above files + var outputContainerName = @"c:\fullpath\to\packfile.pack"; var packFileHeader = PackFileVersionConverter.ToString(outputPackFileVersion); var container = new PackFileContainer("test") { @@ -64,25 +65,35 @@ public void PackFileSerializerWriterTests_GameWithoutCompression( using var writeMs = new MemoryStream(); using var writer = new BinaryWriter(writeMs); - PackFileSerializerWriter.SaveToByteArray(container, writer, gameInfo); + PackFileSerializerWriter.SaveToByteArray(outputContainerName, container, writer, gameInfo); var data = writeMs.ToArray(); + // Asser that the internal file references have been updated + foreach (var fileInfo in expectedFileInfo) + { + var dataSourceInstance = container.FileList[fileInfo.FilePath].DataSource as PackedFileSource; + Assert.That(dataSourceInstance, Is.Not.Null); + Assert.That(dataSourceInstance.Parent.FilePath, Is.EqualTo(outputContainerName)); + } - // Assert + // Load the file and assert using var readBackMs = new MemoryStream(data); var reader = new BinaryReader(readBackMs); - var loadedPackFile = PackFileSerializerLoader.Load("testpackfile.pack", data.LongLength, reader, new CaPackDuplicateFileResolver()); + var loadedPackFile = PackFileSerializerLoader.Load(outputContainerName, data.LongLength, reader, new CaPackDuplicateFileResolver()); - for (int i = 0; i < expectedFileInfo.Count; i++) + for (var i = 0; i < expectedFileInfo.Count; i++) { var expectedFileInfoInstance = expectedFileInfo[i]; var packFile = loadedPackFile.FileList[expectedFileInfoInstance.FilePath.ToLower()]; // Bypass the filesystem lookup and go directly to stream var packFileConentet = (packFile.DataSource as PackedFileSource).ReadData(readBackMs); - // - // - //// Assert content is correct + var parentName = (packFile.DataSource as PackedFileSource).Parent.FilePath; + + // Assert that parent file has been updated correctly + Assert.That(parentName.ToLower(), Is.EqualTo(outputContainerName.ToLower())); + + // Assert content is correct Assert.That(packFileConentet.Length, Is.EqualTo(expectedFileInfoInstance.Length)); Assert.That(packFileConentet, Is.EqualTo(new string(expectedFileInfoInstance.Content, expectedFileInfoInstance.Length)));