diff --git a/AssetEditor.sln b/AssetEditor.sln
index c0993978a..b59bb2955 100644
--- a/AssetEditor.sln
+++ b/AssetEditor.sln
@@ -35,8 +35,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.TextureEditor", "Ed
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.Audio", "Editors\Audio\Editors.Audio.csproj", "{410AC3F4-021C-4993-BCCA-1810D153075D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.AnimationMeta", "Editors\AnimationMeta\Editors.AnimationMeta.csproj", "{4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Editors.AnimationVisualEditors", "Editors\AnimationEditor\Editors.AnimationVisualEditors.csproj", "{F513A090-CC3F-4DB4-8332-50EB3FDA5A37}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.E2EVerification", "Testing\E2EVerification\Test.E2EVerification.csproj", "{0B14A236-AAE0-4E9B-A41E-4AF9DD976BA7}"
@@ -94,6 +92,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnimationFragmentEditor", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editors.AnimationFragmentEditor", "Editors\AnimationFragmentEditor\Editor.AnimationFragmentEditor\Editors.AnimationFragmentEditor.csproj", "{37C9C29E-1353-1519-BBC0-D7827A8AF636}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MetaDataEditor", "MetaDataEditor", "{3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editors.AnimationMeta", "Editors\MetaDataEditor\AnimationMeta\Editors.AnimationMeta.csproj", "{0FCE7A0E-6478-A603-6491-6FE675F54000}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.AnimationMeta", "Editors\AnimationMeta\Test.AnimationMeta\Test.AnimationMeta.csproj", "{E759BE6D-E0A4-46B8-A02A-E8573F579E2F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -144,10 +148,6 @@ Global
{410AC3F4-021C-4993-BCCA-1810D153075D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{410AC3F4-021C-4993-BCCA-1810D153075D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{410AC3F4-021C-4993-BCCA-1810D153075D}.Release|Any CPU.Build.0 = Release|Any CPU
- {4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C}.Release|Any CPU.Build.0 = Release|Any CPU
{F513A090-CC3F-4DB4-8332-50EB3FDA5A37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F513A090-CC3F-4DB4-8332-50EB3FDA5A37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F513A090-CC3F-4DB4-8332-50EB3FDA5A37}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -220,6 +220,14 @@ Global
{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
+ {0FCE7A0E-6478-A603-6491-6FE675F54000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0FCE7A0E-6478-A603-6491-6FE675F54000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FCE7A0E-6478-A603-6491-6FE675F54000}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0FCE7A0E-6478-A603-6491-6FE675F54000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E759BE6D-E0A4-46B8-A02A-E8573F579E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E759BE6D-E0A4-46B8-A02A-E8573F579E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E759BE6D-E0A4-46B8-A02A-E8573F579E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E759BE6D-E0A4-46B8-A02A-E8573F579E2F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -236,7 +244,6 @@ Global
{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}
- {4FA1E72D-8764-4E6E-8C3A-B6BFE0821B5C} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0}
{F513A090-CC3F-4DB4-8332-50EB3FDA5A37} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0}
{0B14A236-AAE0-4E9B-A41E-4AF9DD976BA7} = {18424B6A-CB8A-4CE1-935C-72459F31521B}
{E604D1EB-02AC-4E31-9161-531F8830BFDB} = {18424B6A-CB8A-4CE1-935C-72459F31521B}
@@ -263,6 +270,9 @@ Global
{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}
+ {3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB} = {07AC615B-A8FC-4E1A-BDD5-BC11452429A0}
+ {0FCE7A0E-6478-A603-6491-6FE675F54000} = {3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB}
+ {E759BE6D-E0A4-46B8-A02A-E8573F579E2F} = {3123DC8F-5FAD-45A9-8DCC-7C5E0E61FAEB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB5968F3-98ED-4AFF-98EA-0DBEDCACADF2}
diff --git a/AssetEditor/AssetEditor.csproj b/AssetEditor/AssetEditor.csproj
index ee8486051..85fa332b6 100644
--- a/AssetEditor/AssetEditor.csproj
+++ b/AssetEditor/AssetEditor.csproj
@@ -7,6 +7,7 @@
AssetEditorIcon.ico
true
true
+ enable
@@ -15,11 +16,11 @@
-
+
diff --git a/AssetEditor/DependencyInjectionContainer.cs b/AssetEditor/DependencyInjectionContainer.cs
index 991fd6e9b..59c3d26dc 100644
--- a/AssetEditor/DependencyInjectionContainer.cs
+++ b/AssetEditor/DependencyInjectionContainer.cs
@@ -7,8 +7,8 @@
using Shared.Core.DependencyInjection;
using Shared.Core.DevConfig;
using Shared.Core.ErrorHandling.Exceptions;
+using Shared.Core.Events.Global;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
namespace AssetEditor
{
diff --git a/AssetEditor/ViewModels/EditorShortcutViewModel.cs b/AssetEditor/ViewModels/EditorShortcutViewModel.cs
index 73558c523..134c43947 100644
--- a/AssetEditor/ViewModels/EditorShortcutViewModel.cs
+++ b/AssetEditor/ViewModels/EditorShortcutViewModel.cs
@@ -1,7 +1,7 @@
using CommunityToolkit.Mvvm.Input;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
namespace AssetEditor.ViewModels
{
diff --git a/AssetEditor/ViewModels/MainViewModel.cs b/AssetEditor/ViewModels/MainViewModel.cs
index cd8f06083..e225e1429 100644
--- a/AssetEditor/ViewModels/MainViewModel.cs
+++ b/AssetEditor/ViewModels/MainViewModel.cs
@@ -13,7 +13,6 @@
using Shared.Ui.BaseDialogs.PackFileTree;
using Shared.Ui.BaseDialogs.PackFileTree.ContextMenu;
using Shared.Ui.Common;
-using Shared.Ui.Events.UiCommands;
namespace AssetEditor.ViewModels
{
diff --git a/Editors/AnimationEditor/Editors.AnimationVisualEditors.csproj b/Editors/AnimationEditor/Editors.AnimationVisualEditors.csproj
index ff5af88d7..8563cbe9a 100644
--- a/Editors/AnimationEditor/Editors.AnimationVisualEditors.csproj
+++ b/Editors/AnimationEditor/Editors.AnimationVisualEditors.csproj
@@ -1,10 +1,10 @@
-
- net10.0-windows
- true
- enable
- enable
-
+
+ net10.0-windows
+ enable
+ true
+ enable
+
diff --git a/Editors/AnimationEditor/MountAnimationCreator/MountAnimationCreatorViewModel.cs b/Editors/AnimationEditor/MountAnimationCreator/MountAnimationCreatorViewModel.cs
index 3adad45f8..eec1d6793 100644
--- a/Editors/AnimationEditor/MountAnimationCreator/MountAnimationCreatorViewModel.cs
+++ b/Editors/AnimationEditor/MountAnimationCreator/MountAnimationCreatorViewModel.cs
@@ -15,7 +15,6 @@
using Shared.Ui.Common;
using MessageBox = System.Windows.Forms.MessageBox;
using Clipboard = System.Windows.Clipboard;
-using Shared.Ui.Events.UiCommands;
using Shared.Core.Events;
using GameWorld.Core.Components.Selection;
using GameWorld.Core.Animation;
@@ -27,6 +26,7 @@
using Editors.AnimationVisualEditors.MountAnimationCreator.Services;
using GameWorld.Core.Services;
using Shared.Core.Services;
+using Shared.Core.Events.Global;
namespace AnimationEditor.MountAnimationCreator
diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs
index 3778e5e85..099f735e0 100644
--- a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs
+++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/AnimPackViewModel.cs
@@ -29,7 +29,7 @@ public partial class AnimPackViewModel : NotifyPropertyChangedImpl, IEditorInter
private ITextConverter? _activeConverter;
private readonly ApplicationSettingsService _appSettings;
private readonly IFileSaveService _packFileSaveService;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataFileParser;
public string DisplayName { get; set; } = "Not set";
@@ -40,15 +40,19 @@ public partial class AnimPackViewModel : NotifyPropertyChangedImpl, IEditorInter
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)
+ public AnimPackViewModel(IUiCommandFactory uiCommandFactory,
+ IPackFileService pfs,
+ ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper,
+ ApplicationSettingsService appSettings,
+ IFileSaveService packFileSaveService,
+ MetaDataFileParser metaDataFileParser)
{
_uiCommandFactory = uiCommandFactory;
_pfs = pfs;
_skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper;
_appSettings = appSettings;
_packFileSaveService = packFileSaveService;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
-
+ _metaDataFileParser = metaDataFileParser;
AnimationPackItems = new FilterCollection(new List(), OnItemSelected, BeforeItemSelected)
{
SearchFilter = (value, rx) => { return rx.Match(value.FileName).Success; }
@@ -83,7 +87,7 @@ void OnItemSelected(IAnimationPackFile seletedFile)
else if (seletedFile is AnimationBin typedBin)
_activeConverter = new AnimationBinFileToXmlConverter();
else if (seletedFile is AnimationBinWh3 wh3Bin)
- _activeConverter = new AnimationBinWh3FileToXmlConverter(_skeletonAnimationLookUpHelper, _metaDataTagDeSerializer, CurrentFile);
+ _activeConverter = new AnimationBinWh3FileToXmlConverter(_skeletonAnimationLookUpHelper, _metaDataFileParser, CurrentFile);
if (seletedFile == null || _activeConverter == null || seletedFile.IsUnknownFile)
{
diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs
index 58a9eec2f..857bf7011 100644
--- a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs
+++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs
@@ -16,14 +16,14 @@ namespace Editors.AnimationFragmentEditor.AnimationPack.Converters.AnimationBinW
public class AnimationBinWh3FileToXmlConverter : XmlToBinaryConverter
{
private readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataTagDeSerializer;
private string _animationPersistanceMetaFileName = "";
private readonly Dictionary _animationsVersionFoundInPersistenceMeta = [];
private readonly PackFile _animPackToValidate;
- public AnimationBinWh3FileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, MetaDataTagDeSerializer metaDataTagDeSerializer, PackFile animPackToValidate)
+ public AnimationBinWh3FileToXmlConverter(ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper, MetaDataFileParser metaDataTagDeSerializer, PackFile animPackToValidate)
{
_skeletonAnimationLookUpHelper = skeletonAnimationLookUpHelper;
_metaDataTagDeSerializer = metaDataTagDeSerializer;
@@ -286,7 +286,7 @@ private bool CheckForAnimationVersionsInMeta(string mainAnimationFile, string me
return false;
}
var data = theFile.DataSource.ReadData();
- var parsed = new MetaDataFileParser().ParseFile(data, _metaDataTagDeSerializer);
+ var parsed = _metaDataTagDeSerializer.ParseFile(data);
var mainAnimationHeader = GetAnimationHeader(mainAnimationFile, pfs);
if (mainAnimationHeader == null)
@@ -297,7 +297,7 @@ private bool CheckForAnimationVersionsInMeta(string mainAnimationFile, string me
var mainAnimationVersion = mainAnimationHeader.Version;
- var metaItems = parsed.Items;
+ var metaItems = parsed.Attributes;
foreach (var item in metaItems)
{
diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs
index 7a36a52f2..00ab4a7e9 100644
--- a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs
+++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/DevConfig/AnimPack_WH3.cs
@@ -1,11 +1,11 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
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
{
diff --git a/Editors/AnimationMeta/Editors.AnimationMeta.csproj b/Editors/AnimationMeta/Editors.AnimationMeta.csproj
deleted file mode 100644
index b515da389..000000000
--- a/Editors/AnimationMeta/Editors.AnimationMeta.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- net10.0-windows
- true
-
-
-
-
-
-
-
-
diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs
deleted file mode 100644
index e738cfa42..000000000
--- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows;
-using Editors.AnimationMeta.Presentation;
-using Shared.Core.Events;
-using Shared.Core.Misc;
-using Shared.GameFormats.AnimationMeta.Parsing;
-
-namespace Editors.AnimationMeta.MetaEditor.Commands
-{
- public class MetaDataTagCopyItem : ICopyPastItem
- {
- public string Description => "Copy object for MetaDataTag";
- public List Items { get; set; } = [];
- }
-
- class CopyPastCommand : IUiCommand
- {
- private readonly CopyPasteManager _copyPasteManager;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
-
- public CopyPastCommand(CopyPasteManager copyPasteManager, MetaDataTagDeSerializer metaDataTagDeSerializer)
- {
- _copyPasteManager = copyPasteManager;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
- }
-
- public void ExecuteCopy(MetaDataEditorViewModel controller)
- {
- var selectedTags = controller.Tags
- .Where(x => x.IsSelected)
- .ToList();
-
- // Check for errors
- foreach (var tag in selectedTags)
- {
- if (string.IsNullOrWhiteSpace(tag.HasError()) == false)
- {
- MessageBox.Show($"Can not copy object due to: {tag.HasError()}");
- return;
- }
- }
-
- var copyPastItem = new MetaDataTagCopyItem();
- foreach (var tag in selectedTags)
- {
- var fileFormatData = tag.GetAsFileFormatData();
- var entry = new UnknownMetaEntry()
- {
- Name = fileFormatData.Name,
- Data = fileFormatData.DataItem.Bytes,
- Version = tag.Version,
- };
- copyPastItem.Items.Add(entry);
- }
- _copyPasteManager.SetCopyItem(copyPastItem);
- }
-
- public void ExecutePaste(MetaDataEditorViewModel controller)
- {
- var pastObject = _copyPasteManager.GetPasteObject();
- if (pastObject != null)
- {
- var pasteObjects = pastObject.Items;
- var confirm = MessageBox.Show($"Paste {pasteObjects.Count} metadata objects?", "Meta Copy Paste", MessageBoxButton.YesNo);
- if (confirm != MessageBoxResult.Yes)
- return;
-
- foreach (var item in pasteObjects)
- {
- try
- {
- var typed = _metaDataTagDeSerializer.DeSerialize(item, out var errorStr);
- if (typed == null)
- throw new Exception(errorStr);
- controller.Tags.Add(new MetaDataEntry(typed, _metaDataTagDeSerializer));
- }
- catch
- {
- controller.Tags.Add(new UnkMetaDataEntry(item));
- }
- }
- return;
- }
-
- }
-
-
-
-
- }
-}
-
diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs b/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs
deleted file mode 100644
index 9e853e8c9..000000000
--- a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-using CommunityToolkit.Mvvm.ComponentModel;
-using Microsoft.Xna.Framework;
-using Serilog;
-using Shared.ByteParsing.Parsers;
-using Shared.Core.ErrorHandling;
-using Shared.Core.Misc;
-using Shared.Ui.BaseDialogs.MathViews;
-
-namespace Editors.AnimationMeta.Presentation
-{
- public partial class MetaDataAttribute : ObservableObject
- {
- private readonly ILogger _logger = Logging.Create();
- private readonly IByteParser _parser;
-
- [ObservableProperty] string _valueAsString;
- [ObservableProperty] string _fieldName;
- [ObservableProperty] string _description;
- [ObservableProperty] string _valueType;
- [ObservableProperty] bool _isReadOnly = true;
- [ObservableProperty] bool _isValid = true;
-
- public MetaDataAttribute(IByteParser parser, object value)
- {
- _parser = parser;
- _valueAsString = value.ToString();
- Validate();
- }
-
- partial void OnValueAsStringChanged(string value) => Validate();
-
- void Validate()
- {
- IsValid = _parser.Encode(ValueAsString, out _) != null;
- }
-
- public virtual byte[] GetByteValue()
- {
- _logger.Here().Information($"GetByteValue=>{FieldName} {_parser} {ValueAsString}");
- var value = _parser.Encode(ValueAsString, out var error);
- _logger.Here().Information($"GetByteValue Complete=>{value?.Length} {error}");
- return value;
- }
- }
-
- public partial class OrientationMetaDataAttribute : MetaDataAttribute
- {
- private readonly ILogger _logger = Logging.Create();
- private readonly Vector4Parser _typedParser;
-
- [ObservableProperty] Vector3ViewModel _value = new Vector3ViewModel(0, 0, 0);
-
- public OrientationMetaDataAttribute(Vector4Parser parser, Vector4 value)
- : base(parser, value)
- {
- _typedParser = parser;
-
- var q = new Quaternion(value);
- var eulerRotation = MathUtil.QuaternionToEulerDegree(q);
-
- Value.Set(eulerRotation);
- IsValid = true;
- }
-
- public override byte[] GetByteValue()
- {
- _logger.Here().Information($"GetByteValue Orientation=>{FieldName} {_typedParser} {ValueAsString} {Value}");
-
- var vector3 = Value.GetAsVector3();
- var value = MathUtil.EulerDegreesToQuaternion(vector3);
- value.Normalize();
- _logger.Here().Information($"GetByteValue Orientation=>Vector computed");
-
- var bytes = _typedParser.EncodeValue(value.ToVector4(), out var err);
-
- _logger.Here().Information($"GetByteValue Complete=>{bytes?.Length} {err}");
-
- return bytes;
- }
- }
-
- public partial class VectorMetaDataAttribute : MetaDataAttribute
- {
- private readonly ILogger _logger = Logging.Create();
- private readonly Vector3Parser _parser;
-
- [ObservableProperty] Vector3ViewModel _value = new Vector3ViewModel(0, 0, 0);
-
- public VectorMetaDataAttribute(Vector3Parser parser, Vector3 value) : base(parser, value)
- {
- _parser = parser;
- Value.Set(value);
- IsValid = true;
- }
-
- public override byte[] GetByteValue()
- {
- _logger.Here().Information($"GetByteValue Vector3=>{FieldName} {_parser} {ValueAsString} {Value}");
-
- var vector3 = Value.GetAsVector3();
- _logger.Here().Information($"GetByteValue Vector3=>Vector computed");
-
- var bytes = _parser.EncodeValue(vector3, out var err);
- _logger.Here().Information($"GetByteValue Complete=>{bytes?.Length} {err}");
-
- return bytes;
- }
- }
-}
-
diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs
deleted file mode 100644
index 46e6be747..000000000
--- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reflection;
-using CommunityToolkit.Mvvm.ComponentModel;
-using Microsoft.Xna.Framework;
-using Serilog;
-using Shared.ByteParsing;
-using Shared.ByteParsing.Parsers;
-using Shared.Core.ErrorHandling;
-using Shared.GameFormats.AnimationMeta.Parsing;
-
-namespace Editors.AnimationMeta.Presentation
-{
- public abstract partial class IMetaDataEntry : ObservableObject
- {
- [ObservableProperty] ObservableCollection _variables = [];
-
- [ObservableProperty] string _displayName = "";
- [ObservableProperty] string _description = "";
- [ObservableProperty] bool _isDecodedCorrectly = false;
- [ObservableProperty] int _version;
- [ObservableProperty] bool _isSelected;
-
- public abstract MetaDataTagItem GetAsFileFormatData();
- public abstract string HasError();
- }
-
- public class UnkMetaDataEntry : IMetaDataEntry
- {
- private readonly UnknownMetaEntry _input;
-
- public UnkMetaDataEntry(UnknownMetaEntry unknownMeta)
- {
- _input = unknownMeta;
-
- IsDecodedCorrectly = false;
- DisplayName = unknownMeta.DisplayName;
- Version = unknownMeta.Version;
- }
-
- public override MetaDataTagItem GetAsFileFormatData()
- {
- var newItem = new MetaDataTagItem()
- {
- Name = _input.Name,
- DataItem = new MetaDataTagItem.TagData(_input.Data, 0, _input.Data.Length)
- };
- return newItem;
- }
-
- public override string HasError() => "";
- }
-
- public class MetaDataEntry : IMetaDataEntry
- {
- private readonly ILogger _logger = Logging.Create();
- private readonly string _originalName;
-
- public MetaDataEntry(BaseMetaEntry typedMetaItem, MetaDataTagDeSerializer metaDataTagDeSerializer)
- {
- _originalName = typedMetaItem.Name;
- DisplayName = typedMetaItem.DisplayName;
- Description = metaDataTagDeSerializer.GetDescriptionSafe(_originalName);
- Version = typedMetaItem.Version;
-
- var orderedPropertiesList = typedMetaItem.GetType().GetProperties()
- .Where(x => x.CanWrite)
- .Where(x => Attribute.IsDefined(x, typeof(MetaDataTagAttribute)))
- .OrderBy(x => x.GetCustomAttributes(false).Single().Order);
-
- foreach (var prop in orderedPropertiesList)
- {
- var attributeInfo = prop.GetCustomAttributes(false).Single();
- var parser = ByteParserFactory.Create(prop.PropertyType);
- var value = prop.GetValue(typedMetaItem);
- var itemDiscription = $"Value type is {prop.PropertyType.Name}";
- if (string.IsNullOrWhiteSpace(attributeInfo.Description) == false)
- itemDiscription = attributeInfo.Description + "\n" + itemDiscription;
-
- MetaDataAttribute editableItem = null;
- if (attributeInfo.DisplayOverride == MetaDataTagAttribute.DisplayType.EulerVector || value is Vector3)
- {
- if (value is Vector3 vector3)
- editableItem = new VectorMetaDataAttribute(parser as Vector3Parser, vector3);
- else if (value is Vector4 quaternion)
- editableItem = new OrientationMetaDataAttribute(parser as Vector4Parser, quaternion);
- else
- throw new Exception("Unknown item");
- }
- else
- {
- editableItem = new MetaDataAttribute(parser, value.ToString());
- }
-
- editableItem.Description = itemDiscription;
- editableItem.FieldName = FormatFieldName(prop.Name);
- editableItem.IsReadOnly = !attributeInfo.IsEditable;
- Variables.Add(editableItem);
- }
-
- IsDecodedCorrectly = true;
-
- if (Variables.Count != 0)
- Variables.First().IsReadOnly = true;
- }
-
- public override string HasError()
- {
- foreach (var variable in Variables)
- {
- if (!variable.IsValid)
- return $"Variable '{variable.FieldName}' in {DisplayName} has an error";
- }
-
- return null;
- }
-
- public override MetaDataTagItem GetAsFileFormatData()
- {
- _logger.Here().Information("Start " + DisplayName);
- var newItem = new MetaDataTagItem()
- {
- Name = _originalName,
- };
-
- _logger.Here().Information("Getting variables");
- var byteList = new List();
- foreach (var variable in Variables)
- {
- _logger.Here().Information(variable.FieldName + " " + variable.ValueAsString);
- var bytes = variable.GetByteValue();
- _logger.Here().Information(variable.FieldName + " " + variable.ValueAsString + " {" + bytes.Length + "}");
- byteList.Add(bytes);
- }
-
- _logger.Here().Information("Creating byte array");
- var totalCount = byteList.Sum(x => x.Length);
- var byteArray = new byte[totalCount];
-
- var currentByte = 0;
- foreach (var byteItem in byteList)
- {
- byteItem.CopyTo(byteArray, currentByte);
- currentByte += byteItem.Length;
- }
-
- _logger.Here().Information("Creating tag. Length = " + totalCount);
- var instance = new MetaDataTagItem.TagData(byteArray, 0, totalCount);
- newItem.DataItem = instance;
-
- _logger.Here().Information("Done");
- return newItem;
- }
-
- static string FormatFieldName(string name)
- {
- var newName = "";
- for (var i = 0; i < name.Length; i++)
- {
- if (char.IsUpper(name[i]) && i != 0)
- newName += " ";
- newName += name[i];
- }
- return newName;
- }
- }
-}
-
diff --git a/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj
new file mode 100644
index 000000000..28d5004aa
--- /dev/null
+++ b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj
@@ -0,0 +1,38 @@
+
+
+
+ net10.0-windows
+ true
+ enable
+ enable
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs
new file mode 100644
index 000000000..fd2d32cb4
--- /dev/null
+++ b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs
@@ -0,0 +1,40 @@
+using Editors.AnimationMeta.Presentation;
+using Shared.Core.Events.Global;
+using Test.TestingUtility.Shared;
+using Test.TestingUtility.TestUtility;
+
+namespace Test.AnimationMeta
+{
+ public class Tests
+ {
+
+ [Test]
+ public void MetaDataEditor_OpenAndVerify()
+ {
+ var packFile = PathHelper.GetDataFile("Throt.pack");
+
+
+ var runner = new AssetEditorTestRunner();
+ runner.CreateCaContainer();
+ var outputPackFile = runner.LoadPackFile(packFile, true);
+
+
+ var metaPackFile = runner.PackFileService.FindFile(@"animations/battle/humanoid17/throt_whip_catcher/attacks/hu17_whip_catcher_attack_05.anm.meta");
+ var editor = runner.CommandFactory
+ .Create()
+ .Execute(metaPackFile!, Shared.Core.ToolCreation.EditorEnums.Meta_Editor);
+
+
+ //editor.ParsedFile
+
+
+ // editor.SaveActionCommand.Execute(null);
+ }
+
+
+ // OpenAndSave
+ // OpenModifyAndSave (Check for modifiesd flag)
+ // DeleteAndSave
+ // MoveUpAndSave
+ }
+}
diff --git a/Editors/AnimationReTarget/Test.AnimatioReTarget/AnimationRetargeTool_ComplexUseCase.cs b/Editors/AnimationReTarget/Test.AnimatioReTarget/AnimationRetargeTool_ComplexUseCase.cs
index 28f1ff74f..cd834609c 100644
--- a/Editors/AnimationReTarget/Test.AnimatioReTarget/AnimationRetargeTool_ComplexUseCase.cs
+++ b/Editors/AnimationReTarget/Test.AnimatioReTarget/AnimationRetargeTool_ComplexUseCase.cs
@@ -2,9 +2,9 @@
using Editors.AnimatioReTarget.Editor.BoneHandling;
using Editors.Shared.Core.Common;
using GameWorld.Core.SceneNodes;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles.Models;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
using Test.TestingUtility.Shared;
using Test.TestingUtility.TestUtility;
diff --git a/Editors/Audio/DevConfig/AudioEditor_Wh3.cs b/Editors/Audio/DevConfig/AudioEditor_Wh3.cs
index fe821440e..a35c379ff 100644
--- a/Editors/Audio/DevConfig/AudioEditor_Wh3.cs
+++ b/Editors/Audio/DevConfig/AudioEditor_Wh3.cs
@@ -1,8 +1,8 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.Settings;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
namespace Editors.Audio.DevConfig
{
diff --git a/Editors/Audio/DevConfig/AudioExplorer_Attila.cs b/Editors/Audio/DevConfig/AudioExplorer_Attila.cs
index d39d8f60a..b87c43391 100644
--- a/Editors/Audio/DevConfig/AudioExplorer_Attila.cs
+++ b/Editors/Audio/DevConfig/AudioExplorer_Attila.cs
@@ -1,8 +1,8 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.Settings;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
namespace Editors.Audio.DevConfig
{
diff --git a/Editors/Audio/DevConfig/AudioExplorer_Wh3.cs b/Editors/Audio/DevConfig/AudioExplorer_Wh3.cs
index c12c9fbb2..f891e12b8 100644
--- a/Editors/Audio/DevConfig/AudioExplorer_Wh3.cs
+++ b/Editors/Audio/DevConfig/AudioExplorer_Wh3.cs
@@ -1,8 +1,8 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.Settings;
using Shared.Core.ToolCreation;
-using Shared.Ui.Events.UiCommands;
namespace Editors.Audio.DevConfig
{
diff --git a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl.cs b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl.cs
index 5aeb612e2..e5e3430dd 100644
--- a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl.cs
+++ b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl.cs
@@ -1,11 +1,11 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
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.KitbasherEditor.DevConfig
{
diff --git a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl_WH2.cs b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl_WH2.cs
index 013dca271..792a30605 100644
--- a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl_WH2.cs
+++ b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Karl_WH2.cs
@@ -1,8 +1,8 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.Settings;
-using Shared.Ui.Events.UiCommands;
namespace Editors.KitbasherEditor.DevConfig
{
diff --git a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Ox.cs b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Ox.cs
index 54b5c555e..97e8f3523 100644
--- a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Ox.cs
+++ b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Ox.cs
@@ -1,10 +1,10 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Utility;
using Shared.Core.Settings;
using Shared.EmbeddedResources;
-using Shared.Ui.Events.UiCommands;
namespace Editors.KitbasherEditor.DevConfig
{
diff --git a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Rat.cs b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Rat.cs
index a107de4a0..172028d50 100644
--- a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Rat.cs
+++ b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_Rat.cs
@@ -2,11 +2,11 @@
using Shared.Core.DependencyInjection;
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Utility;
using Shared.Core.Settings;
using Shared.EmbeddedResources;
-using Shared.Ui.Events.UiCommands;
namespace Editors.KitbasherEditor.DevConfig
{
diff --git a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_RomeShield.cs b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_RomeShield.cs
index 0702b3d7d..77629ba19 100644
--- a/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_RomeShield.cs
+++ b/Editors/Kitbashing/KitbasherEditor/DevConfig/Kitbash_RomeShield.cs
@@ -1,10 +1,10 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Utility;
using Shared.Core.Settings;
using Shared.EmbeddedResources;
-using Shared.Ui.Events.UiCommands;
namespace Editors.KitbasherEditor.DevConfig
{
diff --git a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/KitbashEditor_SaveTests.cs b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/KitbashEditor_SaveTests.cs
index 58a83d51a..1b8505373 100644
--- a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/KitbashEditor_SaveTests.cs
+++ b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/KitbashEditor_SaveTests.cs
@@ -1,14 +1,4 @@
-using Editors.KitbasherEditor.UiCommands;
-using GameWorld.Core.Services.SceneSaving;
-using GameWorld.Core.Services.SceneSaving.Lod;
-using Shared.Core.Events;
-using Shared.Core.Settings;
-using Shared.GameFormats.RigidModel;
-using Shared.Ui.Events.UiCommands;
-using Test.TestingUtility.Shared;
-using Test.TestingUtility.TestUtility;
-
-namespace Test.KitbashEditor.LoadAndSave
+namespace Test.KitbashEditor.LoadAndSave
{
public class KitbashEditor_SaveTests
{
diff --git a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSaveBase.cs b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSaveBase.cs
index 3a6c91304..31026de94 100644
--- a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSaveBase.cs
+++ b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSaveBase.cs
@@ -6,11 +6,11 @@
using GameWorld.Core.SceneNodes;
using GameWorld.Core.Services.SceneSaving;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.Settings;
using Shared.GameFormats.RigidModel;
using Shared.GameFormats.RigidModel.MaterialHeaders;
using Shared.GameFormats.RigidModel.Types;
-using Shared.Ui.Events.UiCommands;
using Test.TestingUtility.Shared;
using Test.TestingUtility.TestUtility;
diff --git a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_Geometry.cs b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_Geometry.cs
index 6da85e5b4..cf934eda9 100644
--- a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_Geometry.cs
+++ b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_Geometry.cs
@@ -7,8 +7,8 @@
using GameWorld.Core.Services.SceneSaving;
using GameWorld.Core.Services.SceneSaving.Lod;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.GameFormats.RigidModel;
-using Shared.Ui.Events.UiCommands;
using Test.TestingUtility.Shared;
namespace Test.KitbashEditor.LoadAndSave
diff --git a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_WsModel.cs b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_WsModel.cs
index d9f8ee966..73aabcecc 100644
--- a/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_WsModel.cs
+++ b/Editors/Kitbashing/Test.KitbashEditor/LoadAndSave/LoadAndSave_WsModel.cs
@@ -6,8 +6,8 @@
using Editors.KitbasherEditor.UiCommands;
using GameWorld.Core.Services.SceneSaving;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.GameFormats.RigidModel;
-using Shared.Ui.Events.UiCommands;
using Test.TestingUtility.Shared;
namespace Test.KitbashEditor.LoadAndSave
diff --git a/Editors/AnimationMeta/DependencyInjectionContainer.cs b/Editors/MetaDataEditor/AnimationMeta/DependencyInjectionContainer.cs
similarity index 86%
rename from Editors/AnimationMeta/DependencyInjectionContainer.cs
rename to Editors/MetaDataEditor/AnimationMeta/DependencyInjectionContainer.cs
index bc174b2df..ed4f05620 100644
--- a/Editors/AnimationMeta/DependencyInjectionContainer.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/DependencyInjectionContainer.cs
@@ -3,14 +3,12 @@
using Editors.AnimationMeta.Presentation;
using Editors.AnimationMeta.Presentation.View;
using Editors.AnimationMeta.SuperView;
-using Editors.AnimationMeta.Visualisation;
+using Editors.AnimationMeta.SuperView.Visualisation;
using Editors.Shared.Core.Common.BaseControl;
-using Editors.Shared.Core.Services;
using Microsoft.Extensions.DependencyInjection;
using Shared.Core.DependencyInjection;
using Shared.Core.DevConfig;
using Shared.Core.ToolCreation;
-using Shared.GameFormats.AnimationMeta.Parsing;
namespace Editors.AnimationMeta
{
@@ -18,14 +16,13 @@ public class DependencyInjectionContainer : DependencyContainer
{
public override void Register(IServiceCollection serviceCollection)
{
- serviceCollection.AddSingleton();
serviceCollection.AddTransient();
serviceCollection.AddTransient();
serviceCollection.AddScoped>();
serviceCollection.AddScoped();
- serviceCollection.AddScoped(); // Needs heavy refactorying!
+ serviceCollection.AddScoped(); // Needs heavy refactorying!
// Commands for metadata editor
serviceCollection.AddTransient();
diff --git a/Editors/AnimationMeta/DevConfig/AnimMetaTool.cs b/Editors/MetaDataEditor/AnimationMeta/DevConfig/AnimMetaTool.cs
similarity index 93%
rename from Editors/AnimationMeta/DevConfig/AnimMetaTool.cs
rename to Editors/MetaDataEditor/AnimationMeta/DevConfig/AnimMetaTool.cs
index ab67e92fe..c819c1279 100644
--- a/Editors/AnimationMeta/DevConfig/AnimMetaTool.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/DevConfig/AnimMetaTool.cs
@@ -27,14 +27,14 @@ public void OverrideSettings(ApplicationSettings currentSettings)
var packFile = ResourceLoader.GetDevelopmentDataFolder() + "\\Throt.pack";
var container = _packFileContainerLoader.Load(packFile);
- container.IsCaPackFile = true;
+ container!.IsCaPackFile = true;
_packFileService.AddContainer(container);
}
public void OpenFileOnLoad()
{
var file = _packFileService.FindFile(@"animations\battle\humanoid17\throt_whip_catcher\attacks\hu17_whip_catcher_attack_05.anm.meta");
- _editorCreator.CreateFromFile(file);
+ _editorCreator.CreateFromFile(file!);
}
}
}
diff --git a/Editors/AnimationMeta/DevConfig/SuperView_Rat.cs b/Editors/MetaDataEditor/AnimationMeta/DevConfig/SuperView_Rat.cs
similarity index 97%
rename from Editors/AnimationMeta/DevConfig/SuperView_Rat.cs
rename to Editors/MetaDataEditor/AnimationMeta/DevConfig/SuperView_Rat.cs
index ba8ed1885..921d590be 100644
--- a/Editors/AnimationMeta/DevConfig/SuperView_Rat.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/DevConfig/SuperView_Rat.cs
@@ -29,7 +29,7 @@ public void OverrideSettings(ApplicationSettings currentSettings)
currentSettings.LoadCaPacksByDefault = false;
var packFile = ResourceLoader.GetDevelopmentDataFolder() + "\\Throt.pack";
var container = _packFileContainerLoader.Load(packFile);
- container.IsCaPackFile = true;
+ container!.IsCaPackFile = true;
_packFileService.AddContainer(container);
}
@@ -42,13 +42,13 @@ void CreateThrot(IEditorCreator creator, IPackFileService packfileService)
{
var debugInput = new AnimationToolInput()
{
- Mesh = packfileService.FindFile(@"variantmeshes\variantmeshdefinitions\skv_throt.variantmeshdefinition"),
+ Mesh = packfileService.FindFile(@"variantmeshes\variantmeshdefinitions\skv_throt.variantmeshdefinition")!,
FragmentName = @"animations/database/battle/bin/hu17_dlc16_throt.bin",
AnimationSlot = DefaultAnimationSlotTypeHelper.GetfromValue("ATTACK_5")
};
var editor = creator.Create(EditorEnums.SuperView_Editor) as SuperViewViewModel;
- editor.Load(debugInput);
+ editor!.Load(debugInput);
}
}
diff --git a/Editors/MetaDataEditor/AnimationMeta/Editors.AnimationMeta.csproj b/Editors/MetaDataEditor/AnimationMeta/Editors.AnimationMeta.csproj
new file mode 100644
index 000000000..71ed93c66
--- /dev/null
+++ b/Editors/MetaDataEditor/AnimationMeta/Editors.AnimationMeta.csproj
@@ -0,0 +1,15 @@
+
+
+ net10.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/Editors/MetaDataEditor/AnimationMeta/MetaEditor/AttributeViewModel.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/AttributeViewModel.cs
new file mode 100644
index 000000000..af7cd4e86
--- /dev/null
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/AttributeViewModel.cs
@@ -0,0 +1,130 @@
+using System.Reflection;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Microsoft.Xna.Framework;
+using Serilog;
+using Shared.ByteParsing.Parsers;
+using Shared.Core.ErrorHandling;
+using Shared.Core.Events;
+using Shared.Core.Misc;
+using Shared.Ui.BaseDialogs.MathViews;
+
+namespace Editors.AnimationMeta.Presentation
+{
+ public class MetaDataAttributeChangedEvent()
+ {
+
+ }
+
+ public partial class AttributeViewModel : ObservableObject
+ {
+ private readonly ILogger _logger = Logging.Create();
+ private readonly IByteParser _parser;
+ protected readonly object _target;
+ protected readonly PropertyInfo _property;
+ protected readonly IEventHub _eventHub;
+
+ [ObservableProperty] string _valueAsString;
+ [ObservableProperty] string _fieldName;
+ [ObservableProperty] string _description;
+ [ObservableProperty] string _valueType;
+ [ObservableProperty] bool _isReadOnly = true;
+ [ObservableProperty] bool _isValid = true;
+
+ public AttributeViewModel(IByteParser parser, object value, object target, PropertyInfo property, IEventHub eventHub)
+ {
+ _parser = parser;
+ _target = target;
+ _property = property;
+ _eventHub = eventHub;
+ _valueAsString = value.ToString();
+ Validate();
+ }
+
+ partial void OnValueAsStringChanged(string value) => Validate();
+
+ void Validate()
+ {
+ IsValid = _parser.Encode(ValueAsString, out _) != null;
+ if (IsValid)
+ {
+ switch (_parser.Type)
+ {
+ case DbTypesEnum.String:
+ _property.SetValue(_target, ValueAsString);
+ break;
+ case DbTypesEnum.Integer:
+ _property.SetValue(_target, int.Parse(ValueAsString));
+ break;
+ case DbTypesEnum.Single:
+ _property.SetValue(_target, float.Parse(ValueAsString));
+ break;
+ case DbTypesEnum.Boolean:
+ _property.SetValue(_target, bool.Parse(ValueAsString));
+ break;
+ case DbTypesEnum.Byte:
+ _property.SetValue(_target, byte.Parse(ValueAsString));
+ break;
+ default:
+ var loggingStr = $"Unsupported type {_parser.Type} for property {_property.Name}";
+ _logger.Here().Error(loggingStr);
+ throw new ArgumentException(loggingStr);
+ }
+
+ _eventHub.Publish(new MetaDataAttributeChangedEvent());
+ }
+
+ }
+ }
+
+ public partial class OrientationAttributeViewModel : AttributeViewModel
+ {
+ [ObservableProperty] Vector3ViewModel _value = new(0, 0, 0);
+
+ public OrientationAttributeViewModel(Vector4Parser parser, Vector4 value, object target, PropertyInfo property, IEventHub eventHub)
+ : base(parser, value, target, property, eventHub)
+ {
+
+ _value = new(0, 0, 0, OnValueChangedCallback);
+
+ var q = new Quaternion(value);
+ var eulerRotation = MathUtil.QuaternionToEulerDegree(q);
+
+ Value.Set(eulerRotation);
+ IsValid = true;
+ }
+
+ private void OnValueChangedCallback(Vector3 vector)
+ {
+ var vector3 = Value.GetAsVector3();
+ var value = MathUtil.EulerDegreesToQuaternion(vector3);
+ value.Normalize();
+ _property.SetValue(_target, value.ToVector4());
+
+ _eventHub.Publish(new MetaDataAttributeChangedEvent());
+ }
+
+ }
+
+ public partial class VectorAttributeViewModel : AttributeViewModel
+ {
+ [ObservableProperty] Vector3ViewModel _value;
+
+ public VectorAttributeViewModel(Vector3Parser parser, Vector3 value, object target, PropertyInfo property, IEventHub eventHub)
+ : base(parser, value, target, property, eventHub)
+ {
+ _value = new(0, 0, 0, OnValueChangedCallback);
+ Value.Set(value);
+ IsValid = true;
+ }
+
+
+ private void OnValueChangedCallback(Vector3 vector)
+ {
+ var vector3 = Value.GetAsVector3();
+ _property.SetValue(_target, vector3);
+
+ _eventHub.Publish(new MetaDataAttributeChangedEvent());
+ }
+ }
+}
+
diff --git a/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs
new file mode 100644
index 000000000..1637d411c
--- /dev/null
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs
@@ -0,0 +1,64 @@
+using System.Windows;
+using Editors.AnimationMeta.Presentation;
+using Shared.Core.Events;
+using Shared.Core.Misc;
+using Shared.GameFormats.AnimationMeta.Parsing;
+
+namespace Editors.AnimationMeta.MetaEditor.Commands
+{
+ public class MetaDataTagCopyItem : ICopyPastItem
+ {
+ public string Description => "Copy object for MetaDataTag";
+ public List Items { get; set; } = [];
+ }
+
+ class CopyPastCommand : IUiCommand
+ {
+ private readonly CopyPasteManager _copyPasteManager;
+ private readonly MetaDataFileParser _metaDataFileParser;
+
+ public CopyPastCommand(CopyPasteManager copyPasteManager, MetaDataFileParser metaDataFileParser)
+ {
+ _copyPasteManager = copyPasteManager;
+ _metaDataFileParser = metaDataFileParser;
+ }
+
+ public void ExecuteCopy(MetaDataEditorViewModel controller)
+ {
+ var selectedTags = controller.Tags
+ .Where(x => x.IsSelected)
+ .ToList();
+
+ // Check for errors
+
+ foreach (var tag in selectedTags)
+ {
+ if (string.IsNullOrWhiteSpace(tag.HasError()) == false || tag._input == null)
+ {
+ MessageBox.Show($"Can not copy object due to: {tag.HasError()}");
+ return;
+ }
+ }
+ var copyPastItem = new MetaDataTagCopyItem();
+ foreach (var item in selectedTags)
+ {
+ var copy = ReflectionHelper.CreateShallowCopy(item._input);
+ copyPastItem.Items.Add(copy);
+
+ }
+ _copyPasteManager.SetCopyItem(copyPastItem);
+ }
+
+ public void ExecutePaste(MetaDataEditorViewModel controller)
+ {
+ var pastObject = _copyPasteManager.GetPasteObject();
+ if (pastObject != null)
+ {
+ controller.ParsedFile.Attributes.AddRange(pastObject.Items);
+ }
+
+ controller.UpdateView();
+ }
+ }
+}
+
diff --git a/Editors/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs
similarity index 87%
rename from Editors/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs
index 5688947f0..80e859f17 100644
--- a/Editors/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs
@@ -1,5 +1,4 @@
-using System.Linq;
-using Editors.AnimationMeta.Presentation;
+using Editors.AnimationMeta.Presentation;
using Shared.Core.Events;
namespace Editors.AnimationMeta.MetaEditor.Commands
diff --git a/Editors/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs
similarity index 99%
rename from Editors/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs
index 510c33118..a613f5fb7 100644
--- a/Editors/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs
@@ -36,7 +36,5 @@ public void ExecuteDown(MetaDataEditorViewModel controller)
controller.SelectedTag = itemToMove;
}
-
-
}
}
diff --git a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs
similarity index 55%
rename from Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs
index 0a4712806..3b8afd655 100644
--- a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs
@@ -9,17 +9,21 @@ namespace Editors.AnimationMeta.MetaEditor.Commands
{
internal class NewEntryCommand : IUiCommand
{
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataFileParser;
+ private readonly IMetaDataDatabase _metaDataDatabase;
+ private readonly IEventHub _eventHub;
- public NewEntryCommand(MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public NewEntryCommand(MetaDataFileParser metaDataFileParser, IMetaDataDatabase metaDataDatabase, IEventHub eventHub)
{
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
+ _metaDataFileParser = metaDataFileParser;
+ _metaDataDatabase = metaDataDatabase;
+ _eventHub = eventHub;
}
public void Execute(MetaDataEditorViewModel controller)
{
var dialog = new NewMetaDataEntryWindow() { Owner = Application.Current.MainWindow };
- var allDefs = _metaDataTagDeSerializer.GetSupportedTypes();
+ var allDefs = _metaDataDatabase.GetSupportedTypes();
var model = new NewTagWindowViewModel
{
@@ -30,8 +34,9 @@ public void Execute(MetaDataEditorViewModel controller)
var res = dialog.ShowDialog();
if (res.HasValue && res.Value == true)
{
- var newEntry = _metaDataTagDeSerializer.CreateDefault(model.SelectedItem);
- var newTagView = new MetaDataEntry(newEntry, _metaDataTagDeSerializer);
+ var newEntry = _metaDataFileParser.CreateDefault(model.SelectedItem);
+ var desc = _metaDataDatabase.GetDescriptionSafe(newEntry.DisplayName);
+ var newTagView = new MetaDataEntry(newEntry, desc, _eventHub, true);
controller.Tags.Add(newTagView);
}
diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/SaveCommand.cs
similarity index 72%
rename from Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/SaveCommand.cs
index a92931be9..1e8f760b7 100644
--- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/SaveCommand.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-using System.Windows;
-using Editors.AnimationMeta.Presentation;
+using Editors.AnimationMeta.Presentation;
using Serilog;
using Shared.Core.ErrorHandling;
using Shared.Core.Events;
@@ -17,39 +15,36 @@ class SaveCommand : IUiCommand
private readonly IPackFileService _packFileService;
private readonly IEventHub _eventHub;
private readonly IFileSaveService _packFileSaveService;
+ private readonly IStandardDialogs _standardDialogs;
+ private readonly MetaDataFileParser _metaDataFileParser;
- public SaveCommand(IPackFileService packFileService, IEventHub eventHub, IFileSaveService packFileSaveService)
+ public SaveCommand(IPackFileService packFileService, IEventHub eventHub, IFileSaveService packFileSaveService, IStandardDialogs standardDialogs, MetaDataFileParser metaDataFileParser)
{
_packFileService = packFileService;
_eventHub = eventHub;
_packFileSaveService = packFileSaveService;
+ _standardDialogs = standardDialogs;
+ _metaDataFileParser = metaDataFileParser;
}
public bool Execute(MetaDataEditorViewModel controller)
{
- var path = _packFileService.GetFullPath(controller.CurrentFile);
+ // Ensure there are no errors
foreach (var tag in controller.Tags)
{
var currentErrorMessage = tag.HasError();
if (string.IsNullOrWhiteSpace(currentErrorMessage) == false)
{
- MessageBox.Show($"Unable to save : {currentErrorMessage}");
+ _standardDialogs.ShowDialogBox($"Unable to save : {currentErrorMessage}");
return false;
}
}
+ // Save the file
+ var path = _packFileService.GetFullPath(controller.CurrentFile);
_logger.Here().Information("Creating metadata file. TagCount=" + controller.Tags.Count + " " + path);
- var tagDataItems = new List();
- foreach (var tag in controller.Tags)
- {
- _logger.Here().Information("Prosessing tag " + tag?.DisplayName);
- tagDataItems.Add(tag.GetAsFileFormatData());
- }
-
- _logger.Here().Information("Generating bytes");
- var parser = new MetaDataFileParser();
- var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, tagDataItems);
+ var bytes = _metaDataFileParser.GenerateBytes(controller.MetaDataFileVersion, controller.ParsedFile);
_logger.Here().Information("Saving");
var res = _packFileSaveService.Save(path, bytes, false);
if (res != null)
@@ -65,7 +60,7 @@ public bool Execute(MetaDataEditorViewModel controller)
NewPath = path,
};
_eventHub.Publish(saveEvent);
-
+
return true;
}
}
diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs
similarity index 51%
rename from Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs
index 451987ece..6a6a0be90 100644
--- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.ObjectModel;
+using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Editors.AnimationMeta.MetaEditor.Commands;
@@ -13,20 +12,35 @@ namespace Editors.AnimationMeta.Presentation
public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterface, ISaveableEditor, IFileEditor
{
private readonly IUiCommandFactory _uiCommandFactory;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataFileParser;
+ private readonly IEventHub _eventHub;
+ public ParsedMetadataFile? ParsedFile { get; private set; }
+ public ParsedMetadataAttribute? SelectedAttribute { get; private set; }
[ObservableProperty] string _displayName = "Metadata Editor";
- [ObservableProperty] IMetaDataEntry _selectedTag;
- [ObservableProperty] ObservableCollection _tags = [];
+ [ObservableProperty] MetaDataEntry _selectedTag;
+ [ObservableProperty] ObservableCollection _tags = [];
[ObservableProperty] int _metaDataFileVersion;
public bool HasUnsavedChanges { get; set; } = false;
public PackFile CurrentFile { get; set; }
- public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataFileParser metaDataFileParser, IEventHub eventHub)
{
_uiCommandFactory = uiCommandFactory;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
+ _metaDataFileParser = metaDataFileParser;
+ _eventHub = eventHub;
+ }
+
+ partial void OnSelectedTagChanged(MetaDataEntry value)
+ {
+ if(value == null)
+
+ SelectedAttribute = null;
+ else
+ SelectedAttribute = value._input;
+
+ _eventHub.Publish(new MetaDataAttributeChangedEvent());
}
public bool Save() => _uiCommandFactory.Create().Execute(this);
@@ -38,7 +52,7 @@ public void LoadFile(PackFile file)
return;
CurrentFile = file;
- Tags.Clear();
+
DisplayName = file == null ? "" : file.Name;
if (file == null)
@@ -46,18 +60,32 @@ public void LoadFile(PackFile file)
var fileContent = CurrentFile.DataSource.ReadData();
- var parser = new MetaDataFileParser();
- var loadedMetadataFile = parser.ParseFile(fileContent, _metaDataTagDeSerializer);
- MetaDataFileVersion = loadedMetadataFile.Version;
+ ParsedFile = _metaDataFileParser.ParseFile(fileContent);
+ MetaDataFileVersion = ParsedFile.Version;
+
+ UpdateView();
+ }
+
+ public void UpdateView()
+ {
+ Tags.Clear();
+ if (ParsedFile == null)
+ return;
- foreach (var item in loadedMetadataFile.Items)
+ foreach (var metadataEntry in ParsedFile.Attributes)
{
- if (item is UnknownMetaEntry uknMeta)
- Tags.Add(new UnkMetaDataEntry(uknMeta));
- else if (item is BaseMetaEntry metaBase)
- Tags.Add(new MetaDataEntry(metaBase, _metaDataTagDeSerializer));
+ if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta)
+ {
+ var desc = _metaDataFileParser.GetDatabase().GetDescriptionSafe(uknMeta.DisplayName);
+ Tags.Add(new MetaDataEntry(uknMeta, desc, _eventHub, false));
+ }
+ else if (metadataEntry is ParsedMetadataAttribute parsedKnownAttribute)
+ {
+ var desc = _metaDataFileParser.GetDatabase().GetDescriptionSafe(parsedKnownAttribute.DisplayName);
+ Tags.Add(new MetaDataEntry(parsedKnownAttribute, desc, _eventHub, true));
+ }
else
- throw new Exception($"{item.GetType()} is not a known type for {nameof(MetaDataEditorViewModel)}");
+ throw new Exception($"{metadataEntry.GetType()} is not a known type for {nameof(MetaDataEditorViewModel)}");
}
}
diff --git a/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs
new file mode 100644
index 000000000..5e5fdb6d8
--- /dev/null
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs
@@ -0,0 +1,99 @@
+using System.Collections.ObjectModel;
+using System.Reflection;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Microsoft.Xna.Framework;
+using Shared.ByteParsing;
+using Shared.ByteParsing.Parsers;
+using Shared.Core.Events;
+using Shared.GameFormats.AnimationMeta.Parsing;
+
+namespace Editors.AnimationMeta.Presentation
+{
+ public partial class MetaDataEntry : ObservableObject
+ {
+ public ParsedMetadataAttribute _input;
+
+ [ObservableProperty] ObservableCollection _variables = [];
+ [ObservableProperty] string _displayName = "";
+ [ObservableProperty] string _description = "";
+ [ObservableProperty] bool _isDecodedCorrectly = false;
+ [ObservableProperty] int _version;
+ [ObservableProperty] bool _isSelected;
+
+ public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, IEventHub eventHub, bool decodedCorrectly)
+ {
+ _input = typedMetaItem;
+ DisplayName = typedMetaItem.DisplayName;
+ Description = description;
+ Version = typedMetaItem.Version;
+ IsDecodedCorrectly = decodedCorrectly;
+
+ if(IsDecodedCorrectly == false)
+ return;
+
+ var orderedPropertiesList = typedMetaItem.GetType().GetProperties()
+ .Where(x => x.CanWrite)
+ .Where(x => Attribute.IsDefined(x, typeof(MetaDataTagAttribute)))
+ .OrderBy(x => x.GetCustomAttributes(false).Single().Order);
+
+ foreach (var prop in orderedPropertiesList)
+ {
+ var attributeInfo = prop.GetCustomAttributes(false).Single();
+ var parser = ByteParserFactory.Create(prop.PropertyType);
+ var value = prop.GetValue(typedMetaItem);
+ var itemDiscription = $"Value type is {prop.PropertyType.Name}";
+ if (string.IsNullOrWhiteSpace(attributeInfo.Description) == false)
+ itemDiscription = attributeInfo.Description + "\n" + itemDiscription;
+
+ AttributeViewModel? editableItem = null;
+ if (attributeInfo.DisplayOverride == MetaDataTagAttribute.DisplayType.EulerVector || value is Vector3)
+ {
+ if (value is Vector3 vector3)
+ editableItem = new VectorAttributeViewModel(parser as Vector3Parser, vector3, typedMetaItem, prop, eventHub);
+ else if (value is Vector4 quaternion)
+ editableItem = new OrientationAttributeViewModel(parser as Vector4Parser, quaternion, typedMetaItem, prop, eventHub);
+ else
+ throw new Exception("Unknown item");
+ }
+ else
+ {
+ editableItem = new AttributeViewModel(parser, value.ToString(), typedMetaItem, prop, eventHub);
+ }
+
+ editableItem.Description = itemDiscription;
+ editableItem.FieldName = FormatFieldName(prop.Name);
+ editableItem.IsReadOnly = !attributeInfo.IsEditable;
+ Variables.Add(editableItem);
+ }
+
+ if (Variables.Count != 0)
+ Variables.First().IsReadOnly = true;
+ }
+
+ public string? HasError()
+ {
+ foreach (var variable in Variables)
+ {
+ if (!variable.IsValid)
+ return $"Variable '{variable.FieldName}' in {DisplayName} has an error";
+ }
+
+ return null;
+ }
+
+ static string FormatFieldName(string name)
+ {
+ var newName = "";
+ for (var i = 0; i < name.Length; i++)
+ {
+ if (char.IsUpper(name[i]) && i != 0)
+ newName += " ";
+ newName += name[i];
+ }
+ return newName;
+ }
+ }
+
+
+}
+
diff --git a/Editors/AnimationMeta/MetaEditor/View/MainEditorView.xaml b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MainEditorView.xaml
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/MainEditorView.xaml
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MainEditorView.xaml
diff --git a/Editors/AnimationMeta/MetaEditor/View/MainEditorView.xaml.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MainEditorView.xaml.cs
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/MainEditorView.xaml.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MainEditorView.xaml.cs
diff --git a/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml
similarity index 98%
rename from Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml
index facda6317..6f5d642d7 100644
--- a/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml
+++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml
@@ -40,7 +40,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -81,7 +81,7 @@
-
+
diff --git a/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml.cs
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml.cs
diff --git a/Editors/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml
diff --git a/Editors/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml.cs
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml.cs
diff --git a/Editors/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml
diff --git a/Editors/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml.cs
similarity index 100%
rename from Editors/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml.cs
rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml.cs
diff --git a/Editors/AnimationMeta/SuperView/EditorView.xaml b/Editors/MetaDataEditor/AnimationMeta/SuperView/EditorView.xaml
similarity index 100%
rename from Editors/AnimationMeta/SuperView/EditorView.xaml
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/EditorView.xaml
diff --git a/Editors/AnimationMeta/SuperView/EditorView.xaml.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/EditorView.xaml.cs
similarity index 100%
rename from Editors/AnimationMeta/SuperView/EditorView.xaml.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/EditorView.xaml.cs
diff --git a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/SuperViewViewModel.cs
similarity index 70%
rename from Editors/AnimationMeta/SuperView/SuperViewViewModel.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/SuperViewViewModel.cs
index ce5f79a76..ff3d187ec 100644
--- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/SuperViewViewModel.cs
@@ -1,7 +1,6 @@
-using System;
-using System.Linq;
-using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
using Editors.AnimationMeta.Presentation;
+using Editors.AnimationMeta.SuperView.Visualisation;
using Editors.Shared.Core.Common;
using Editors.Shared.Core.Common.BaseControl;
using Editors.Shared.Core.Common.ReferenceModel;
@@ -18,7 +17,8 @@ public partial class SuperViewViewModel : EditorHostBase
SceneObjectViewModel _asset;
private readonly SceneObjectEditor _sceneObjectBuilder;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataFileParser;
+ private readonly IMetaDataBuilder _metaDataFactory;
private readonly IPackFileService _packFileService;
private readonly IEventHub _eventHub;
private readonly IUiCommandFactory _uiCommandFactory;
@@ -36,7 +36,8 @@ public SuperViewViewModel(
IUiCommandFactory uiCommandFactory,
SceneObjectEditor sceneObjectBuilder,
IEditorHostParameters editorHostParameters,
- MetaDataTagDeSerializer metaDataTagDeSerializer)
+ MetaDataFileParser metaDataFileParser,
+ IMetaDataBuilder metaDataFactory)
: base(editorHostParameters)
{
DisplayName = "Super view";
@@ -44,12 +45,19 @@ public SuperViewViewModel(
_eventHub = eventHub;
_uiCommandFactory = uiCommandFactory;
_sceneObjectBuilder = sceneObjectBuilder;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
+ _metaDataFileParser = metaDataFileParser;
+ _metaDataFactory = metaDataFactory;
Initialize();
eventHub.Register(this, OnFileSaved);
eventHub.Register(this, OnSceneObjectUpdated);
+ eventHub.Register(this, OnMetaDataAttributeChanged);
}
+ private void OnMetaDataAttributeChanged(MetaDataAttributeChangedEvent @event)
+ {
+ RecreateMetaDataInformation(null);
+ }
+
private void OnFileSaved(ScopedFileSavedEvent evnt)
{
var newFile = _packFileService.FindFile(evnt.NewPath);
@@ -63,16 +71,36 @@ private void OnFileSaved(ScopedFileSavedEvent evnt)
void Initialize()
{
- PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer);
- MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer);
+ PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser, _eventHub);
+ MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser, _eventHub);
- var assetViewModel = _sceneObjectViewModelBuilder.CreateAsset("SuperViewRoot", true, "Root", Color.Black,null, true);
+ var assetViewModel = _sceneObjectViewModelBuilder.CreateAsset("SuperViewRoot", true, "Root", Color.Black,null);
SceneObjects.Add(assetViewModel);
-
+
+ assetViewModel.Data.MetaDataChanged += RecreateMetaDataInformation;
+
_asset = assetViewModel;
OnSceneObjectUpdated(new SceneObjectUpdateEvent(_asset.Data, false, false, false, true));
}
+ void RecreateMetaDataInformation(SceneObject modsel)
+ {
+ foreach (var item in SceneObjects)
+ {
+ foreach (var t in item.Data.MetaDataItems)
+ t.CleanUp();
+
+ item.Data.MetaDataItems.Clear();
+ item.Data.Player.AnimationRules.Clear();
+ }
+
+ var persist = PersistentMetaEditor.ParsedFile;
+ var meta = MetaEditor.ParsedFile;
+
+ _asset.Data.MetaDataItems = _metaDataFactory.Create(persist, meta, MetaEditor.SelectedAttribute, _asset.Data.MainNode, _asset.Data, _asset.Data.Player, _asset.FragAndSlotSelection.FragmentList.SelectedItem);
+ _asset.Data.Player.Refresh();
+ }
+
private void OnSceneObjectUpdated(SceneObjectUpdateEvent e)
{
PersistentMetaEditor.LoadFile(e.Owner.PersistMetaData);
diff --git a/Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs
similarity index 85%
rename from Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs
index fb3f08d35..c309cce3a 100644
--- a/Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs
@@ -1,8 +1,8 @@
-using Editors.Shared.Core.Services;
+using Editors.Shared.Core.Common;
using GameWorld.Core.Animation;
using GameWorld.Core.SceneNodes;
-namespace Editors.AnimationMeta.Visualisation.Instances
+namespace Editors.AnimationMeta.SuperView.Visualisation.Instances
{
public class AnimatedPropInstance : IMetaDataInstance
{
diff --git a/Editors/AnimationMeta/Visualisation/Instances/DrawableMetaInstance.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs
similarity index 92%
rename from Editors/AnimationMeta/Visualisation/Instances/DrawableMetaInstance.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs
index 32451a346..ee2e23a36 100644
--- a/Editors/AnimationMeta/Visualisation/Instances/DrawableMetaInstance.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs
@@ -1,4 +1,4 @@
-using Editors.Shared.Core.Services;
+using Editors.Shared.Core.Common;
using GameWorld.Core.Animation;
using GameWorld.Core.SceneNodes;
using GameWorld.Core.Utility;
@@ -6,11 +6,11 @@
using Shared.Core.ErrorHandling;
using System;
-namespace Editors.AnimationMeta.Visualisation.Instances
+namespace Editors.AnimationMeta.SuperView.Visualisation.Instances
{
public class DrawableMetaInstance : IMetaDataInstance
{
- private readonly ILogger _logger = Logging.Create();
+ private readonly ILogger _logger = Logging.Create();
private bool _hasError = false;
private readonly SceneNode _node;
diff --git a/Editors/AnimationMeta/Visualisation/MetaDataFactory.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs
similarity index 70%
rename from Editors/AnimationMeta/Visualisation/MetaDataFactory.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs
index ed4c3e501..f82321c62 100644
--- a/Editors/AnimationMeta/Visualisation/MetaDataFactory.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs
@@ -1,10 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Linq;
-using Editors.AnimationMeta.Visualisation.Instances;
-using Editors.AnimationMeta.Visualisation.Rules;
-using Editors.Shared.Core.Services;
+using System.Data;
+using Editors.AnimationMeta.SuperView.Visualisation.Instances;
+using Editors.AnimationMeta.SuperView.Visualisation.Rules;
+using Editors.Shared.Core.Common;
using GameWorld.Core.Animation;
using GameWorld.Core.Components;
using GameWorld.Core.Components.Rendering;
@@ -22,19 +19,26 @@
using Shared.GameFormats.AnimationMeta.Parsing;
using Shared.GameFormats.AnimationPack;
-namespace Editors.AnimationMeta.Visualisation
+namespace Editors.AnimationMeta.SuperView.Visualisation
{
+ public interface IMetaDataBuilder
+ {
+ List Create(ParsedMetadataFile persistent, ParsedMetadataFile metaData, ParsedMetadataAttribute selectedMetaDataAttribute, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment);
+ }
- public class MetaDataFactory : IMetaDataFactory
+ public class MetaDataBuilder : IMetaDataBuilder
{
- private readonly ILogger _logger = Logging.Create();
+ private readonly ILogger _logger = Logging.Create();
private readonly ComplexMeshLoader _complexMeshLoader;
private readonly RenderEngineComponent _resourceLibrary;
private readonly ISkeletonAnimationLookUpHelper _skeletonAnimationLookUpHelper;
private readonly IPackFileService _packFileService;
private readonly AnimationsContainerComponent _animationsContainerComponent;
- public MetaDataFactory(ComplexMeshLoader complexMeshLoader,
+ private static Color s_color = Color.Black;
+ private static Color s_selectedColor = Color.Red;
+
+ public MetaDataBuilder(ComplexMeshLoader complexMeshLoader,
RenderEngineComponent resourceLibrary,
ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper,
IPackFileService packFileService,
@@ -47,39 +51,42 @@ public MetaDataFactory(ComplexMeshLoader complexMeshLoader,
_animationsContainerComponent = animationsContainerComponent;
}
- public List Create(MetaDataFile persistent, MetaDataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment)
+ public List Create(ParsedMetadataFile persistent,
+ ParsedMetadataFile metaData,ParsedMetadataAttribute selectedMetaDataAttribute,
+ SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment)
{
// Clear all
var output = new List();
+ // Apply persistent meta data, if no disable is given.
if (metaData == null || metaData.GetItemsOfType().Count == 0)
{
- var metaDataPersistent = ApplyMetaData(persistent, root, skeleton, rootPlayer, fragment);
+ var metaDataPersistent = ApplyMetaData(persistent, selectedMetaDataAttribute,root, skeleton, rootPlayer, fragment);
output.AddRange(metaDataPersistent);
}
- var metaDataInstances = ApplyMetaData(metaData, root, skeleton, rootPlayer, fragment);
+ var metaDataInstances = ApplyMetaData(metaData, selectedMetaDataAttribute,root, skeleton, rootPlayer, fragment);
output.AddRange(metaDataInstances);
return output;
}
- private IEnumerable ApplyMetaData(MetaDataFile file, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment)
+ private IEnumerable ApplyMetaData(ParsedMetadataFile file, ParsedMetadataAttribute selectedAttribute, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment)
{
var output = new List();
if (file == null)
return output;
- output.AddRange(file.GetItemsOfType().Select(x => CreateAnimatedProp(x, root, skeleton)));
+ output.AddRange(file.GetItemsOfType().Select(x => CreateAnimatedProp(x, root, skeleton, selectedAttribute, rootPlayer)));
- output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "ImpactPos")));
+ output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "ImpactPos", selectedAttribute)));
- output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "TargetPos")));
+ output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "TargetPos", selectedAttribute)));
- output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "FirePos")));
+ output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateStaticLocator(meteDataItem, root, meteDataItem.Position, "FirePos", selectedAttribute)));
- output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateSplashAttack(meteDataItem, root, $"SplashAttack_{Math.Round(meteDataItem.EndTime, 2)}", 0.1f)));
+ output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateSplashAttack(meteDataItem, root, $"SplashAttack_{Math.Round(meteDataItem.EndTime, 2)}", 0.1f, selectedAttribute)));
- output.AddRange(file.GetItemsOfType().Select(x => CreateEffect(x, root, skeleton)));
+ output.AddRange(file.GetItemsOfType().Select(x => CreateEffect(x, root, skeleton, selectedAttribute)));
foreach (var meteDataItem in file.GetItemsOfType())
CreateEquipmentDock(meteDataItem, fragment, skeleton, rootPlayer);
@@ -129,9 +136,10 @@ private void CreateEquipmentDock(DockEquipment metaData, IAnimationBinGenericFor
rootPlayer.AnimationRules.Add(rule);
}
- private IMetaDataInstance CreateAnimatedProp(IAnimatedPropMeta animatedPropMeta, SceneNode root, ISkeletonProvider rootSkeleton)
+ private IMetaDataInstance CreateAnimatedProp(IAnimatedPropMeta animatedPropMeta, SceneNode root, ISkeletonProvider rootSkeleton, ParsedMetadataAttribute selectedMetaDataAttribute, AnimationPlayer rootPlayer)
{
var propName = "Animated_prop";
+ var color = selectedMetaDataAttribute == animatedPropMeta ? s_selectedColor : s_color;
var meshPath = _packFileService.FindFile(animatedPropMeta.ModelName);
var animationPath = _packFileService.FindFile(animatedPropMeta.AnimationName);
@@ -151,23 +159,31 @@ private IMetaDataInstance CreateAnimatedProp(IAnimatedPropMeta animatedPropMeta,
propPlayer.SetAnimation(clip, skeleton);
// Add the prop skeleton
- var skeletonSceneNode = new SkeletonNode(skeleton);
- skeletonSceneNode.NodeColour = Color.Yellow;
- skeletonSceneNode.ScaleMult = animatedPropMeta.Scale;
+ var skeletonSceneNode = new SkeletonNode(skeleton)
+ {
+ NodeColour = color,
+ ScaleMult = animatedPropMeta.Scale
+ };
loadedNode.AddObject(skeletonSceneNode);
}
// Configure scale
loadedNode.ForeachNodeRecursive((node) =>
{
- if (node is SceneNode selectable)
- selectable.ScaleMult = animatedPropMeta.Scale;
+ if (node is ISelectable selectableNode)
+ selectableNode.IsSelectable = false;
+
+ if (node is SceneNode sceneNode)
+ sceneNode.ScaleMult = animatedPropMeta.Scale;
});
loadedNode.ScaleMult = animatedPropMeta.Scale;
// Add the animation rules
var animationRule = new CopyRootTransform(rootSkeleton, animatedPropMeta.BoneId, animatedPropMeta.Position, new Quaternion(animatedPropMeta.Orientation));
propPlayer.AnimationRules.Add(animationRule);
+ if(rootPlayer.IsPlaying)
+ propPlayer.Play();
+ propPlayer.Refresh();
// Add to scene
root.AddObject(loadedNode);
@@ -175,39 +191,41 @@ private IMetaDataInstance CreateAnimatedProp(IAnimatedPropMeta animatedPropMeta,
return new AnimatedPropInstance(loadedNode, propPlayer);
}
- private IMetaDataInstance CreateStaticLocator(DecodedMetaEntryBase metaData, SceneNode root, Vector3 position, string displayName, float scale = 0.3f)
+ private IMetaDataInstance CreateStaticLocator(DecodedMetaEntryBase metaData, SceneNode root, Vector3 position, string displayName, ParsedMetadataAttribute selectedMetaDataAttribute, float scale = 0.3f)
{
+ var color = selectedMetaDataAttribute == metaData ? s_selectedColor : s_color;
+
var node = new SimpleDrawableNode(displayName);
- node.AddItem(new WorldTextRenderItem(_resourceLibrary, displayName, position));
- node.AddItem(LineHelper.AddCircle(position, scale, Color.Red));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, displayName, position, color));
+ node.AddItem(LineHelper.AddCircle(position, scale, color));
root.AddObject(node);
return new DrawableMetaInstance(metaData.StartTime, metaData.EndTime, node.Name, node);
}
- private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, SceneNode root, string displayName, float scale = 0.3f)
+ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, SceneNode root, string displayName, float scale, ParsedMetadataAttribute selectedAttribute)
{
var distance = Vector3.Distance(splashAttack.StartPosition, splashAttack.EndPosition);
if (MathUtil.CompareEqualFloats(distance))
- {
throw new ConstraintException($"{displayName}: the distance between StartPosition {splashAttack.StartPosition} and EndPosition {splashAttack.EndPosition} is close to 0");
- }
+
+ var color = selectedAttribute == splashAttack ? s_selectedColor : s_color;
var node = new SimpleDrawableNode(displayName);
var textPos = (splashAttack.EndPosition + splashAttack.StartPosition) / 2;
- node.AddItem( new WorldTextRenderItem(_resourceLibrary, "StartPos", splashAttack.StartPosition));
- node.AddItem(LineHelper.AddLocator(splashAttack.StartPosition, scale, Color.Red));
+ node.AddItem( new WorldTextRenderItem(_resourceLibrary, "StartPos", splashAttack.StartPosition, color));
+ node.AddItem(LineHelper.AddLocator(splashAttack.StartPosition, scale, color));
- node.AddItem( new WorldTextRenderItem(_resourceLibrary, "EndPos", splashAttack.EndPosition));
- node.AddItem(LineHelper.AddLocator(splashAttack.EndPosition, scale, Color.Red));
+ node.AddItem( new WorldTextRenderItem(_resourceLibrary, "EndPos", splashAttack.EndPosition, color));
+ node.AddItem(LineHelper.AddLocator(splashAttack.EndPosition, scale, color));
- node.AddItem(new WorldTextRenderItem(_resourceLibrary, displayName, textPos));
- node.AddItem(LineHelper.AddLine(splashAttack.StartPosition, splashAttack.EndPosition, Color.Red));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, displayName, textPos, color));
+ node.AddItem(LineHelper.AddLine(splashAttack.StartPosition, splashAttack.EndPosition, color));
var normal = splashAttack.EndPosition - splashAttack.StartPosition; // corresponds to Z
normal.Normalize();
- var random = new Random();
+ var random = new Random(1);
Func RandomFloat = r => (float)(2 * r.NextDouble() - 1);
var vectorP = new Vector3(RandomFloat(random), RandomFloat(random), RandomFloat(random));
vectorP.Normalize();
@@ -217,12 +235,12 @@ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, Scen
planeVectorP.Normalize();
planeVectorPN.Normalize();
- var rotationM = MathUtil.CreateRotation(new[]
- {
+ var rotationM = MathUtil.CreateRotation(
+ [
planeVectorP,
planeVectorPN,
normal
- });
+ ]);
if (splashAttack.AoeShape == 0) // Cone or Sphere
{
@@ -231,7 +249,7 @@ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, Scen
throw new ConstraintException($"{displayName}: the half-angle {splashAttack.AngleForCone / 2} of the cone is close to 0");
}
var transformationM = rotationM * Matrix.CreateScale(distance) * Matrix.CreateTranslation(splashAttack.StartPosition);
- node.AddItem(LineHelper.AddConeSplash(splashAttack.StartPosition, splashAttack.EndPosition, transformationM, splashAttack.AngleForCone, Color.Red));
+ node.AddItem(LineHelper.AddConeSplash(splashAttack.StartPosition, splashAttack.EndPosition, transformationM, splashAttack.AngleForCone, color));
}
if (splashAttack.AoeShape == 1) // Corridor
{
@@ -240,7 +258,7 @@ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, Scen
throw new ConstraintException($"{displayName}: the WidthForCorridor {splashAttack.WidthForCorridor} of the corridor is close to 0");
}
var transformationM = rotationM * Matrix.CreateScale(splashAttack.WidthForCorridor / 2) * Matrix.CreateTranslation(splashAttack.StartPosition);
- node.AddItem(LineHelper.AddCorridorSplash(splashAttack.StartPosition, splashAttack.EndPosition, transformationM, Color.Red));
+ node.AddItem(LineHelper.AddCorridorSplash(splashAttack.StartPosition, splashAttack.EndPosition, transformationM, color));
}
root.AddObject(node);
@@ -248,16 +266,21 @@ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, Scen
return new DrawableMetaInstance(splashAttack.StartTime, splashAttack.EndTime, node.Name, node);
}
- private IMetaDataInstance CreateEffect(Effect_v11 effect, SceneNode root, ISkeletonProvider skeleton)
+ private IMetaDataInstance CreateEffect(IEffectMeta effect, SceneNode root, ISkeletonProvider skeleton, ParsedMetadataAttribute selectedAttribute)
{
+ var color = selectedAttribute == effect ? s_selectedColor : s_color;
var node = new SimpleDrawableNode("Effect:" + effect.VfxName);
- node.AddItem(LineHelper.AddLocator(effect.Position, 0.3f, Color.Red));
- node.AddItem(new WorldTextRenderItem(_resourceLibrary, effect.VfxName, effect.Position));
-
+ var locatorScale = 0.3f;
+ node.AddItem(LineHelper.AddRgbLocator(effect.Position, locatorScale));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, effect.VfxName, effect.Position, color));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, "X", effect.Position + new Vector3(locatorScale * .5f + 0.01f,0,0), Color.Red));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, "Y", effect.Position + new Vector3(0, locatorScale * .5f + 0.01f, 0), Color.Green));
+ node.AddItem(new WorldTextRenderItem(_resourceLibrary, "Z", effect.Position + new Vector3(0,0,locatorScale * .5f + 0.01f), Color.Blue));
+
root.AddObject(node);
- var instance = new DrawableMetaInstance(effect.StartTime, effect.EndTime, node.Name, node);
+ var instance = new DrawableMetaInstance(effect.EffectStartTime, effect.EffectEndTime, node.Name, node);
if (effect.Tracking)
instance.FollowBone(skeleton, effect.NodeIndex);
return instance;
diff --git a/Editors/AnimationMeta/Visualisation/Rules/CopyRootTransform.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs
similarity index 81%
rename from Editors/AnimationMeta/Visualisation/Rules/CopyRootTransform.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs
index 0499ee0a0..fa912b81f 100644
--- a/Editors/AnimationMeta/Visualisation/Rules/CopyRootTransform.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs
@@ -1,20 +1,21 @@
-using GameWorld.Core.Animation;
+using System;
+using System.Collections.ObjectModel;
+using GameWorld.Core.Animation;
using GameWorld.Core.Animation.AnimationChange;
using GameWorld.Core.SceneNodes;
using Microsoft.Xna.Framework;
using Serilog;
using Shared.Core.ErrorHandling;
-using System;
-namespace Editors.AnimationMeta.Visualisation.Rules
+namespace Editors.AnimationMeta.SuperView.Visualisation.Rules
{
public class CopyRootTransform : ILocalSpaceAnimationRule
{
- ILogger _logger = Logging.Create();
- bool _hasError = false;
+ readonly ILogger _logger = Logging.Create();
+ readonly ISkeletonProvider _skeletonProvider;
+ readonly int _boneId;
- ISkeletonProvider _skeletonProvider;
- int _boneId;
+ bool _hasError = false;
Vector3 _offsetPos;
Quaternion _offsetRot;
diff --git a/Editors/AnimationMeta/Visualisation/Rules/DockEquipmentRule.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs
similarity index 97%
rename from Editors/AnimationMeta/Visualisation/Rules/DockEquipmentRule.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs
index e62734009..478f18dec 100644
--- a/Editors/AnimationMeta/Visualisation/Rules/DockEquipmentRule.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs
@@ -6,7 +6,7 @@
using Shared.Core.ErrorHandling;
using System;
-namespace Editors.AnimationMeta.Visualisation.Rules
+namespace Editors.AnimationMeta.SuperView.Visualisation.Rules
{
public class DockEquipmentRule : IWorldSpaceAnimationRule
{
diff --git a/Editors/AnimationMeta/Visualisation/Rules/TransformBoneRule.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs
similarity index 95%
rename from Editors/AnimationMeta/Visualisation/Rules/TransformBoneRule.cs
rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs
index f8a463b31..6bd55c046 100644
--- a/Editors/AnimationMeta/Visualisation/Rules/TransformBoneRule.cs
+++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs
@@ -6,7 +6,7 @@
using Shared.Core.ErrorHandling;
using Shared.GameFormats.AnimationMeta.Definitions;
-namespace Editors.AnimationMeta.Visualisation.Rules
+namespace Editors.AnimationMeta.SuperView.Visualisation.Rules
{
public class TransformBoneRule : ILocalSpaceAnimationRule
{
diff --git a/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs b/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs
index 6db88e7f1..a3ac56e18 100644
--- a/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs
+++ b/Editors/Reports/Animation/AnimMetaDataJsonGenerator.cs
@@ -26,20 +26,21 @@ public class AnimMetaDataJsonGenerator
private readonly ILogger _logger = Logging.Create();
private readonly IPackFileService _pfs;
private readonly ApplicationSettingsService _settingsService;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+
+ private readonly MetaDataFileParser _metaDataFileParser;
private readonly JsonSerializerSettings _jsonOptions;
- public AnimMetaDataJsonGenerator(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public AnimMetaDataJsonGenerator(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataFileParser metaDataFileParser)
{
_pfs = pfs;
_settingsService = settingsService;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
+ _metaDataFileParser = metaDataFileParser;
_jsonOptions = new JsonSerializerSettings { Formatting = Formatting.Indented };
}
- public static void Generate(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public static void Generate(IPackFileService pfs, ApplicationSettingsService settingsService,MetaDataFileParser metaDataFileParser)
{
- var instance = new AnimMetaDataJsonGenerator(pfs, settingsService, metaDataTagDeSerializer);
+ var instance = new AnimMetaDataJsonGenerator(pfs, settingsService, metaDataFileParser);
instance.Create();
}
@@ -65,7 +66,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, null);
+ var converter = new AnimationBinWh3FileToXmlConverter(null, _metaDataFileParser, null);
foreach (var animFile in animPackFile.Files)
{
if (animFile is AnimationBinWh3)
@@ -86,8 +87,7 @@ public void Create()
if (data.Length == 0)
continue;
- var parser = new MetaDataFileParser();
- var metaData = parser.ParseFile(data, _metaDataTagDeSerializer);
+ var metaData = _metaDataFileParser.ParseFile(data);
DumpAsJson(gameOutputDir, fileName + ".json", metaData);
}
catch (Exception e)
diff --git a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs
index 487a19cf7..8666320f7 100644
--- a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs
+++ b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs
@@ -32,18 +32,18 @@ class FileReport
private readonly IPackFileService _pfs;
private readonly ApplicationSettingsService _settingsService;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
+ private readonly MetaDataFileParser _metaDataFileParser;
- public AnimMetaDataReportGenerator(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public AnimMetaDataReportGenerator(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataFileParser metaDataFileParser)
{
_pfs = pfs;
_settingsService = settingsService;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
+ _metaDataFileParser = metaDataFileParser;
}
- public static void Generate(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public static void Generate(IPackFileService pfs, ApplicationSettingsService settingsService, MetaDataFileParser metaDataFileParser)
{
- var instance = new AnimMetaDataReportGenerator(pfs, settingsService, metaDataTagDeSerializer);
+ var instance = new AnimMetaDataReportGenerator(pfs, settingsService, metaDataFileParser);
instance.Create();
}
@@ -63,7 +63,7 @@ public void Create()
var fileList = PackFileServiceUtility.FindAllWithExtentionIncludePaths(_pfs, ".meta");
var failedFiles = new List();
- var metaTable = new List<(string Path, MetaDataFile File)>();
+ var metaTable = new List<(string Path, ParsedMetadataFile File)>();
for (var i = 0; i < fileList.Count; i++)
{
var fileName = fileList[i].FileName;
@@ -77,12 +77,12 @@ public void Create()
if (data.Length == 0)
continue;
- var parser = new MetaDataFileParser();
- var metaData = parser.ParseFile(data, _metaDataTagDeSerializer);
+
+ var metaData = _metaDataFileParser.ParseFile(data);
metaTable.Add((fileName, metaData));
var completedTags = 0;
- foreach (var item in metaData.Items)
+ foreach (var item in metaData.Attributes)
{
var tagName = item.DisplayName;
tagName = tagName.ToLower();
@@ -92,7 +92,7 @@ public void Create()
try
{
- var variables = _metaDataTagDeSerializer.DeSerializeToStrings(item, out var errorMessage);
+ var variables = _metaDataFileParser.DeSerializeToStrings(item, out var errorMessage);
if (variables != null)
{
@@ -122,7 +122,7 @@ public void Create()
}
}
- _logger.Here().Information($"File processed {i}/{fileList.Count} - {completedTags}/{metaData.Items.Count} tags loaded correctly");
+ _logger.Here().Information($"File processed {i}/{fileList.Count} - {completedTags}/{metaData.Attributes.Count} tags loaded correctly");
}
catch
{
diff --git a/Editors/Shared/Editors.Shared.Core/Common/IMetaDataInstance.cs b/Editors/Shared/Editors.Shared.Core/Common/IMetaDataInstance.cs
new file mode 100644
index 000000000..833297dae
--- /dev/null
+++ b/Editors/Shared/Editors.Shared.Core/Common/IMetaDataInstance.cs
@@ -0,0 +1,9 @@
+namespace Editors.Shared.Core.Common
+{
+ public interface IMetaDataInstance
+ {
+ void CleanUp();
+ void Update(float currentTime);
+ GameWorld.Core.Animation.AnimationPlayer Player { get; }
+ }
+}
diff --git a/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/BinAnimationViewModel.cs b/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/BinAnimationViewModel.cs
index 4630426f7..5a63a1528 100644
--- a/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/BinAnimationViewModel.cs
+++ b/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/BinAnimationViewModel.cs
@@ -4,12 +4,12 @@
using GameWorld.Core.Animation;
using GameWorld.Core.Services;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Models;
using Shared.Core.PackFiles.Utility;
using Shared.GameFormats.AnimationPack;
using Shared.Ui.Common;
-using Shared.Ui.Events.UiCommands;
namespace Editors.Shared.Core.Common.ReferenceModel
{
diff --git a/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/SceneObjectViewModel.cs b/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/SceneObjectViewModel.cs
index fe6c9c35b..e543023b7 100644
--- a/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/SceneObjectViewModel.cs
+++ b/Editors/Shared/Editors.Shared.Core/Common/ReferenceModel/SceneObjectViewModel.cs
@@ -1,10 +1,8 @@
using CommunityToolkit.Mvvm.ComponentModel;
-using Editors.Shared.Core.Services;
using GameWorld.Core.Services;
using Shared.Core.Events;
using Shared.Core.PackFiles;
using Shared.Core.Services;
-using Shared.GameFormats.AnimationMeta.Parsing;
namespace Editors.Shared.Core.Common.ReferenceModel
{
@@ -13,15 +11,13 @@ public partial class SceneObjectViewModel : ObservableObject
private readonly IPackFileService _pfs;
private readonly IStandardDialogs _uiProvider;
private readonly SceneObjectEditor _sceneObjectBuilder;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
- private readonly IMetaDataFactory _metaDataFactory;
[ObservableProperty] string _headerName;
[ObservableProperty] string _subHeaderName;
[ObservableProperty] SceneObject _data;
[ObservableProperty] bool _isVisible = true;
[ObservableProperty] bool _isControlVisible = true;
- [ObservableProperty] bool _allowMetaData = true;
+
[ObservableProperty] bool _isEnabled = true;
[ObservableProperty] bool _isExpand = true;
@@ -30,20 +26,16 @@ public partial class SceneObjectViewModel : ObservableObject
public SceneObjectViewModel(
IUiCommandFactory uiCommandFactory,
- IMetaDataFactory metaDataFactory,
IPackFileService packFileService,
IStandardDialogs uiProvider,
SceneObject data,
string headerName,
SceneObjectEditor sceneObjectBuilder,
- ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper,
- MetaDataTagDeSerializer metaDataTagDeSerializer)
+ ISkeletonAnimationLookUpHelper skeletonAnimationLookUpHelper)
{
- _metaDataFactory = metaDataFactory;
_pfs = packFileService;
_uiProvider = uiProvider;
_sceneObjectBuilder = sceneObjectBuilder;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
Data = data;
HeaderName = headerName;
@@ -52,7 +44,6 @@ public SceneObjectViewModel(
Data.AnimationChanged += (x) => OnSceneObjectChanged();
Data.SkeletonChanged += (x) => OnSceneObjectChanged();
- Data.MetaDataChanged += RecreateMetaDataInformation;
}
partial void OnIsVisibleChanged(bool value)
@@ -83,22 +74,5 @@ public void BrowseMesh()
_sceneObjectBuilder.SetMesh(Data, file);
}
}
-
- // Move this to superveiw!
- void RecreateMetaDataInformation(SceneObject model)
- {
- if (AllowMetaData == false)
- return;
-
- foreach (var item in model.MetaDataItems)
- item.CleanUp();
- model.MetaDataItems.Clear();
- model.Player.AnimationRules.Clear();
-
- var parser = new MetaDataFileParser();
- var persist = parser.ParseFile(model.PersistMetaData, _metaDataTagDeSerializer);
- var meta = parser.ParseFile(model.MetaData, _metaDataTagDeSerializer);
- model.MetaDataItems = _metaDataFactory.Create(persist, meta, model.MainNode, model, model.Player, FragAndSlotSelection.FragmentList.SelectedItem);
- }
}
}
diff --git a/Editors/Shared/Editors.Shared.Core/Common/SceneObject.cs b/Editors/Shared/Editors.Shared.Core/Common/SceneObject.cs
index 369c95cc9..4b65fd06a 100644
--- a/Editors/Shared/Editors.Shared.Core/Common/SceneObject.cs
+++ b/Editors/Shared/Editors.Shared.Core/Common/SceneObject.cs
@@ -1,5 +1,4 @@
-using Editors.Shared.Core.Services;
-using GameWorld.Core.Animation;
+using GameWorld.Core.Animation;
using GameWorld.Core.Components;
using GameWorld.Core.SceneNodes;
using Microsoft.Xna.Framework;
@@ -43,7 +42,6 @@ public class SceneObject : BaseComponent, ISkeletonProvider
public Matrix Offset { get; set; } = Matrix.Identity;
public string Id { get; private set; }
-
// --- UI elements
public NotifyAttr MeshName { get; set; } = new NotifyAttr("");
public NotifyAttr SkeletonName { get; set; } = new NotifyAttr("");
@@ -51,7 +49,6 @@ public class SceneObject : BaseComponent, ISkeletonProvider
public NotifyAttr ShowMesh { get; set; }
public NotifyAttr ShowSkeleton { get; set; }
-
public SceneObject(string uniqeId) : base()
{
Id = uniqeId;
diff --git a/Editors/Shared/Editors.Shared.Core/Common/SceneObjectEditor.cs b/Editors/Shared/Editors.Shared.Core/Common/SceneObjectEditor.cs
index 4475fc25f..2a6b5a9bb 100644
--- a/Editors/Shared/Editors.Shared.Core/Common/SceneObjectEditor.cs
+++ b/Editors/Shared/Editors.Shared.Core/Common/SceneObjectEditor.cs
@@ -1,10 +1,8 @@
-using Editors.Shared.Core.Common;
-using GameWorld.Core.Animation;
+using GameWorld.Core.Animation;
using GameWorld.Core.Components;
using GameWorld.Core.SceneNodes;
using GameWorld.Core.Services;
using GameWorld.Core.Utility;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Xna.Framework;
using Serilog;
using Shared.Core.ErrorHandling;
diff --git a/Editors/Shared/Editors.Shared.Core/Common/SceneObjectViewModelBuilder.cs b/Editors/Shared/Editors.Shared.Core/Common/SceneObjectViewModelBuilder.cs
index bb318eeef..bb9825486 100644
--- a/Editors/Shared/Editors.Shared.Core/Common/SceneObjectViewModelBuilder.cs
+++ b/Editors/Shared/Editors.Shared.Core/Common/SceneObjectViewModelBuilder.cs
@@ -1,52 +1,43 @@
using Editors.Shared.Core.Common.AnimationPlayer;
using Editors.Shared.Core.Common.BaseControl;
using Editors.Shared.Core.Common.ReferenceModel;
-using Editors.Shared.Core.Services;
using GameWorld.Core.Services;
using Microsoft.Xna.Framework;
using Shared.Core.Events;
using Shared.Core.PackFiles;
using Shared.Core.Services;
-using Shared.GameFormats.AnimationMeta.Parsing;
namespace Editors.Shared.Core.Common
{
public class SceneObjectViewModelBuilder
{
private readonly AnimationPlayerViewModel _animationPlayerViewModel;
- private readonly IMetaDataFactory _metaDataFactory;
private readonly SceneObjectEditor _sceneObjectEditor;
private readonly IPackFileService _pfs;
private readonly ISkeletonAnimationLookUpHelper _skeletonHelper;
private readonly IUiCommandFactory _uiCommandFactory;
private readonly IStandardDialogs _packFileUiProvider;
- private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer;
public SceneObjectViewModelBuilder(
AnimationPlayerViewModel animationPlayerViewModel,
- IMetaDataFactory metaDataFactory,
SceneObjectEditor assetViewModelBuilder,
IPackFileService pfs,
ISkeletonAnimationLookUpHelper skeletonHelper,
IUiCommandFactory uiCommandFactory,
- IStandardDialogs packFileUiProvider,
- MetaDataTagDeSerializer metaDataTagDeSerializer)
+ IStandardDialogs packFileUiProvider)
{
_animationPlayerViewModel = animationPlayerViewModel;
- _metaDataFactory = metaDataFactory;
_sceneObjectEditor = assetViewModelBuilder;
_pfs = pfs;
_skeletonHelper = skeletonHelper;
_uiCommandFactory = uiCommandFactory;
_packFileUiProvider = packFileUiProvider;
- _metaDataTagDeSerializer = metaDataTagDeSerializer;
}
- public SceneObjectViewModel CreateAsset(string uniqeId, bool createByDefault, string header, Color skeletonColour, AnimationToolInput input, bool allowMetaData = false)
+ public SceneObjectViewModel CreateAsset(string uniqeId, bool createByDefault, string header, Color skeletonColour, AnimationToolInput input)
{
var mainAsset = _sceneObjectEditor.CreateAsset(uniqeId, header, skeletonColour);
- var returnObj = new SceneObjectViewModel(_uiCommandFactory, _metaDataFactory, _pfs, _packFileUiProvider, mainAsset, header + ":", _sceneObjectEditor, _skeletonHelper, _metaDataTagDeSerializer);
- returnObj.AllowMetaData = allowMetaData;
+ var returnObj = new SceneObjectViewModel(_uiCommandFactory, _pfs, _packFileUiProvider, mainAsset, header + ":", _sceneObjectEditor, _skeletonHelper);
if (createByDefault)
{
diff --git a/Editors/Shared/Editors.Shared.Core/Editors.Shared.Core.csproj b/Editors/Shared/Editors.Shared.Core/Editors.Shared.Core.csproj
index 3dd5794a2..2a6376463 100644
--- a/Editors/Shared/Editors.Shared.Core/Editors.Shared.Core.csproj
+++ b/Editors/Shared/Editors.Shared.Core/Editors.Shared.Core.csproj
@@ -1,11 +1,11 @@
-
- net10.0-windows
- enable
- enable
- true
-
+
+ net10.0-windows
+ enable
+ true
+ enable
+
diff --git a/Editors/Shared/Editors.Shared.Core/Services/IMetaDataFactory.cs b/Editors/Shared/Editors.Shared.Core/Services/IMetaDataFactory.cs
deleted file mode 100644
index a02197bbd..000000000
--- a/Editors/Shared/Editors.Shared.Core/Services/IMetaDataFactory.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using GameWorld.Core.Animation;
-using GameWorld.Core.SceneNodes;
-using Shared.GameFormats.AnimationMeta.Parsing;
-using Shared.GameFormats.AnimationPack;
-
-namespace Editors.Shared.Core.Services
-{
- public interface IMetaDataInstance
- {
- void CleanUp();
- void Update(float currentTime);
- AnimationPlayer Player { get; }
- }
-
- public interface IMetaDataFactory
- {
- List Create(MetaDataFile persistent, MetaDataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment);
- }
-
-}
diff --git a/Editors/SkeletonEditor/Test.SkeletonEditor/SkeletonTool_ComplexUsecase.cs b/Editors/SkeletonEditor/Test.SkeletonEditor/SkeletonTool_ComplexUsecase.cs
index 437b04b58..854ddbdec 100644
--- a/Editors/SkeletonEditor/Test.SkeletonEditor/SkeletonTool_ComplexUsecase.cs
+++ b/Editors/SkeletonEditor/Test.SkeletonEditor/SkeletonTool_ComplexUsecase.cs
@@ -1,10 +1,10 @@
using Editor.VisualSkeletonEditor.SkeletonEditor;
using Editors.Shared.Core.Common.ReferenceModel;
using Moq;
+using Shared.Core.Events.Global;
using Shared.Core.Services;
using Shared.Core.ToolCreation;
using Shared.GameFormats.Animation;
-using Shared.Ui.Events.UiCommands;
using Test.TestingUtility.Shared;
using Test.TestingUtility.TestUtility;
diff --git a/Editors/TextureEditor/DevConfig/Texture_Karl.cs b/Editors/TextureEditor/DevConfig/Texture_Karl.cs
index c3741dc0b..d50766aac 100644
--- a/Editors/TextureEditor/DevConfig/Texture_Karl.cs
+++ b/Editors/TextureEditor/DevConfig/Texture_Karl.cs
@@ -1,10 +1,10 @@
using Shared.Core.DevConfig;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Utility;
using Shared.Core.Settings;
using Shared.EmbeddedResources;
-using Shared.Ui.Events.UiCommands;
namespace Editors.TextureEditor.DevConfig
{
diff --git a/GameWorld/View3D/Animation/AnimationSampler.cs b/GameWorld/View3D/Animation/AnimationSampler.cs
index 8c0713907..dbe045ce1 100644
--- a/GameWorld/View3D/Animation/AnimationSampler.cs
+++ b/GameWorld/View3D/Animation/AnimationSampler.cs
@@ -1,11 +1,7 @@
using GameWorld.Core.Animation.AnimationChange;
using Microsoft.Xna.Framework;
-using Serilog;
using Shared.Core.ErrorHandling;
using Shared.Core.Misc;
-using System;
-using System.Collections.Generic;
-using System.Linq;
namespace GameWorld.Core.Animation
{
@@ -49,7 +45,7 @@ public static AnimationFrame Sample(int frameIndex, float frameIterpolation, Gam
}
// Apply animation rules
- if (animationChangeRules != null)
+ if (animationChangeRules != null && animationClip != null)
{
foreach (var rule in animationChangeRules.OfType())
rule.TransformFrameWorldSpace(currentFrame, animationClip.PlayTimeInSec);
diff --git a/GameWorld/View3D/Components/AnimationsContainerComponent.cs b/GameWorld/View3D/Components/AnimationsContainerComponent.cs
index 0a6b16bbe..e0b685f93 100644
--- a/GameWorld/View3D/Components/AnimationsContainerComponent.cs
+++ b/GameWorld/View3D/Components/AnimationsContainerComponent.cs
@@ -27,7 +27,7 @@ public void Remove(AnimationPlayer player)
_playerMap.Remove(item.First().Key);
}
- public AnimationPlayer Get(string name)
+ public AnimationPlayer? Get(string name)
{
var hasKey = _playerMap.ContainsKey(name);
if (!hasKey)
diff --git a/GameWorld/View3D/Rendering/LineMeshRender.cs b/GameWorld/View3D/Rendering/LineMeshRender.cs
index 96f9fe03d..990a14251 100644
--- a/GameWorld/View3D/Rendering/LineMeshRender.cs
+++ b/GameWorld/View3D/Rendering/LineMeshRender.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Shared.Core.Misc;
@@ -127,6 +124,20 @@ public static VertexPositionColor[] AddLocator(Vector3 pos, float size, Color co
return vertices;
}
+ public static VertexPositionColor[] AddRgbLocator(Vector3 pos, float size)
+ {
+ var vertices = new VertexPositionColor[6];
+ var halfLength = size / 2;
+ vertices[0] = new VertexPositionColor(pos + new Vector3(-halfLength, 0, 0), Color.Red);
+ vertices[1] = new VertexPositionColor(pos + new Vector3(halfLength, 0, 0), Color.Red);
+ vertices[2] = new VertexPositionColor(pos + new Vector3(0, -halfLength, 0), Color.Green);
+ vertices[3] = new VertexPositionColor(pos + new Vector3(0, halfLength, 0), Color.Green);
+ vertices[4] = new VertexPositionColor(pos + new Vector3(0, 0, -halfLength), Color.Blue);
+ vertices[5] = new VertexPositionColor(pos + new Vector3(0, 0, halfLength), Color.Blue);
+
+ return vertices;
+ }
+
private static IEnumerable<(int, float, float)> CircleAnglesGenerator(int steps = 20)
{
var stepSize = 2 * MathF.PI / steps;
diff --git a/GameWorld/View3D/Rendering/RenderItems/WorldTextRenderItem.cs b/GameWorld/View3D/Rendering/RenderItems/WorldTextRenderItem.cs
index 4c9c2b6be..7a3c61af4 100644
--- a/GameWorld/View3D/Rendering/RenderItems/WorldTextRenderItem.cs
+++ b/GameWorld/View3D/Rendering/RenderItems/WorldTextRenderItem.cs
@@ -1,5 +1,4 @@
using GameWorld.Core.Components.Rendering;
-using GameWorld.Core.Services;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -8,7 +7,7 @@ namespace GameWorld.Core.Rendering.RenderItems
public class WorldTextRenderItem : IRenderItem
{
Vector3 _pos;
-
+ private readonly Color _color;
readonly RenderEngineComponent _resourceLib;
readonly string _text;
public Matrix ModelMatrix { get; set; } = Matrix.Identity;
@@ -18,11 +17,19 @@ public WorldTextRenderItem(RenderEngineComponent resourceLib, string text, Vecto
_resourceLib = resourceLib;
_text = text;
_pos = pos;
+ _color = Color.Red;
+ }
+
+ public WorldTextRenderItem(RenderEngineComponent resourceLib, string text, Vector3 pos, Color color)
+ {
+ _resourceLib = resourceLib;
+ _text = text;
+ _pos = pos;
+ _color = color;
}
public void Draw(GraphicsDevice device, CommonShaderParameters parameters, RenderingTechnique renderingTechnique)
{
- var colour = Color.Red;
float x = 1;
var measure = _resourceLib.DefaultFont.MeasureString(_text);
@@ -33,7 +40,7 @@ public void Draw(GraphicsDevice device, CommonShaderParameters parameters, Rende
var scale = 1.0f / (_pos - parameters.CameraPosition).Length();
x = 0;
- _resourceLib.CommonSpriteBatch.DrawString(_resourceLib.DefaultFont, _text, centeredPosition + new Vector2(measure.X * 0.5f, measure.Y * 0.5f), colour, x, new Vector2(measure.X * 0.5f, measure.Y * 0.5f), scale * 5, SpriteEffects.None, 0.99f);
+ _resourceLib.CommonSpriteBatch.DrawString(_resourceLib.DefaultFont, _text, centeredPosition + new Vector2(measure.X * 0.5f, measure.Y * 0.5f), _color, x, new Vector2(measure.X * 0.5f, measure.Y * 0.5f), scale * 5, SpriteEffects.None, 0.99f);
x += 0.05f;
}
}
diff --git a/GameWorld/View3D/SceneNodes/SceneNode.cs b/GameWorld/View3D/SceneNodes/SceneNode.cs
index eee822408..46b75b7fa 100644
--- a/GameWorld/View3D/SceneNodes/SceneNode.cs
+++ b/GameWorld/View3D/SceneNodes/SceneNode.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using GameWorld.Core.Components;
+using GameWorld.Core.Components;
using Microsoft.Xna.Framework;
using Shared.Core.Misc;
diff --git a/GameWorld/View3D/SceneNodes/SimpleDrawableNode.cs b/GameWorld/View3D/SceneNodes/SimpleDrawableNode.cs
index 5332814fe..169d132e5 100644
--- a/GameWorld/View3D/SceneNodes/SimpleDrawableNode.cs
+++ b/GameWorld/View3D/SceneNodes/SimpleDrawableNode.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using GameWorld.Core.Components.Rendering;
+using GameWorld.Core.Components.Rendering;
using GameWorld.Core.Rendering.RenderItems;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
diff --git a/GameWorld/View3D/Utility/UserInterface/ShaderTextureViewModel.cs b/GameWorld/View3D/Utility/UserInterface/ShaderTextureViewModel.cs
index 0ab8c43d6..48c42390d 100644
--- a/GameWorld/View3D/Utility/UserInterface/ShaderTextureViewModel.cs
+++ b/GameWorld/View3D/Utility/UserInterface/ShaderTextureViewModel.cs
@@ -9,9 +9,9 @@
using GameWorld.Core.Rendering.Materials.Capabilities.Utility;
using GameWorld.Core.Services;
using Shared.Core.Events;
+using Shared.Core.Events.Global;
using Shared.Core.PackFiles;
using Shared.Core.Services;
-using Shared.Ui.Events.UiCommands;
namespace GameWorld.Core.Utility.UserInterface
{
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/BoolParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/BoolParser.cs
index c0e02747b..2b3ffa0bd 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/BoolParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/BoolParser.cs
@@ -79,5 +79,37 @@ public object GetValueAsObject(byte[] buffer, int index, out int bytesRead)
return value;
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (value is bool b)
+ {
+ var bytes = EncodeValue(b, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ if (value is string s)
+ {
+ var bytes = Encode(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ try
+ {
+ var converted = Convert.ToBoolean(value);
+ var bytes = EncodeValue(converted, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to convert object to Boolean", ex);
+ }
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs
index 76251bcea..8f8d27d30 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs
@@ -30,6 +30,8 @@ public interface IByteParser
bool TryDecode(byte[] buffer, int index, out string value, out int bytesRead, out string? error);
bool CanDecode(byte[] buffer, int index, out int bytesRead, out string? error);
byte[]? Encode(string value, out string? error);
+ byte[] Encode(object value);
+
object GetValueAsObject(byte[] buffer, int index, out int bytesRead);
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IntParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IntParser.cs
index a2f385cee..62ee9ef8f 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IntParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IntParser.cs
@@ -28,5 +28,36 @@ protected override int Decode(byte[] buffer, int index)
return EncodeValue(spesificValue, out error);
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null) throw new ArgumentNullException(nameof(value));
+
+ if (value is int i)
+ {
+ var bytes = EncodeValue(i, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ if (value is string s)
+ {
+ var bytes = Encode(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ try
+ {
+ var converted = Convert.ToInt32(value);
+ var bytes = EncodeValue(converted, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to convert object to Int32", ex);
+ }
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/NumberParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/NumberParser.cs
index 9d3c6e6d0..460a8bf3e 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/NumberParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/NumberParser.cs
@@ -53,5 +53,33 @@ public object GetValueAsObject(byte[] buffer, int index, out int bytesRead)
var value = Decode(buffer, index) as object;
return value!;
}
+
+ public virtual byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ // If already the correct type, use it
+ if (value is T t)
+ {
+ var bytes = EncodeValue(t, out var error);
+ if (bytes == null)
+ throw new Exception(error);
+ return bytes;
+ }
+
+ try
+ {
+ var converted = (T)Convert.ChangeType(value, typeof(T));
+ var bytes = EncodeValue(converted, out var error);
+ if (bytes == null)
+ throw new Exception(error);
+ return bytes;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Unable to convert object to {typeof(T).Name}", ex);
+ }
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/StringParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/StringParser.cs
index fd514df80..66efcf756 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/StringParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/StringParser.cs
@@ -177,6 +177,31 @@ public object GetValueAsObject(byte[] buffer, int index, out int bytesRead)
return value;
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (value is string s)
+ {
+ var bytes = EncodeValue(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ try
+ {
+ var converted = Convert.ToString(value);
+ var bytes = EncodeValue(converted!, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to convert object to String", ex);
+ }
+ }
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/UIntParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/UIntParser.cs
index 877f551d3..584507d3c 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/UIntParser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/UIntParser.cs
@@ -28,5 +28,37 @@ protected override uint Decode(byte[] buffer, int index)
return EncodeValue(spesificValue, out error);
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (value is uint v)
+ {
+ var bytes = EncodeValue(v, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ if (value is string s)
+ {
+ var bytes = Encode(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ try
+ {
+ var converted = Convert.ToUInt32(value);
+ var bytes = EncodeValue(converted, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to convert object to UInt32", ex);
+ }
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector3Parser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector3Parser.cs
index 40eebbdac..4eecaa4cd 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector3Parser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector3Parser.cs
@@ -87,5 +87,27 @@ public object GetValueAsObject(byte[] buffer, int index, out int bytesRead)
return value;
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (value is Vector3 v)
+ {
+ var bytes = EncodeValue(v, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ if (value is string s)
+ {
+ var bytes = Encode(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ throw new Exception("Unable to convert object to Vector3");
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector4Parser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector4Parser.cs
index 03f6af23e..0781e8d29 100644
--- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector4Parser.cs
+++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/Vector4Parser.cs
@@ -98,5 +98,27 @@ public object GetValueAsObject(byte[] buffer, int index, out int bytesRead)
return value;
}
+
+ public byte[] Encode(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (value is Vector4 v)
+ {
+ var bytes = EncodeValue(v, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ if (value is string s)
+ {
+ var bytes = Encode(s, out var error);
+ if (bytes == null) throw new Exception(error);
+ return bytes;
+ }
+
+ throw new Exception("Unable to convert object to Vector4");
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedAciiStringParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedAciiStringParserTest.cs
new file mode 100644
index 000000000..e96841e7e
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedAciiStringParserTest.cs
@@ -0,0 +1,44 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+using System.Text;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class FixedAciiStringParserTest
+ {
+ [Test]
+ public void TryDecodeValue_Succeeds_ForValidAscii()
+ {
+ var parser = new FixedAciiStringParser(4);
+ var buffer = Encoding.ASCII.GetBytes("ABCD");
+
+ var ok = parser.TryDecodeValue(buffer, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(4));
+ Assert.That(value, Is.EqualTo("ABCD"));
+ }
+
+ [Test]
+ public void TryDecodeValue_Fails_WhenBufferTooSmall()
+ {
+ var parser = new FixedAciiStringParser(4);
+ var buffer = new byte[3];
+
+ var ok = parser.TryDecodeValue(buffer, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.False);
+ Assert.That(error, Is.Not.Null);
+ Assert.That(bytesRead, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void Encode_Throws_NotImplemented()
+ {
+ var parser = new FixedAciiStringParser(4);
+ Assert.Throws(() => parser.Encode((object)"ABCD"));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedStringParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedStringParserTest.cs
new file mode 100644
index 000000000..241daabdc
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedStringParserTest.cs
@@ -0,0 +1,31 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+using System.Text;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class FixedStringParserTest
+ {
+ [Test]
+ public void TryDecodeValue_Succeeds_ForValidUnicode()
+ {
+ var parser = new FixedStringParser(4);
+ var buffer = Encoding.Unicode.GetBytes("ABCD");
+
+ var ok = parser.TryDecodeValue(buffer, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(8));
+ Assert.That(value, Is.EqualTo("ABCD"));
+ }
+
+ [Test]
+ public void Encode_Throws_NotImplemented()
+ {
+ var parser = new FixedStringParser(4);
+ Assert.Throws(() => parser.Encode((object)"ABCD"));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/IntParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/IntParserTest.cs
index 924a7f00f..5e92f88a9 100644
--- a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/IntParserTest.cs
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/IntParserTest.cs
@@ -67,5 +67,24 @@ public void TryDecodeValue_Fails_WhenBufferTooSmall()
Assert.That(error, Is.Not.Null);
Assert.That(bytesRead, Is.EqualTo(0));
}
+
+ [TestCase(0)]
+ [TestCase(1)]
+ [TestCase(-1)]
+ [TestCase(123456)]
+ public void EncodeObject_RoundTrips(int input)
+ {
+ var parser = new IntParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(4));
+ Assert.That(value, Is.EqualTo(input));
+ }
}
}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/ShortParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/ShortParserTest.cs
new file mode 100644
index 000000000..efdfde741
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/ShortParserTest.cs
@@ -0,0 +1,28 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class ShortParserTest
+ {
+ [TestCase((short)0)]
+ [TestCase((short)1)]
+ [TestCase((short)-1)]
+ [TestCase((short)12345)]
+ public void EncodeObject_RoundTrips(short input)
+ {
+ var parser = new ShortParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(2));
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/SingleParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/SingleParserTest.cs
new file mode 100644
index 000000000..d7c2c6285
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/SingleParserTest.cs
@@ -0,0 +1,27 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class SingleParserTest
+ {
+ [TestCase(0.0f)]
+ [TestCase(1.5f)]
+ [TestCase(-2.25f)]
+ public void EncodeObject_RoundTrips(float input)
+ {
+ var parser = new SingleParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(4));
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/StringParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/StringParserTest.cs
new file mode 100644
index 000000000..ebac79ee6
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/StringParserTest.cs
@@ -0,0 +1,25 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class StringParserTest
+ {
+ [Test]
+ public void EncodeObject_RoundTrips()
+ {
+ var parser = new StringParser();
+ var input = "hello";
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UInt64ParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UInt64ParserTest.cs
new file mode 100644
index 000000000..dda92dd94
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UInt64ParserTest.cs
@@ -0,0 +1,27 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class UIntParserTests
+ {
+ [TestCase((uint)0)]
+ [TestCase((uint)1)]
+ [TestCase((uint)123456)]
+ public void EncodeObject_RoundTrips(uint input)
+ {
+ var parser = new UIntParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(4));
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UIntParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UIntParserTest.cs
new file mode 100644
index 000000000..bdfda5e6d
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UIntParserTest.cs
@@ -0,0 +1,27 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class UIntParserTest
+ {
+ [TestCase(0u)]
+ [TestCase(1u)]
+ [TestCase(123456u)]
+ public void EncodeObject_RoundTrips(uint input)
+ {
+ var parser = new UIntParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(4));
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UShortParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UShortParserTest.cs
new file mode 100644
index 000000000..22c54a448
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UShortParserTest.cs
@@ -0,0 +1,27 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class UShortParserTest
+ {
+ [TestCase((ushort)0)]
+ [TestCase((ushort)1)]
+ [TestCase((ushort)65535)]
+ public void EncodeObject_RoundTrips(ushort input)
+ {
+ var parser = new UShortParser();
+ var bytes = parser.Encode((object)input);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(2));
+ Assert.That(value, Is.EqualTo(input));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector3ParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector3ParserTest.cs
new file mode 100644
index 000000000..cf180b938
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector3ParserTest.cs
@@ -0,0 +1,44 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+using Vector3 = Microsoft.Xna.Framework.Vector3;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class Vector3ParserTest
+ {
+ [Test]
+ public void EncodeObject_RoundTrips_FromObject()
+ {
+ var parser = new Vector3Parser();
+ var vec = new Vector3(1.0f, 2.0f, 3.0f);
+ var bytes = parser.Encode((object)vec);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(12));
+ Assert.That(value, Is.EqualTo(vec));
+ }
+
+ [Test]
+ public void EncodeObject_RoundTrips_FromString()
+ {
+ var parser = new Vector3Parser();
+ var str = "1|2|3";
+ var bytes = parser.Encode((object)str);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(12));
+ Assert.That(value, Is.EqualTo(new Vector3(1,2,3)));
+ }
+ }
+}
diff --git a/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector4ParserTest.cs b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector4ParserTest.cs
new file mode 100644
index 000000000..344b63e1f
--- /dev/null
+++ b/Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector4ParserTest.cs
@@ -0,0 +1,44 @@
+using NUnit.Framework;
+using Shared.ByteParsing.Parsers;
+using Vector4 = Microsoft.Xna.Framework.Vector4;
+
+namespace Shared.ByteParsingTest.Parsers
+{
+ [TestFixture]
+ public class Vector4ParserTest
+ {
+ [Test]
+ public void EncodeObject_RoundTrips_FromObject()
+ {
+ var parser = new Vector4Parser();
+ var vec = new Vector4(1.0f, 2.0f, 3.0f, 4.0f);
+ var bytes = parser.Encode((object)vec);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(16));
+ Assert.That(value, Is.EqualTo(vec));
+ }
+
+ [Test]
+ public void EncodeObject_RoundTrips_FromString()
+ {
+ var parser = new Vector4Parser();
+ var str = "1|2|3|4";
+ var bytes = parser.Encode((object)str);
+
+ Assert.That(bytes, Is.Not.Null);
+
+ var ok = parser.TryDecodeValue(bytes, 0, out var value, out var bytesRead, out var error);
+
+ Assert.That(ok, Is.True);
+ Assert.That(error, Is.Null);
+ Assert.That(bytesRead, Is.EqualTo(16));
+ Assert.That(value, Is.EqualTo(new Vector4(1,2,3,4)));
+ }
+ }
+}
diff --git a/Shared/GameFiles/AnimationMeta/Definitions/AnimatedProp.cs b/Shared/GameFiles/AnimationMeta/Definitions/AnimatedProp.cs
index baedc5718..9e4855754 100644
--- a/Shared/GameFiles/AnimationMeta/Definitions/AnimatedProp.cs
+++ b/Shared/GameFiles/AnimationMeta/Definitions/AnimatedProp.cs
@@ -1,8 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework;
using Shared.GameFormats.AnimationMeta.Parsing;
namespace Shared.GameFormats.AnimationMeta.Definitions
diff --git a/Shared/GameFiles/AnimationMeta/Definitions/DisablePersistant.cs b/Shared/GameFiles/AnimationMeta/Definitions/DisablePersistant.cs
index ff90b59d3..2cf6fee61 100644
--- a/Shared/GameFiles/AnimationMeta/Definitions/DisablePersistant.cs
+++ b/Shared/GameFiles/AnimationMeta/Definitions/DisablePersistant.cs
@@ -1,8 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Shared.GameFormats.AnimationMeta.Parsing;
+using Shared.GameFormats.AnimationMeta.Parsing;
namespace Shared.GameFormats.AnimationMeta.Definitions
{
diff --git a/Shared/GameFiles/AnimationMeta/Definitions/DockEquipment.cs b/Shared/GameFiles/AnimationMeta/Definitions/DockEquipment.cs
index 5adf98ebe..4e7488c24 100644
--- a/Shared/GameFiles/AnimationMeta/Definitions/DockEquipment.cs
+++ b/Shared/GameFiles/AnimationMeta/Definitions/DockEquipment.cs
@@ -1,11 +1,22 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Shared.GameFormats.AnimationMeta.Parsing;
+using Shared.GameFormats.AnimationMeta.Parsing;
namespace Shared.GameFormats.AnimationMeta.Definitions
{
+ public abstract class DockEquipment : DecodedMetaEntryBase
+ {
+ [MetaDataTag(5, "0=\"Weapon Bone 1\" in .frg but \"be_prop_0\" in a typical VMD. 1=\"Weapon Bone 2\" in .frg but \"be_prop_1\" in VMD. etc.")]
+ public int PropBoneId { get; set; }
+
+ [MetaDataTag(6)]
+ public float BlendInTime { get; set; }
+
+ [MetaDataTag(7)]
+ public float BlendOutTime { get; set; }
+
+ public virtual string AnimationSlotName { get; } = "";
+ public virtual string[] SkeletonNameAlternatives { get; } = new string[] { "" };
+ }
+
public abstract class DockEquipment_v0 : DecodedMetaEntryBase_v0
{
@@ -46,20 +57,7 @@ public abstract class DockEquipment_v3 : DockEquipment_v2
public float BlendOutTime { get; set; }
}
- public abstract class DockEquipment : DecodedMetaEntryBase
- {
- [MetaDataTag(5, "0=\"Weapon Bone 1\" in .frg but \"be_prop_0\" in a typical VMD. 1=\"Weapon Bone 2\" in .frg but \"be_prop_1\" in VMD. etc.")]
- public int PropBoneId { get; set; }
-
- [MetaDataTag(6)]
- public float BlendInTime { get; set; }
-
- [MetaDataTag(7)]
- public float BlendOutTime { get; set; }
-
- public virtual string AnimationSlotName { get; } = "";
- public virtual string[] SkeletonNameAlternatives { get; } = new string[] { "" };
- }
+
///
/// Dock right hand
diff --git a/Shared/GameFiles/AnimationMeta/Definitions/Effect.cs b/Shared/GameFiles/AnimationMeta/Definitions/Effect.cs
index 904ef0809..968991709 100644
--- a/Shared/GameFiles/AnimationMeta/Definitions/Effect.cs
+++ b/Shared/GameFiles/AnimationMeta/Definitions/Effect.cs
@@ -1,15 +1,21 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework;
using Shared.GameFormats.AnimationMeta.Parsing;
namespace Shared.GameFormats.AnimationMeta.Definitions
{
- public interface IEffectMeta
+ public interface IEffectMeta
{
public string VfxName { get; set; }
+ public int NodeIndex { get; set; }
+ public bool Tracking { get; set; }
+ public Vector3 Position { get; set; }
+
+ public Vector4 Orientation { get; set; }
+
+ public float EffectStartTime { get; set; }
+ public float EffectEndTime { get; set; }
+
+
}
[MetaData("EFFECT", 1)]
@@ -29,6 +35,12 @@ public class Effect_v1 : DecodedMetaEntryBase_v1, IEffectMeta
[MetaDataTag(7, "Bone the effect is attached to, use -1 for it to just spawn and not follow animations")]
public int NodeIndex { get; set; }
+
+ // Part of the inteface - not the metedata file
+ public bool Tracking { get; set; } = false;
+ public float EffectStartTime { get => 0; set; }
+ public float EffectEndTime { get => 0; set; }
+
}
[MetaData("EFFECT", 2)]
@@ -48,6 +60,11 @@ public class Effect_v2 : DecodedMetaEntryBase_v2, IEffectMeta
[MetaDataTag(8, "Bone the effect is attached to, use -1 for it to just spawn and not follow animations")]
public int NodeIndex { get; set; }
+
+ // Part of the inteface - not the metedata file
+ public bool Tracking { get; set; } = false;
+ public float EffectStartTime { get => 0; set; }
+ public float EffectEndTime { get => 0; set; }
}
[MetaData("EFFECT", 3)]
@@ -95,6 +112,11 @@ public class Effect_v7 : DecodedMetaEntryBase_v2, IEffectMeta
[MetaDataTag(11, "Scale of the effect")]
public float Scale { get; set; } = 1;
+
+
+ // Part of the inteface - not the metedata file
+ public float EffectStartTime { get => StartTime; set; }
+ public float EffectEndTime { get => EndTime; set; }
}
[MetaData("EFFECT", 11)]
@@ -126,14 +148,63 @@ public class Effect_v11 : DecodedMetaEntryBase, IEffectMeta
[MetaDataTag(13, "Scale of the effect")]
public float Scale { get; set; } = 1;
+
+
+ // Part of the inteface - not the metedata file
+ public float EffectStartTime { get => StartTime; set; }
+ public float EffectEndTime { get => EndTime; set; }
}
[MetaData("EFFECT", 12)]
- public class Effect_v12 : Effect_v11
+ public class Effect_v12 : DecodedMetaEntryBase, IEffectMeta
{
+ [MetaDataTag(5, "Name of the VFX's .xml file in the vfx folder. Leave off the file extension. Note that for this you don't need to add custom vfx to the particles db table and they still require a \"movie\"-type .pack for them to be loaded.")]
+ public string VfxName { get; set; } = "";
+
+ [MetaDataTag(6, "normal(0), ability_aura(1), ability_weapon(2)")]
+ public int EffectType { get; set; }
+
+ [MetaDataTag(7)]
+ public bool Tracking { get; set; }
+
+ [MetaDataTag(8, "Does the effect crash with the terrain?")]
+ public bool TerrainMutable { get; set; }
+
+ [MetaDataTag(9)]
+ public bool DistanceCulled { get; set; }
+
// new field
[MetaDataTag(10)]
- public bool ScalesWithParent { get; set; }
+ public bool ScalesWithParent { get; set; }
+
+ [MetaDataTag(11)]
+ public Vector3 Position { get; set; } = new Vector3();
+
+ [MetaDataTag(12, "", MetaDataTagAttribute.DisplayType.EulerVector)]
+ public Vector4 Orientation { get; set; } = new Vector4(0, 0, 0, 1);
+
+ [MetaDataTag(13, "Bone the effect is attached to, use -1 for it to just spawn and not follow animations")]
+ public int NodeIndex { get; set; }
+
+ [MetaDataTag(14, "Scale of the effect")]
+ public float Scale { get; set; } = 1;
+
+
+ // Part of the inteface - not the metedata file
+ public float EffectStartTime { get => StartTime; set; }
+ public float EffectEndTime { get => EndTime; set; }
+ }
+
+
+
+
+ /*
+
+
+ [MetaData("EFFECT", 12)]
+ public class Effect_v12_old : Effect_v11
+ {
+
// override order
[MetaDataTag(11)]
@@ -147,5 +218,5 @@ public class Effect_v12 : Effect_v11
[MetaDataTag(14, "Scale of the effect")]
public new float Scale { get; set; } = 1;
- }
+ }*/
}
diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs
similarity index 71%
rename from Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs
rename to Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs
index 91f66052a..21f87dfde 100644
--- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs
+++ b/Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs
@@ -1,20 +1,43 @@
using System.Reflection;
-using Shared.ByteParsing;
namespace Shared.GameFormats.AnimationMeta.Parsing
{
- public class MetaDataTagDeSerializer
+ public interface IMetaDataDatabase
{
+ string GetDescription(string metaDataTagName);
+ string GetDescriptionSafe(string metaDataTagName);
+ List GetSupportedTypes();
+
+ List GetDefinition(string metadataName);
+ }
+
+ public class MetaDataDatabase : IMetaDataDatabase
+ {
+ private bool _isInitialized = false;
private readonly Dictionary> _typeTable = [];
private readonly Dictionary _descriptionMap = [];
- public MetaDataTagDeSerializer()
+ public MetaDataDatabase()
+ {
+
+ }
+
+ public List GetDefinition(string metadataName)
{
EnsureMappingTableCreated();
+
+ var result = _typeTable.TryGetValue(metadataName, out var typeTable);
+ if (result == false || typeTable == null)
+ throw new Exception($"No metadata tags for {metadataName}");
+ return typeTable;
}
- void EnsureMappingTableCreated()
+ public void EnsureMappingTableCreated()
{
+ if (_isInitialized)
+ return;
+
+ _isInitialized = true;
CreateDescriptions();
var typesWithMyAttribute =
@@ -73,6 +96,24 @@ from t in a.GetTypes()
#endif
}
+
+ ParsedMetadataAttribute CreateDefault(string itemName)
+ {
+ EnsureMappingTableCreated();
+
+ if (_typeTable.ContainsKey(itemName) == false)
+ throw new Exception("Unknown metadata item " + itemName);
+
+ var type = _typeTable[itemName].First();
+ var instance = Activator.CreateInstance(type) as ParsedMetadataAttribute;
+
+ var itemNameSplit = itemName.ToUpper().Split("_");
+ instance.Version = int.Parse(itemNameSplit.Last());
+ instance.Name = string.Join("_", itemNameSplit.Take(itemNameSplit.Length - 1));
+ return instance;
+ }
+
+
void CreateDescriptions()
{
_descriptionMap["TIME"] = "Generic time marker";
@@ -177,6 +218,8 @@ void CreateDescriptions()
public string GetDescription(string metaDataTagName)
{
+ EnsureMappingTableCreated();
+
if (_descriptionMap.ContainsKey(metaDataTagName) == false)
throw new Exception($"Unable to get description of {metaDataTagName}");
return _descriptionMap[metaDataTagName];
@@ -184,6 +227,8 @@ public string GetDescription(string metaDataTagName)
public string GetDescriptionSafe(string metaDataTagName)
{
+ EnsureMappingTableCreated();
+
if (_descriptionMap.ContainsKey(metaDataTagName) == false)
return "Missing";
return _descriptionMap[metaDataTagName];
@@ -191,163 +236,14 @@ public string GetDescriptionSafe(string metaDataTagName)
public List GetSupportedTypes()
{
+ EnsureMappingTableCreated();
+
return _typeTable.Select(x => x.Key).ToList();
}
- bool IsSequential(int[] array)
+ static bool IsSequential(int[] array)
{
return array.Zip(array.Skip(1), (a, b) => a + 1 == b).All(x => x);
}
-
- List GetTypesFromMeta(BaseMetaEntry entry)
- {
- var key = entry.Name + "_" + entry.Version;
- if (_typeTable.ContainsKey(key) == false)
- return null;
-
- return _typeTable[key];
- }
-
- public BaseMetaEntry? DeSerialize(UnknownMetaEntry entry, out string? errorMessage)
- {
- var entryInfoList = GetEntryInformation(entry);
- if (entryInfoList == null)
- {
- errorMessage = $"Unable to find decoder for {entry.Name}_{entry.Version}";
- return null;
- }
-
- errorMessage = null;
- foreach (var entryInfo in entryInfoList)
- {
- var instance = Activator.CreateInstance(entryInfo.Type);
- var bytes = entry.Data;
- var currentIndex = 0;
- foreach (var proptery in entryInfo.Properties)
- {
- var parser = ByteParserFactory.Create(proptery.PropertyType);
- try
- {
- var value = parser.GetValueAsObject(bytes, currentIndex, out var bytesRead);
- currentIndex += bytesRead;
- proptery.SetValue(instance, value);
- errorMessage = "";
- }
- catch (Exception e)
- {
- errorMessage = $"Failed to read object - {e.Message} bytes left";
- break;
- }
- }
-
- if (errorMessage != "")
- continue;
-
- var bytesLeft = bytes.Length - currentIndex;
- if (bytesLeft != 0)
- {
- errorMessage = $"Failed to read object - {bytesLeft} bytes left";
- continue;
- }
-
- var typedInstance = instance as BaseMetaEntry;
- typedInstance.Name = entry.Name;
- typedInstance.Data = bytes;
- errorMessage = null;
- return typedInstance;
- }
-
- return null;
- }
-
- public List<(string Header, string Value)>? DeSerializeToStrings(BaseMetaEntry entry, out string? errorMessage)
- {
- var entryInfoList = GetEntryInformation(entry);
- if (entryInfoList == null)
- {
- errorMessage = $"Unable to find decoder for {entry.Name}_{entry.Version}";
- return null;
- }
-
- var bytes = entry.Data;
- var currentIndex = 0;
- var output = new List<(string, string)>();
- errorMessage = null;
-
- foreach (var entryInfo in entryInfoList)
- {
- errorMessage = "";
- foreach (var proptery in entryInfo.Properties)
- {
- var parser = ByteParserFactory.Create(proptery.PropertyType);
- var result = parser.TryDecode(bytes, currentIndex, out var value, out var bytesRead, out var error);
- if (result == false)
- {
- errorMessage = $"Failed to serialize {proptery.Name} - {error}";
- break;
- }
- currentIndex += bytesRead;
- output.Add((proptery.Name, value));
- }
-
- if (errorMessage != "")
- continue;
-
- var bytesLeft = bytes.Length - currentIndex;
- if (bytesLeft != 0)
- {
- errorMessage = $"Failed to read object - {bytesLeft} bytes left";
- continue;
- }
-
- errorMessage = null;
- return output;
- }
-
- return output;
- }
-
- public BaseMetaEntry CreateDefault(string itemName)
- {
- if (_typeTable.ContainsKey(itemName) == false)
- throw new Exception("Unknown metadata item " + itemName);
-
- var type = _typeTable[itemName].First();
- var instance = Activator.CreateInstance(type) as BaseMetaEntry;
-
- var itemNameSplit = itemName.ToUpper().Split("_");
- instance.Version = int.Parse(itemNameSplit.Last());
- instance.Name = string.Join("_", itemNameSplit.Take(itemNameSplit.Length - 1));
- return instance;
- }
-
- List? GetEntryInformation(BaseMetaEntry entry)
- {
- var metaDataTypes = GetTypesFromMeta(entry);
- if (metaDataTypes == null)
- return null;
-
- var output = new List();
- foreach (var metaDataType in metaDataTypes)
- {
- var instance = Activator.CreateInstance(metaDataType);
- var orderedPropertiesList = metaDataType.GetProperties()
- .Where(x => x.CanWrite)
- .Where(x => Attribute.IsDefined(x, typeof(MetaDataTagAttribute)))
- .OrderBy(x => x.GetCustomAttributes(false).Single().Order)
- .ToList();
-
- var entryInfo = new EntryInfoResult() { Type = metaDataType, Properties = orderedPropertiesList };
- output.Add(entryInfo);
- }
-
- return output;
- }
-
- public class EntryInfoResult
- {
- public Type? Type { get; set; }
- public List Properties { get; set; } = new();
- }
}
}
diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs
index 88f90eb1b..774ae3210 100644
--- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs
+++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs
@@ -1,7 +1,10 @@
using System.Diagnostics;
+using System.Reflection;
+using CommunityToolkit.Diagnostics;
using Serilog;
using Shared.ByteParsing;
using Shared.Core.ErrorHandling;
+using Shared.Core.Misc;
using Shared.Core.PackFiles.Models;
namespace Shared.GameFormats.AnimationMeta.Parsing
@@ -9,19 +12,27 @@ namespace Shared.GameFormats.AnimationMeta.Parsing
public class MetaDataFileParser
{
private readonly ILogger _logger = Logging.Create();
+ private readonly IMetaDataDatabase _metaDataDatabase;
- public MetaDataFile? ParseFile(PackFile pf, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public MetaDataFileParser(IMetaDataDatabase metaDataDatabase)
+ {
+ _metaDataDatabase = metaDataDatabase;
+ }
+
+ public IMetaDataDatabase GetDatabase() => _metaDataDatabase;
+
+ public ParsedMetadataFile? ParseFile(PackFile pf)
{
if (pf == null)
return null;
- return ParseFile(pf.DataSource.ReadData(), metaDataTagDeSerializer);
+ return ParseFile(pf.DataSource.ReadData());
}
- public MetaDataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDataTagDeSerializer)
+ public ParsedMetadataFile ParseFile(byte[] fileContent)
{
- var contentLength = fileContent.Count();
+ var contentLength = fileContent.Length;
- var outputFile = new MetaDataFile()
+ var outputFile = new ParsedMetadataFile()
{
Version = BitConverter.ToInt32(fileContent, 0)
};
@@ -29,72 +40,70 @@ public MetaDataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDa
if (outputFile.Version != 2)
throw new Exception($"Unknown version - {outputFile.Version}");
- if (contentLength > 8)
- {
- var expectedElements = BitConverter.ToUInt32(fileContent, 4);
- var items = ExploratoryGetEntries(fileContent);
+ if (contentLength > 8 == false)
+ return outputFile;
- if (Debugger.IsAttached)
- {
- if (expectedElements != items.Count)
- throw new Exception($"Not the expected amount elements. Expected {expectedElements}, got {items.Count}");
- }
+ var expectedAttributeCount = BitConverter.ToUInt32(fileContent, 4);
+ var attributes = GetAttributes(fileContent);
+ Debug.Assert(expectedAttributeCount == attributes.Count, $"Not the expected amount elements. Expected {expectedAttributeCount}, got {attributes.Count}");
- // Convert to sensible stuff
- foreach (var item in items)
+ // Try to convert from UnkownAttribute to KnownAttribute.
+ // If this fails, we keep the unkown in the list as it has the correct byte data.
+ foreach (var attribute in attributes)
+ {
+ try
{
- try
+ var deserializedAttribute = DeSerialize(attribute, out var errorStr);
+ if (deserializedAttribute != null)
{
- var deserializedTag = metaDataTagDeSerializer.DeSerialize(item, out var errorStr);
- if (deserializedTag == null)
- {
- outputFile.Items.Add(item);
- _logger.Here().Error($"Failed to parse tag of type {item.Name}_{item.Version} - {errorStr}");
- }
- else
- {
- outputFile.Items.Add(deserializedTag);
- }
+ outputFile.Attributes.Add(deserializedAttribute);
}
- catch (Exception e)
+ else
{
- _logger.Here().Error($"Failed to parse tag of type {item.Name}_{item.Version} - {e.Message}");
- outputFile.Items.Add(item);
+ outputFile.Attributes.Add(attribute);
+ _logger.Here().Error($"Failed to parse tag of type {attribute.Name}_{attribute.Version} - {errorStr}");
}
}
+ catch (Exception e)
+ {
+ _logger.Here().Error($"Failed to parse tag of type {attribute.Name}_{attribute.Version} - {e.Message}");
+ outputFile.Attributes.Add(attribute);
+ }
}
-
+
return outputFile;
}
- List ExploratoryGetEntries(byte[] fileContent)
+ public byte[] GenerateBytes(int version, ParsedMetadataFile metaFile)
+ {
+ var data = new List();
+ data.AddRange(BitConverter.GetBytes(metaFile.Version));
+ data.AddRange(BitConverter.GetBytes(metaFile.Attributes.Count()));
+ foreach (var item in metaFile.Attributes)
+ {
+ var bytes = Serialize(item, out var errorStr) ;
+ data.AddRange(ByteParsers.String.Encode(item.Name, out _));
+ data.AddRange(bytes);
+ }
+
+ return data.ToArray();
+ }
+
+ List GetAttributes(byte[] fileContent)
{
var byteLength = fileContent.Length;
- var output = new List();
+ var output = new List();
var currentIndex = 0 + 8; // version and num elements
- UnknownMetaEntry currentElement;
- while (currentIndex != byteLength && (currentElement = GetElement(currentIndex, fileContent, out currentIndex)) != null)
+ ParsedUnknownMetadataAttribute currentElement;
+ while (currentIndex != byteLength && (currentElement = GetAttribute(currentIndex, fileContent, out currentIndex)) != null)
output.Add(currentElement);
return output;
}
- public byte[] GenerateBytes(int version, IEnumerable items)
- {
- var data = new List();
- data.AddRange(BitConverter.GetBytes(version));
- data.AddRange(BitConverter.GetBytes(items.Count()));
- foreach (var item in items)
- {
- data.AddRange(ByteParsers.String.Encode(item.Name, out _));
- data.AddRange(item.DataItem.Bytes);
- }
-
- return data.ToArray();
- }
- UnknownMetaEntry GetElement(int startIndex, byte[] data, out int updatedByteIndex)
+ ParsedUnknownMetadataAttribute GetAttribute(int startIndex, byte[] data, out int updatedByteIndex)
{
if (!ByteParsers.String.TryDecode(data, startIndex, out var tagName, out var strBytesRead, out var error))
throw new Exception($"Unable to detect tagname for MetaData element starting at {startIndex} - {error}");
@@ -103,7 +112,7 @@ UnknownMetaEntry GetElement(int startIndex, byte[] data, out int updatedByteInde
for (; currentIndex < data.Length; currentIndex++)
{
- if (IsAllCapsCaString(currentIndex, data))
+ if (StringSanitizer.IsAllCapsCaString(currentIndex, data))
break;
}
@@ -117,7 +126,7 @@ UnknownMetaEntry GetElement(int startIndex, byte[] data, out int updatedByteInde
var destination = new byte[size];
Array.Copy(data, start, destination, 0, size);
- var metaTagItem = new UnknownMetaEntry()
+ var metaTagItem = new ParsedUnknownMetadataAttribute()
{
Name = tagName,
Version = version,
@@ -127,19 +136,203 @@ UnknownMetaEntry GetElement(int startIndex, byte[] data, out int updatedByteInde
return metaTagItem;
}
- bool IsAllCapsCaString(int index, byte[] data)
+
+ public ParsedMetadataAttribute? DeSerialize(ParsedUnknownMetadataAttribute entry, out string? errorMessage)
{
- if (ByteParsers.String.TryDecode(data, index, out var tagName, out _, out _))
+ var possibleClassLayouts = GetPossibleClassLayoutsForMetaDataAttribute(entry);
+ if (possibleClassLayouts == null)
{
- if (string.IsNullOrWhiteSpace(tagName))
- return false;
- if (tagName.Length < 4)
- return false;
- var allCaps = tagName.All(c => char.IsUpper(c) || c == '_' || c == ' ' || char.IsNumber(c));
- return allCaps;
+ errorMessage = $"Unable to find decoder for deserializing {entry.Name}_{entry.Version}";
+ return null;
}
- return false;
+ errorMessage = null;
+
+ // Try all possible class layouts until we find one that can successfully read the data
+ foreach (var possibleClassLayout in possibleClassLayouts)
+ {
+ var attributeInstance = Activator.CreateInstance(possibleClassLayout.Type);
+ var bytes = entry.Data;
+ var currentIndex = 0;
+ foreach (var proptery in possibleClassLayout.Properties)
+ {
+ var parser = ByteParserFactory.Create(proptery.PropertyType);
+ try
+ {
+ var value = parser.GetValueAsObject(bytes, currentIndex, out var bytesRead);
+ currentIndex += bytesRead;
+ proptery.SetValue(attributeInstance, value);
+ errorMessage = "";
+ }
+ catch (Exception e)
+ {
+ errorMessage = $"Failed to read object - {e.Message} bytes left";
+ break;
+ }
+ }
+
+ if (errorMessage != "")
+ continue;
+
+ var bytesLeft = bytes.Length - currentIndex;
+ if (bytesLeft != 0)
+ {
+ errorMessage = $"Failed to read object - {bytesLeft} bytes left";
+ continue;
+ }
+
+ var typedInstance = attributeInstance as ParsedMetadataAttribute;
+ Guard.IsNotNull(typedInstance, $"Failed to convert {attributeInstance} into {nameof(ParsedMetadataAttribute)}");
+
+ typedInstance.Name = entry.Name;
+ typedInstance.Data = bytes;
+ errorMessage = null;
+ return typedInstance;
+ }
+
+ return null;
}
+
+
+ public byte[]? Serialize(ParsedMetadataAttribute entry, out string? errorMessage)
+ {
+ var classLayout = GetClassLayoutsForMetaDataAttribute(entry);
+ if (classLayout == null)
+ {
+ errorMessage = $"Unable to find decoder for serializing {entry.Name}_{entry.Version}";
+ return null;
+ }
+
+ // Convert the class to bytes by getting the class layout and serializing each property in order.
+ var data = new List();
+ foreach (var proptery in classLayout.Properties)
+ {
+ var propertyValue = ReflectionHelper.GetMemberValue(entry, proptery.Name);
+ var parser = ByteParserFactory.Create(proptery.PropertyType);
+ var attributeByteValue = parser.Encode(propertyValue);
+ data.AddRange(attributeByteValue);
+ }
+
+ errorMessage = null;
+ return data.ToArray();
+ }
+
+
+
+
+ ///
+ /// Get all possible metadata definitions for a given metadata attribute.
+ /// It could be multiple, as some games share the same attribute name, but
+ /// has different binary representation. For example BlendOverride_v11_Troy
+ ///
+ public List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry)
+ {
+ var key = entry.Name + "_" + entry.Version;
+ var s = _metaDataDatabase.GetDefinition(key);
+ return s;
+
+ }
+
+ public List<(string Header, string Value)>? DeSerializeToStrings(ParsedMetadataAttribute entry, out string? errorMessage)
+ {
+ var entryInfoList = GetPossibleClassLayoutsForMetaDataAttribute(entry);
+ if (entryInfoList == null)
+ {
+ errorMessage = $"Unable to find decoder for {entry.Name}_{entry.Version}";
+ return null;
+ }
+
+ var bytes = entry.Data;
+ var currentIndex = 0;
+ var output = new List<(string, string)>();
+ errorMessage = null;
+
+ foreach (var entryInfo in entryInfoList)
+ {
+ errorMessage = "";
+ foreach (var proptery in entryInfo.Properties)
+ {
+ var parser = ByteParserFactory.Create(proptery.PropertyType);
+ var result = parser.TryDecode(bytes, currentIndex, out var value, out var bytesRead, out var error);
+ if (result == false)
+ {
+ errorMessage = $"Failed to serialize {proptery.Name} - {error}";
+ break;
+ }
+ currentIndex += bytesRead;
+ output.Add((proptery.Name, value));
+ }
+
+ if (errorMessage != "")
+ continue;
+
+ var bytesLeft = bytes.Length - currentIndex;
+ if (bytesLeft != 0)
+ {
+ errorMessage = $"Failed to read object - {bytesLeft} bytes left";
+ continue;
+ }
+
+ errorMessage = null;
+ return output;
+ }
+
+ return output;
+ }
+
+ public ParsedMetadataAttribute CreateDefault(string itemName)
+ {
+ var type = _metaDataDatabase.GetDefinition(itemName);
+ if (type.Count == 0)
+ throw new Exception("Unknown metadata item " + itemName);
+
+ var instance = Activator.CreateInstance(type.First()) as ParsedMetadataAttribute;
+
+ var itemNameSplit = itemName.ToUpper().Split("_");
+ instance.Version = int.Parse(itemNameSplit.Last());
+ instance.Name = string.Join("_", itemNameSplit.Take(itemNameSplit.Length - 1));
+ return instance;
+ }
+
+
+
+ List? GetPossibleClassLayoutsForMetaDataAttribute(ParsedMetadataAttribute entry)
+ {
+ var possibleAttributeTypes = GetPossibleTypesForMetaDataAttribute(entry);
+ if (possibleAttributeTypes.Count() == 0)
+ return null;
+
+ var output = new List();
+ foreach (var possibleAttributeType in possibleAttributeTypes)
+ {
+ var instance = Activator.CreateInstance(possibleAttributeType);
+ var orderedPropertiesList = possibleAttributeType.GetProperties()
+ .Where(x => x.CanWrite)
+ .Where(x => Attribute.IsDefined(x, typeof(MetaDataTagAttribute)))
+ .OrderBy(x => x.GetCustomAttributes(false).Single().Order)
+ .ToList();
+
+ var entryInfo = new EntryInfoResult(possibleAttributeType, orderedPropertiesList);
+ output.Add(entryInfo);
+ }
+
+ return output;
+ }
+
+ EntryInfoResult GetClassLayoutsForMetaDataAttribute(ParsedMetadataAttribute entry)
+ {
+ var orderedPropertiesList = entry.GetType().GetProperties()
+ .Where(x => x.CanWrite)
+ .Where(x => Attribute.IsDefined(x, typeof(MetaDataTagAttribute)))
+ .OrderBy(x => x.GetCustomAttributes(false).Single().Order)
+ .ToList();
+
+ var entryInfo = new EntryInfoResult(entry.GetType(), orderedPropertiesList);
+ return entryInfo;
+ }
+
+ record EntryInfoResult(Type? Type, List Properties);
+
+
}
}
diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagItem.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagItem.cs
deleted file mode 100644
index c68774d34..000000000
--- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagItem.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace Shared.GameFormats.AnimationMeta.Parsing
-{
- public class MetaDataTagItem
- {
- public class TagData
- {
- public TagData(byte[] bytes, int start, int size)
- {
- Bytes = bytes;
- Start = start;
- Size = size;
- }
-
- public byte[] Bytes { get; set; }
- public int Start { get; set; }
- public int Size { get; set; }
- }
-
- public string Name { get; set; } = ""; // Only name, no _v10 stuff here. Used for saving
- public TagData DataItem { get; set; }
- }
-}
diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs
similarity index 83%
rename from Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs
rename to Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs
index 0c23bea79..26936bcad 100644
--- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs
+++ b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs
@@ -2,19 +2,16 @@
namespace Shared.GameFormats.AnimationMeta.Parsing
{
- public class MetaDataFile
+ public class ParsedMetadataFile
{
- public int Version { get; set; }
- public List Items { get; set; } = new List();
+ public required int Version { get; set; }
+ public List Attributes { get; set; } = [];
- public List GetItemsOfType()
- {
- return Items.Where(x => x is T).Cast().ToList();
- }
+ public List GetItemsOfType() => Attributes.Where(x => x is T).Cast().ToList();
}
- public abstract class BaseMetaEntry
+ public abstract class ParsedMetadataAttribute
{
public string Name { get; set; }
@@ -29,11 +26,11 @@ public abstract class BaseMetaEntry
}
- public class UnknownMetaEntry : BaseMetaEntry
+ public class ParsedUnknownMetadataAttribute : ParsedMetadataAttribute
{
}
- public abstract class DecodedMetaEntryBase_v0 : BaseMetaEntry
+ public abstract class DecodedMetaEntryBase_v0 : ParsedMetadataAttribute
{
[MetaDataTag(1)]
public int UnknownIntBase_v0 { get; set; }
@@ -45,7 +42,7 @@ public abstract class DecodedMetaEntryBase_v1 : DecodedMetaEntryBase_v0
public int UnknownIntBase_v1 { get; set; }
}
- public abstract class DecodedMetaEntryBase_v2 : BaseMetaEntry
+ public abstract class DecodedMetaEntryBase_v2 : ParsedMetadataAttribute
{
[MetaDataTag(1, "Time in second when the Tag takes effect")]
public float StartTime { get; set; }
@@ -57,7 +54,7 @@ public abstract class DecodedMetaEntryBase_v2 : BaseMetaEntry
public string Filter { get; set; } = "";
}
- public abstract class DecodedMetaEntryBase : BaseMetaEntry
+ public abstract class DecodedMetaEntryBase : ParsedMetadataAttribute
{
[MetaDataTag(1, "Time in second when the Tag takes effect")]
public float StartTime { get; set; }
diff --git a/Shared/GameFiles/DependencyInjectionContainer.cs b/Shared/GameFiles/DependencyInjectionContainer.cs
index a0f90b2db..9f14dd09f 100644
--- a/Shared/GameFiles/DependencyInjectionContainer.cs
+++ b/Shared/GameFiles/DependencyInjectionContainer.cs
@@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Shared.Core.DependencyInjection;
+using Shared.GameFormats.AnimationMeta.Parsing;
namespace Shared.GameFormats
{
@@ -11,6 +12,8 @@ public DependencyInjectionContainer()
public override void Register(IServiceCollection services)
{
+ services.AddSingleton();
+ services.AddTransient();
}
}
}
diff --git a/Shared/SharedCore/Events/Global/OpenEditorCommand.cs b/Shared/SharedCore/Events/Global/OpenEditorCommand.cs
index 03599ba23..1f08fdbeb 100644
--- a/Shared/SharedCore/Events/Global/OpenEditorCommand.cs
+++ b/Shared/SharedCore/Events/Global/OpenEditorCommand.cs
@@ -1,10 +1,10 @@
using System.Diagnostics;
-using Shared.Core.Events;
+using CommunityToolkit.Diagnostics;
using Shared.Core.PackFiles;
using Shared.Core.PackFiles.Models;
using Shared.Core.ToolCreation;
-namespace Shared.Ui.Events.UiCommands
+namespace Shared.Core.Events.Global
{
public class OpenEditorCommand : IUiCommand
{
@@ -23,6 +23,15 @@ public IEditorInterface Execute(PackFile file, EditorEnums? preferedEditor = nul
return editor;
}
+ public T Execute(PackFile file, EditorEnums? preferedEditor = null)
+ where T: class, IEditorInterface
+ {
+ var editor = _editorCreator.CreateFromFile(file, preferedEditor);
+ var typed = editor as T;
+ Guard.IsNotNull(typed, "Editor is not of the expected type. Expected: " + typeof(T).Name + ", Actual: " + editor.GetType().Name);
+ return typed;
+ }
+
public IEditorInterface Execute(string file, EditorEnums? preferedEditor = null)
{
var packFile = _packFileService.FindFile(file);
diff --git a/Shared/SharedCore/Misc/ReflectionHelper.cs b/Shared/SharedCore/Misc/ReflectionHelper.cs
new file mode 100644
index 000000000..cbd9f4c9e
--- /dev/null
+++ b/Shared/SharedCore/Misc/ReflectionHelper.cs
@@ -0,0 +1,57 @@
+using System.Reflection;
+
+namespace Shared.Core.Misc
+{
+ public static class ReflectionHelper
+ {
+
+ public static object GetMemberValue(object obj, string memberName)
+ {
+ if (obj == null)
+ throw new ArgumentNullException(nameof(obj));
+
+ var type = obj.GetType();
+
+ // Try to get as a Property
+ var propInfo = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (propInfo != null)
+ return propInfo.GetValue(obj, null);
+
+ // Try to get as a Field
+ var fieldInfo = type.GetField(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (fieldInfo != null)
+ return fieldInfo.GetValue(obj);
+
+ throw new MemberAccessException($"Member '{memberName}' not found in type '{type.Name}'.");
+ }
+
+ public static T CreateShallowCopy(T original) where T : class
+ {
+ if (original == null)
+ {
+ return null;
+ }
+
+ // Create a new instance of the same type as the original object.
+ // Activator.CreateInstance() uses reflection to instantiate the type dynamically.
+ T copy = (T)Activator.CreateInstance(original.GetType());
+
+ // Get all public, instance properties of the class.
+ PropertyInfo[] properties = original.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ foreach (PropertyInfo property in properties)
+ {
+ // Check if the property can be read and written to.
+ if (property.CanRead && property.CanWrite)
+ {
+ // Get the value from the original object and set it on the new copy.
+ object value = property.GetValue(original);
+ property.SetValue(copy, value);
+ }
+ }
+
+ return copy;
+ }
+
+ }
+}
diff --git a/Shared/SharedCore/Misc/StringSanitizer.cs b/Shared/SharedCore/Misc/StringSanitizer.cs
index f86df25ee..046dcc8b7 100644
--- a/Shared/SharedCore/Misc/StringSanitizer.cs
+++ b/Shared/SharedCore/Misc/StringSanitizer.cs
@@ -1,4 +1,6 @@
-namespace Shared.Core.Misc
+using Shared.ByteParsing;
+
+namespace Shared.Core.Misc
{
public static class StringSanitizer
{
@@ -9,5 +11,20 @@ public static string FixedString(string str)
return str.Substring(0, idx);
return str;
}
+
+ public static bool IsAllCapsCaString(int index, byte[] data)
+ {
+ if (ByteParsers.String.TryDecode(data, index, out var tagName, out _, out _))
+ {
+ if (string.IsNullOrWhiteSpace(tagName))
+ return false;
+ if (tagName.Length < 4)
+ return false;
+ var allCaps = tagName.All(c => char.IsUpper(c) || c == '_' || c == ' ' || char.IsNumber(c));
+ return allCaps;
+ }
+
+ return false;
+ }
}
}