From a445667913874151c7fff2bb5db9007e9ec0be48 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Mon, 23 Feb 2026 20:04:43 +0100 Subject: [PATCH 01/12] Code cleanup --- .../DependencyInjectionContainer.cs | 2 +- .../MetaEditor/MetaDataEditorViewModel.cs | 6 ++ .../SuperView/SuperViewViewModel.cs | 25 +++++- .../Instances/AnimatedPropInstance.cs | 4 +- .../Instances/DrawableMetaInstance.cs | 4 +- .../Visualisation/MetaDataFactory.cs | 34 ++++--- .../Visualisation/Rules/CopyRootTransform.cs | 15 ++-- .../Visualisation/Rules/DockEquipmentRule.cs | 2 +- .../Visualisation/Rules/TransformBoneRule.cs | 2 +- .../Common/IMetaDataInstance.cs | 9 ++ .../ReferenceModel/SceneObjectViewModel.cs | 30 +------ .../Editors.Shared.Core/Common/SceneObject.cs | 5 +- .../Common/SceneObjectViewModelBuilder.cs | 15 +--- .../Services/IMetaDataFactory.cs | 20 ----- GameWorld/View3D/Rendering/LineMeshRender.cs | 19 +++- .../RenderItems/WorldTextRenderItem.cs | 15 +++- GameWorld/View3D/SceneNodes/SceneNode.cs | 4 +- .../View3D/SceneNodes/SimpleDrawableNode.cs | 3 +- .../Definitions/DisablePersistant.cs | 6 +- .../Definitions/DockEquipment.cs | 36 ++++---- .../AnimationMeta/Definitions/Effect.cs | 89 +++++++++++++++++-- 21 files changed, 206 insertions(+), 139 deletions(-) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/Instances/AnimatedPropInstance.cs (85%) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/Instances/DrawableMetaInstance.cs (93%) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/MetaDataFactory.cs (89%) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/Rules/CopyRootTransform.cs (81%) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/Rules/DockEquipmentRule.cs (97%) rename Editors/AnimationMeta/{ => SuperView}/Visualisation/Rules/TransformBoneRule.cs (95%) create mode 100644 Editors/Shared/Editors.Shared.Core/Common/IMetaDataInstance.cs delete mode 100644 Editors/Shared/Editors.Shared.Core/Services/IMetaDataFactory.cs diff --git a/Editors/AnimationMeta/DependencyInjectionContainer.cs b/Editors/AnimationMeta/DependencyInjectionContainer.cs index bc174b2df..aa5bf5982 100644 --- a/Editors/AnimationMeta/DependencyInjectionContainer.cs +++ b/Editors/AnimationMeta/DependencyInjectionContainer.cs @@ -3,7 +3,7 @@ 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; diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index 451987ece..3efad3fb1 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -29,6 +29,12 @@ public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataTagDe _metaDataTagDeSerializer = metaDataTagDeSerializer; } + partial void OnSelectedTagChanged(IMetaDataEntry value) + { + + + } + public bool Save() => _uiCommandFactory.Create().Execute(this); public void Close() { } diff --git a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs index ce5f79a76..10b6cf579 100644 --- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs +++ b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs @@ -2,6 +2,7 @@ using System.Linq; 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; @@ -19,6 +20,7 @@ public partial class SuperViewViewModel : EditorHostBase private readonly SceneObjectEditor _sceneObjectBuilder; private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + private readonly IMetaDataFactory _metaDataFactory; private readonly IPackFileService _packFileService; private readonly IEventHub _eventHub; private readonly IUiCommandFactory _uiCommandFactory; @@ -36,7 +38,8 @@ public SuperViewViewModel( IUiCommandFactory uiCommandFactory, SceneObjectEditor sceneObjectBuilder, IEditorHostParameters editorHostParameters, - MetaDataTagDeSerializer metaDataTagDeSerializer) + MetaDataTagDeSerializer metaDataTagDeSerializer, + IMetaDataFactory metaDataFactory) : base(editorHostParameters) { DisplayName = "Super view"; @@ -45,6 +48,7 @@ public SuperViewViewModel( _uiCommandFactory = uiCommandFactory; _sceneObjectBuilder = sceneObjectBuilder; _metaDataTagDeSerializer = metaDataTagDeSerializer; + _metaDataFactory = metaDataFactory; Initialize(); eventHub.Register(this, OnFileSaved); eventHub.Register(this, OnSceneObjectUpdated); @@ -66,13 +70,28 @@ void Initialize() PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer); MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer); - 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 model) + { + 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, SceneObjects[0].FragAndSlotSelection.FragmentList.SelectedItem); + } + private void OnSceneObjectUpdated(SceneObjectUpdateEvent e) { PersistentMetaEditor.LoadFile(e.Owner.PersistMetaData); diff --git a/Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs b/Editors/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs similarity index 85% rename from Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs rename to Editors/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs index fb3f08d35..c309cce3a 100644 --- a/Editors/AnimationMeta/Visualisation/Instances/AnimatedPropInstance.cs +++ b/Editors/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/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs similarity index 93% rename from Editors/AnimationMeta/Visualisation/Instances/DrawableMetaInstance.cs rename to Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs index 32451a346..9de9acd13 100644 --- a/Editors/AnimationMeta/Visualisation/Instances/DrawableMetaInstance.cs +++ b/Editors/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,7 +6,7 @@ using Shared.Core.ErrorHandling; using System; -namespace Editors.AnimationMeta.Visualisation.Instances +namespace Editors.AnimationMeta.SuperView.Visualisation.Instances { public class DrawableMetaInstance : IMetaDataInstance { diff --git a/Editors/AnimationMeta/Visualisation/MetaDataFactory.cs b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs similarity index 89% rename from Editors/AnimationMeta/Visualisation/MetaDataFactory.cs rename to Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs index ed4c3e501..1596068da 100644 --- a/Editors/AnimationMeta/Visualisation/MetaDataFactory.cs +++ b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs @@ -2,9 +2,9 @@ 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 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,9 +22,14 @@ using Shared.GameFormats.AnimationMeta.Parsing; using Shared.GameFormats.AnimationPack; -namespace Editors.AnimationMeta.Visualisation +namespace Editors.AnimationMeta.SuperView.Visualisation { + public interface IMetaDataFactory + { + List Create(MetaDataFile persistent, MetaDataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment); + } + public class MetaDataFactory : IMetaDataFactory { private readonly ILogger _logger = Logging.Create(); @@ -79,7 +84,7 @@ private IEnumerable ApplyMetaData(MetaDataFile file, SceneNod output.AddRange(file.GetItemsOfType().Select(meteDataItem => CreateSplashAttack(meteDataItem, root, $"SplashAttack_{Math.Round(meteDataItem.EndTime, 2)}", 0.1f))); - output.AddRange(file.GetItemsOfType().Select(x => CreateEffect(x, root, skeleton))); + output.AddRange(file.GetItemsOfType().Select(x => CreateEffect(x, root, skeleton))); foreach (var meteDataItem in file.GetItemsOfType()) CreateEquipmentDock(meteDataItem, fragment, skeleton, rootPlayer); @@ -217,12 +222,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 { @@ -248,16 +253,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) { var node = new SimpleDrawableNode("Effect:" + effect.VfxName); - node.AddItem(LineHelper.AddLocator(effect.Position, 0.3f, Color.Red)); + var locatorScale = 0.3f; + node.AddItem(LineHelper.AddRgbLocator(effect.Position, locatorScale)); node.AddItem(new WorldTextRenderItem(_resourceLibrary, effect.VfxName, effect.Position)); - + 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/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs similarity index 81% rename from Editors/AnimationMeta/Visualisation/Rules/CopyRootTransform.cs rename to Editors/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs index 0499ee0a0..fa912b81f 100644 --- a/Editors/AnimationMeta/Visualisation/Rules/CopyRootTransform.cs +++ b/Editors/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/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs similarity index 97% rename from Editors/AnimationMeta/Visualisation/Rules/DockEquipmentRule.cs rename to Editors/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs index e62734009..478f18dec 100644 --- a/Editors/AnimationMeta/Visualisation/Rules/DockEquipmentRule.cs +++ b/Editors/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/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs similarity index 95% rename from Editors/AnimationMeta/Visualisation/Rules/TransformBoneRule.cs rename to Editors/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs index f8a463b31..6bd55c046 100644 --- a/Editors/AnimationMeta/Visualisation/Rules/TransformBoneRule.cs +++ b/Editors/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/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/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/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/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/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/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; - } + }*/ } From c2a5f611b3963b126cdb72f2aedb989336293a71 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Tue, 24 Feb 2026 21:27:39 +0100 Subject: [PATCH 02/12] Temp --- .../MetaEditor/Commands/SaveCommand.cs | 56 ++++++-- .../MetaEditor/MetaDataAttribute.cs | 65 ++++++++- .../MetaEditor/MetaDataEditorViewModel.cs | 14 +- .../AnimationMeta/MetaEditor/MetaDataEntry.cs | 15 +- .../MetaEditor/PropertyViewModel.cs | 59 ++++++++ .../Visualisation/MetaDataFactory.cs | 6 +- .../Animation/AnimMetaDataReportGenerator.cs | 2 +- .../Shared.ByteParsing/Parsers/IByteParser.cs | 1 + .../Parsing/MetaDataFileParser.cs | 29 +++- .../Parsing/MetaDataTagDeSerializer.cs | 131 ++++++++++++++---- ...{MetaDataFile.cs => ParsedMetadataFile.cs} | 14 +- 11 files changed, 321 insertions(+), 71 deletions(-) create mode 100644 Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs rename Shared/GameFiles/AnimationMeta/Parsing/{MetaDataFile.cs => ParsedMetadataFile.cs} (87%) diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index a92931be9..f2894dc26 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Drawing.Imaging; using System.Windows; using Editors.AnimationMeta.Presentation; using Serilog; @@ -48,23 +50,49 @@ public bool Execute(MetaDataEditorViewModel controller) _logger.Here().Information("Generating bytes"); - var parser = new MetaDataFileParser(); - var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, tagDataItems); - _logger.Here().Information("Saving"); - var res = _packFileSaveService.Save(path, bytes, false); - if (res != null) { - controller.CurrentFile = res; - controller.DisplayName = res.Name; + var parser = new MetaDataFileParser(); + var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, tagDataItems); + _logger.Here().Information("Saving"); + var res = _packFileSaveService.Save(path, bytes, false); + if (res != null) + { + controller.CurrentFile = res; + controller.DisplayName = res.Name; + } + + _logger.Here().Information("Creating metadata file complete"); + var saveEvent = new ScopedFileSavedEvent() + { + FileOwner = controller, + NewPath = path, + }; + _eventHub.Publish(saveEvent); } - _logger.Here().Information("Creating metadata file complete"); - var saveEvent = new ScopedFileSavedEvent() { - FileOwner = controller, - NewPath = path, - }; - _eventHub.Publish(saveEvent); + + + + var parser = new MetaDataFileParser(); + var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); + _logger.Here().Information("Saving"); + var res = _packFileSaveService.Save(path, bytes, false); + if (res != null) + { + controller.CurrentFile = res; + controller.DisplayName = res.Name; + } + + _logger.Here().Information("Creating metadata file complete"); + var saveEvent = new ScopedFileSavedEvent() + { + FileOwner = controller, + NewPath = path, + }; + _eventHub.Publish(saveEvent); + } + return true; } diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs b/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs index 9e853e8c9..d57624fc8 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs @@ -1,4 +1,6 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using System; +using System.Reflection; +using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Xna.Framework; using Serilog; using Shared.ByteParsing.Parsers; @@ -12,6 +14,8 @@ public partial class MetaDataAttribute : ObservableObject { private readonly ILogger _logger = Logging.Create(); private readonly IByteParser _parser; + protected readonly object _target; + protected readonly PropertyInfo _property; [ObservableProperty] string _valueAsString; [ObservableProperty] string _fieldName; @@ -20,9 +24,11 @@ public partial class MetaDataAttribute : ObservableObject [ObservableProperty] bool _isReadOnly = true; [ObservableProperty] bool _isValid = true; - public MetaDataAttribute(IByteParser parser, object value) + public MetaDataAttribute(IByteParser parser, object value, object target, PropertyInfo property) { _parser = parser; + _target = target; + _property = property; _valueAsString = value.ToString(); Validate(); } @@ -32,6 +38,32 @@ public MetaDataAttribute(IByteParser parser, object value) 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); + } + } + } public virtual byte[] GetByteValue() @@ -48,11 +80,14 @@ public partial class OrientationMetaDataAttribute : MetaDataAttribute private readonly ILogger _logger = Logging.Create(); private readonly Vector4Parser _typedParser; - [ObservableProperty] Vector3ViewModel _value = new Vector3ViewModel(0, 0, 0); + [ObservableProperty] Vector3ViewModel _value = new(0, 0, 0); - public OrientationMetaDataAttribute(Vector4Parser parser, Vector4 value) - : base(parser, value) + public OrientationMetaDataAttribute(Vector4Parser parser, Vector4 value, object target, PropertyInfo property) + : base(parser, value, target, property) { + + _value = new(0, 0, 0, OnValueChangedCallback); + _typedParser = parser; var q = new Quaternion(value); @@ -62,6 +97,14 @@ public OrientationMetaDataAttribute(Vector4Parser parser, Vector4 value) IsValid = true; } + private void OnValueChangedCallback(Vector3 vector) + { + var vector3 = Value.GetAsVector3(); + var value = MathUtil.EulerDegreesToQuaternion(vector3); + value.Normalize(); + _property.SetValue(_target, value.ToVector4()); + } + public override byte[] GetByteValue() { _logger.Here().Information($"GetByteValue Orientation=>{FieldName} {_typedParser} {ValueAsString} {Value}"); @@ -84,15 +127,23 @@ public partial class VectorMetaDataAttribute : MetaDataAttribute private readonly ILogger _logger = Logging.Create(); private readonly Vector3Parser _parser; - [ObservableProperty] Vector3ViewModel _value = new Vector3ViewModel(0, 0, 0); + [ObservableProperty] Vector3ViewModel _value; - public VectorMetaDataAttribute(Vector3Parser parser, Vector3 value) : base(parser, value) + public VectorMetaDataAttribute(Vector3Parser parser, Vector3 value, object target, PropertyInfo property) : base(parser, value, target, property) { + _value = new(0, 0, 0, OnValueChangedCallback); _parser = parser; Value.Set(value); IsValid = true; } + + private void OnValueChangedCallback(Vector3 vector) + { + var vector3 = Value.GetAsVector3(); + _property.SetValue(_target, vector3); + } + public override byte[] GetByteValue() { _logger.Here().Information($"GetByteValue Vector3=>{FieldName} {_parser} {ValueAsString} {Value}"); diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index 3efad3fb1..1e41e3f0b 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -15,6 +15,8 @@ public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterfac private readonly IUiCommandFactory _uiCommandFactory; private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + public ParsedMetadataFile _metaDataFile; + [ObservableProperty] string _displayName = "Metadata Editor"; [ObservableProperty] IMetaDataEntry _selectedTag; [ObservableProperty] ObservableCollection _tags = []; @@ -56,14 +58,16 @@ public void LoadFile(PackFile file) var loadedMetadataFile = parser.ParseFile(fileContent, _metaDataTagDeSerializer); MetaDataFileVersion = loadedMetadataFile.Version; - foreach (var item in loadedMetadataFile.Items) + _metaDataFile = loadedMetadataFile; + + foreach (var metadataEntry in loadedMetadataFile.Items) { - if (item is UnknownMetaEntry uknMeta) + if (metadataEntry is UnknownMetaEntry uknMeta) Tags.Add(new UnkMetaDataEntry(uknMeta)); - else if (item is BaseMetaEntry metaBase) - Tags.Add(new MetaDataEntry(metaBase, _metaDataTagDeSerializer)); + else if (metadataEntry is ParsedMetadataAttribute parsedKnownAttribute) + Tags.Add(new MetaDataEntry(parsedKnownAttribute, _metaDataTagDeSerializer)); 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/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs index 46e6be747..c2c18b240 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Reflection; using CommunityToolkit.Mvvm.ComponentModel; @@ -58,7 +59,7 @@ public class MetaDataEntry : IMetaDataEntry private readonly ILogger _logger = Logging.Create(); private readonly string _originalName; - public MetaDataEntry(BaseMetaEntry typedMetaItem, MetaDataTagDeSerializer metaDataTagDeSerializer) + public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, MetaDataTagDeSerializer metaDataTagDeSerializer) { _originalName = typedMetaItem.Name; DisplayName = typedMetaItem.DisplayName; @@ -83,15 +84,15 @@ public MetaDataEntry(BaseMetaEntry typedMetaItem, MetaDataTagDeSerializer metaDa if (attributeInfo.DisplayOverride == MetaDataTagAttribute.DisplayType.EulerVector || value is Vector3) { if (value is Vector3 vector3) - editableItem = new VectorMetaDataAttribute(parser as Vector3Parser, vector3); + editableItem = new VectorMetaDataAttribute(parser as Vector3Parser, vector3, typedMetaItem, prop); else if (value is Vector4 quaternion) - editableItem = new OrientationMetaDataAttribute(parser as Vector4Parser, quaternion); + editableItem = new OrientationMetaDataAttribute(parser as Vector4Parser, quaternion, typedMetaItem, prop); else throw new Exception("Unknown item"); } else { - editableItem = new MetaDataAttribute(parser, value.ToString()); + editableItem = new MetaDataAttribute(parser, value.ToString(), typedMetaItem, prop); } editableItem.Description = itemDiscription; @@ -119,6 +120,10 @@ public override string HasError() public override MetaDataTagItem GetAsFileFormatData() { + // Go though all using reflection. + // Get the byte + + _logger.Here().Information("Start " + DisplayName); var newItem = new MetaDataTagItem() { @@ -166,5 +171,7 @@ static string FormatFieldName(string name) return newName; } } + + } diff --git a/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs b/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs new file mode 100644 index 000000000..8652dbb3d --- /dev/null +++ b/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs @@ -0,0 +1,59 @@ +using System; +using System.ComponentModel; +using System.Reflection; + +namespace Editors.AnimationMeta.Presentation +{ + + public abstract class ViewModelBase : INotifyPropertyChanged + { + public event PropertyChangedEventHandler? PropertyChanged; + protected void OnPropertyChanged(string name) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + + public class PropertyViewModel : ViewModelBase + { + private readonly object _target; + private readonly PropertyInfo _property; + + public string Name => _property.Name; + public Type PropertyType => _property.PropertyType; + + public object? Value + { + get => _property.GetValue(_target); + set + { + try + { + if (_property.PropertyType == typeof(Single)) + { + + string val = value as string; + var singleValue = Single.Parse(val); + _property.SetValue(_target, singleValue); + + } + else + { + + _property.SetValue(_target, value); + } + + + + OnPropertyChanged(nameof(Value)); + } + catch { } + } + } + + public PropertyViewModel(object target, PropertyInfo property) + { + _target = target; + _property = property; + } + } +} + diff --git a/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs index 1596068da..b6f32927f 100644 --- a/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs +++ b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs @@ -27,7 +27,7 @@ namespace Editors.AnimationMeta.SuperView.Visualisation public interface IMetaDataFactory { - List Create(MetaDataFile persistent, MetaDataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment); + List Create(ParsedMetadataFile persistent, ParsedMetadataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment); } public class MetaDataFactory : IMetaDataFactory @@ -52,7 +52,7 @@ 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, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment) { // Clear all var output = new List(); @@ -68,7 +68,7 @@ public List Create(MetaDataFile persistent, MetaDataFile meta return output; } - private IEnumerable ApplyMetaData(MetaDataFile file, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment) + private IEnumerable ApplyMetaData(ParsedMetadataFile file, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment) { var output = new List(); if (file == null) diff --git a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs index 487a19cf7..403010f3b 100644 --- a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs +++ b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs @@ -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; diff --git a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs index 76251bcea..a7741614b 100644 --- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs +++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs @@ -30,6 +30,7 @@ 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); + object GetValueAsObject(byte[] buffer, int index, out int bytesRead); } diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs index 88f90eb1b..c00b3bfb8 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs @@ -10,18 +10,18 @@ public class MetaDataFileParser { private readonly ILogger _logger = Logging.Create(); - public MetaDataFile? ParseFile(PackFile pf, MetaDataTagDeSerializer metaDataTagDeSerializer) + public ParsedMetadataFile? ParseFile(PackFile pf, MetaDataTagDeSerializer metaDataTagDeSerializer) { if (pf == null) return null; return ParseFile(pf.DataSource.ReadData(), metaDataTagDeSerializer); } - public MetaDataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDataTagDeSerializer) + public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDataTagDeSerializer) { var contentLength = fileContent.Count(); - var outputFile = new MetaDataFile() + var outputFile = new ParsedMetadataFile() { Version = BitConverter.ToInt32(fileContent, 0) }; @@ -94,6 +94,29 @@ public byte[] GenerateBytes(int version, IEnumerable items) return data.ToArray(); } + public byte[] GenerateBytes(int version, ParsedMetadataFile metaFile) + { + + var metaDataTagDeSerializer = new MetaDataTagDeSerializer(); + + + + var data = new List(); + data.AddRange(BitConverter.GetBytes(metaFile.Version)); + data.AddRange(BitConverter.GetBytes(metaFile.Items.Count())); + foreach (var item in metaFile.Items) + { + metaDataTagDeSerializer.Serialize(item, out var errorStr) ; + + + 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) { if (!ByteParsers.String.TryDecode(data, startIndex, out var tagName, out var strBytesRead, out var error)) diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs index 91f66052a..2b9917f38 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs @@ -199,38 +199,45 @@ bool IsSequential(int[] array) return array.Zip(array.Skip(1), (a, b) => a + 1 == b).All(x => x); } - List GetTypesFromMeta(BaseMetaEntry entry) + /// + /// 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 + /// + List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry) { var key = entry.Name + "_" + entry.Version; if (_typeTable.ContainsKey(key) == false) - return null; + return []; return _typeTable[key]; } - public BaseMetaEntry? DeSerialize(UnknownMetaEntry entry, out string? errorMessage) + public ParsedMetadataAttribute? DeSerialize(UnknownMetaEntry entry, out string? errorMessage) { - var entryInfoList = GetEntryInformation(entry); - if (entryInfoList == null) + var possibleClassLayouts = GetPossibleClassLayoutsForMetaDataAttribute(entry); + if (possibleClassLayouts == null) { - errorMessage = $"Unable to find decoder for {entry.Name}_{entry.Version}"; + errorMessage = $"Unable to find decoder for deserializing {entry.Name}_{entry.Version}"; return null; } errorMessage = null; - foreach (var entryInfo in entryInfoList) + + // Try all possible class layouts until we find one that can successfully read the data + foreach (var possibleClassLayout in possibleClassLayouts) { - var instance = Activator.CreateInstance(entryInfo.Type); + var attributeInstance = Activator.CreateInstance(possibleClassLayout.Type); var bytes = entry.Data; var currentIndex = 0; - foreach (var proptery in entryInfo.Properties) + 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(instance, value); + proptery.SetValue(attributeInstance, value); errorMessage = ""; } catch (Exception e) @@ -250,7 +257,7 @@ List GetTypesFromMeta(BaseMetaEntry entry) continue; } - var typedInstance = instance as BaseMetaEntry; + var typedInstance = attributeInstance as ParsedMetadataAttribute; typedInstance.Name = entry.Name; typedInstance.Data = bytes; errorMessage = null; @@ -260,9 +267,82 @@ List GetTypesFromMeta(BaseMetaEntry entry) return null; } - public List<(string Header, string Value)>? DeSerializeToStrings(BaseMetaEntry entry, out string? errorMessage) + + public byte[] Serialize(ParsedMetadataAttribute entry, out string? errorMessage) + { + var entryInfoList = GetPossibleClassLayoutsForMetaDataAttribute(entry); + if (entryInfoList == null) + { + errorMessage = $"Unable to find decoder for serializing {entry.Name}_{entry.Version}"; + return null; + } + + errorMessage = null; + + + var data = new List(); + // data.AddRange(BitConverter.GetBytes(metaFile.Version)); + // data.AddRange(BitConverter.GetBytes(metaFile.Items.Count())); + + foreach (var entryInfo in entryInfoList) + { + // var instance = Activator.CreateInstance(entryInfo.Type); + foreach (var proptery in entryInfo.Properties) + { + var parser = ByteParserFactory.Create(proptery.PropertyType); + try + { + object propertyValue = GetMemberValue(entry, proptery.Name); + var attributeByteValue = parser.Encode(null, out var writeError); + //data.AddRange(attributeByteValue); + } + catch (Exception e) + { + + break; + } + } + } + + return null; + } + + + // + + public static object GetMemberValue(object obj, string memberName) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + + Type type = obj.GetType(); + + // Try to get as a Property + PropertyInfo propInfo = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (propInfo != null) + { + return propInfo.GetValue(obj, null); + } + + // Try to get as a Field + FieldInfo 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 List<(string Header, string Value)>? DeSerializeToStrings(ParsedMetadataAttribute entry, out string? errorMessage) { - var entryInfoList = GetEntryInformation(entry); + var entryInfoList = GetPossibleClassLayoutsForMetaDataAttribute(entry); if (entryInfoList == null) { errorMessage = $"Unable to find decoder for {entry.Name}_{entry.Version}"; @@ -307,13 +387,13 @@ List GetTypesFromMeta(BaseMetaEntry entry) return output; } - public BaseMetaEntry CreateDefault(string itemName) + public ParsedMetadataAttribute 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 instance = Activator.CreateInstance(type) as ParsedMetadataAttribute; var itemNameSplit = itemName.ToUpper().Split("_"); instance.Version = int.Parse(itemNameSplit.Last()); @@ -321,33 +401,30 @@ public BaseMetaEntry CreateDefault(string itemName) return instance; } - List? GetEntryInformation(BaseMetaEntry entry) + List? GetPossibleClassLayoutsForMetaDataAttribute(ParsedMetadataAttribute entry) { - var metaDataTypes = GetTypesFromMeta(entry); - if (metaDataTypes == null) + var possibleAttributeTypes = GetPossibleTypesForMetaDataAttribute(entry); + if (possibleAttributeTypes.Count() == 0) return null; var output = new List(); - foreach (var metaDataType in metaDataTypes) + foreach (var possibleAttributeType in possibleAttributeTypes) { - var instance = Activator.CreateInstance(metaDataType); - var orderedPropertiesList = metaDataType.GetProperties() + 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() { Type = metaDataType, Properties = orderedPropertiesList }; + var entryInfo = new EntryInfoResult(possibleAttributeType, orderedPropertiesList); output.Add(entryInfo); } return output; } - public class EntryInfoResult - { - public Type? Type { get; set; } - public List Properties { get; set; } = new(); - } + public record EntryInfoResult(Type? Type, List Properties); + } } diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs similarity index 87% rename from Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs rename to Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs index 0c23bea79..9cb8dffe2 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFile.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs @@ -2,10 +2,10 @@ namespace Shared.GameFormats.AnimationMeta.Parsing { - public class MetaDataFile + public class ParsedMetadataFile { public int Version { get; set; } - public List Items { get; set; } = new List(); + public List Items { get; set; } = new List(); public List GetItemsOfType() { @@ -14,7 +14,7 @@ public List GetItemsOfType() } - public abstract class BaseMetaEntry + public abstract class ParsedMetadataAttribute { public string Name { get; set; } @@ -29,11 +29,11 @@ public abstract class BaseMetaEntry } - public class UnknownMetaEntry : BaseMetaEntry + public class UnknownMetaEntry : ParsedMetadataAttribute { } - public abstract class DecodedMetaEntryBase_v0 : BaseMetaEntry + public abstract class DecodedMetaEntryBase_v0 : ParsedMetadataAttribute { [MetaDataTag(1)] public int UnknownIntBase_v0 { get; set; } @@ -45,7 +45,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 +57,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; } From f5b45f34946f536d228ae110b68d7cd76cae7c62 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Wed, 25 Feb 2026 19:56:31 +0100 Subject: [PATCH 03/12] Code --- .../MetaEditor/Commands/CopyPastCommand.cs | 4 +- .../MetaEditor/Commands/SaveCommand.cs | 4 +- .../MetaEditor/MetaDataEditorViewModel.cs | 2 +- .../AnimationMeta/MetaEditor/MetaDataEntry.cs | 4 +- .../Shared.ByteParsing/Parsers/BoolParser.cs | 32 ++++++++++++++ .../Shared.ByteParsing/Parsers/IByteParser.cs | 1 + .../Shared.ByteParsing/Parsers/IntParser.cs | 31 +++++++++++++ .../Parsers/NumberParser.cs | 28 ++++++++++++ .../Parsers/StringParser.cs | 25 +++++++++++ .../Shared.ByteParsing/Parsers/UIntParser.cs | 32 ++++++++++++++ .../Parsers/Vector3Parser.cs | 22 ++++++++++ .../Parsers/Vector4Parser.cs | 22 ++++++++++ .../Parsers/FixedAciiStringParserTest.cs | 44 +++++++++++++++++++ .../Parsers/FixedStringParserTest.cs | 31 +++++++++++++ .../Parsers/IntParserTest.cs | 19 ++++++++ .../Parsers/ShortParserTest.cs | 28 ++++++++++++ .../Parsers/SingleParserTest.cs | 27 ++++++++++++ .../Parsers/StringParserTest.cs | 25 +++++++++++ .../Parsers/UInt64ParserTest.cs | 27 ++++++++++++ .../Parsers/UIntParserTest.cs | 27 ++++++++++++ .../Parsers/UShortParserTest.cs | 27 ++++++++++++ .../Parsers/Vector3ParserTest.cs | 44 +++++++++++++++++++ .../Parsers/Vector4ParserTest.cs | 44 +++++++++++++++++++ .../Parsing/MetaDataFileParser.cs | 10 ++--- .../Parsing/MetaDataTagDeSerializer.cs | 20 +++++---- .../Parsing/ParsedMetadataFile.cs | 2 +- 26 files changed, 559 insertions(+), 23 deletions(-) create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedAciiStringParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/FixedStringParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/ShortParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/SingleParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/StringParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UInt64ParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UIntParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/UShortParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector3ParserTest.cs create mode 100644 Shared/ByteParsing/Shared.ByteParsingTest/Parsers/Vector4ParserTest.cs diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs index e738cfa42..ae50438ab 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs @@ -12,7 +12,7 @@ namespace Editors.AnimationMeta.MetaEditor.Commands public class MetaDataTagCopyItem : ICopyPastItem { public string Description => "Copy object for MetaDataTag"; - public List Items { get; set; } = []; + public List Items { get; set; } = []; } class CopyPastCommand : IUiCommand @@ -46,7 +46,7 @@ public void ExecuteCopy(MetaDataEditorViewModel controller) foreach (var tag in selectedTags) { var fileFormatData = tag.GetAsFileFormatData(); - var entry = new UnknownMetaEntry() + var entry = new ParsedUnknownMetadataAttribute() { Name = fileFormatData.Name, Data = fileFormatData.DataItem.Bytes, diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index f2894dc26..44f0b3bc6 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing.Imaging; +using System.Collections.Generic; using System.Windows; using Editors.AnimationMeta.Presentation; using Serilog; diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index 1e41e3f0b..cfdb40bb5 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -62,7 +62,7 @@ public void LoadFile(PackFile file) foreach (var metadataEntry in loadedMetadataFile.Items) { - if (metadataEntry is UnknownMetaEntry uknMeta) + if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta) Tags.Add(new UnkMetaDataEntry(uknMeta)); else if (metadataEntry is ParsedMetadataAttribute parsedKnownAttribute) Tags.Add(new MetaDataEntry(parsedKnownAttribute, _metaDataTagDeSerializer)); diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs index c2c18b240..b70deece6 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs @@ -30,9 +30,9 @@ public abstract partial class IMetaDataEntry : ObservableObject public class UnkMetaDataEntry : IMetaDataEntry { - private readonly UnknownMetaEntry _input; + private readonly ParsedUnknownMetadataAttribute _input; - public UnkMetaDataEntry(UnknownMetaEntry unknownMeta) + public UnkMetaDataEntry(ParsedUnknownMetadataAttribute unknownMeta) { _input = unknownMeta; 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 a7741614b..8f8d27d30 100644 --- a/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs +++ b/Shared/ByteParsing/Shared.ByteParsing/Parsers/IByteParser.cs @@ -30,6 +30,7 @@ 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/Parsing/MetaDataFileParser.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs index c00b3bfb8..b8df122b7 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs @@ -67,13 +67,13 @@ public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer return outputFile; } - List ExploratoryGetEntries(byte[] fileContent) + List ExploratoryGetEntries(byte[] fileContent) { var byteLength = fileContent.Length; - var output = new List(); + var output = new List(); var currentIndex = 0 + 8; // version and num elements - UnknownMetaEntry currentElement; + ParsedUnknownMetadataAttribute currentElement; while (currentIndex != byteLength && (currentElement = GetElement(currentIndex, fileContent, out currentIndex)) != null) output.Add(currentElement); @@ -117,7 +117,7 @@ public byte[] GenerateBytes(int version, ParsedMetadataFile metaFile) } - UnknownMetaEntry GetElement(int startIndex, byte[] data, out int updatedByteIndex) + ParsedUnknownMetadataAttribute GetElement(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}"); @@ -140,7 +140,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, diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs index 2b9917f38..9a2e4f2fb 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs @@ -213,7 +213,7 @@ List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry) return _typeTable[key]; } - public ParsedMetadataAttribute? DeSerialize(UnknownMetaEntry entry, out string? errorMessage) + public ParsedMetadataAttribute? DeSerialize(ParsedUnknownMetadataAttribute entry, out string? errorMessage) { var possibleClassLayouts = GetPossibleClassLayoutsForMetaDataAttribute(entry); if (possibleClassLayouts == null) @@ -290,20 +290,22 @@ public byte[] Serialize(ParsedMetadataAttribute entry, out string? errorMessage) foreach (var proptery in entryInfo.Properties) { var parser = ByteParserFactory.Create(proptery.PropertyType); - try + //try { object propertyValue = GetMemberValue(entry, proptery.Name); - var attributeByteValue = parser.Encode(null, out var writeError); - //data.AddRange(attributeByteValue); - } - catch (Exception e) - { - - break; + var attributeByteValue = parser.Encode(propertyValue); + data.AddRange(attributeByteValue); } + //catch (Exception e) + //{ + // + // break; + //} } } + return data.ToArray(); + return null; } diff --git a/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs index 9cb8dffe2..7fa1f5813 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs @@ -29,7 +29,7 @@ public abstract class ParsedMetadataAttribute } - public class UnknownMetaEntry : ParsedMetadataAttribute + public class ParsedUnknownMetadataAttribute : ParsedMetadataAttribute { } From f5726d72a56e33a209a43c49fd85937841b71fe6 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Wed, 25 Feb 2026 20:25:20 +0100 Subject: [PATCH 04/12] Code --- .../AnimationBinWh3FileToXmlConverter.cs | 2 +- .../MetaEditor/Commands/SaveCommand.cs | 52 +++------ .../MetaEditor/MetaDataEditorViewModel.cs | 2 +- .../Animation/AnimMetaDataReportGenerator.cs | 4 +- .../Parsing/MetaDataFileParser.cs | 103 +++++++----------- .../Parsing/MetaDataTagDeSerializer.cs | 75 ++++++------- .../Parsing/ParsedMetadataFile.cs | 9 +- 7 files changed, 94 insertions(+), 153 deletions(-) diff --git a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs index 58a9eec2f..0ebfba540 100644 --- a/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs +++ b/Editors/AnimationFragmentEditor/Editor.AnimationFragmentEditor/AnimationPack/Converters/AnimationBinWh3Converter/AnimationBinWh3FileToXmlConverter.cs @@ -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/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index 44f0b3bc6..5c2f24056 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs @@ -48,48 +48,24 @@ public bool Execute(MetaDataEditorViewModel controller) _logger.Here().Information("Generating bytes"); + var parser = new MetaDataFileParser(); + var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); + _logger.Here().Information("Saving"); + var res = _packFileSaveService.Save(path, bytes, false); + if (res != null) { - var parser = new MetaDataFileParser(); - var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, tagDataItems); - _logger.Here().Information("Saving"); - var res = _packFileSaveService.Save(path, bytes, false); - if (res != null) - { - controller.CurrentFile = res; - controller.DisplayName = res.Name; - } - - _logger.Here().Information("Creating metadata file complete"); - var saveEvent = new ScopedFileSavedEvent() - { - FileOwner = controller, - NewPath = path, - }; - _eventHub.Publish(saveEvent); + controller.CurrentFile = res; + controller.DisplayName = res.Name; } + _logger.Here().Information("Creating metadata file complete"); + var saveEvent = new ScopedFileSavedEvent() { - - - - var parser = new MetaDataFileParser(); - var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); - _logger.Here().Information("Saving"); - var res = _packFileSaveService.Save(path, bytes, false); - if (res != null) - { - controller.CurrentFile = res; - controller.DisplayName = res.Name; - } - - _logger.Here().Information("Creating metadata file complete"); - var saveEvent = new ScopedFileSavedEvent() - { - FileOwner = controller, - NewPath = path, - }; - _eventHub.Publish(saveEvent); - } + FileOwner = controller, + NewPath = path, + }; + _eventHub.Publish(saveEvent); + return true; diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index cfdb40bb5..6df0ca88c 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -60,7 +60,7 @@ public void LoadFile(PackFile file) _metaDataFile = loadedMetadataFile; - foreach (var metadataEntry in loadedMetadataFile.Items) + foreach (var metadataEntry in loadedMetadataFile.Attributes) { if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta) Tags.Add(new UnkMetaDataEntry(uknMeta)); diff --git a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs index 403010f3b..2d2e821a1 100644 --- a/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs +++ b/Editors/Reports/Animation/AnimMetaDataReportGenerator.cs @@ -82,7 +82,7 @@ public void Create() 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(); @@ -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/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs index b8df122b7..f66af5b75 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs @@ -19,7 +19,7 @@ public class MetaDataFileParser public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDataTagDeSerializer) { - var contentLength = fileContent.Count(); + var contentLength = fileContent.Length; var outputFile = new ParsedMetadataFile() { @@ -29,95 +29,74 @@ public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer 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 = metaDataTagDeSerializer.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) - { - var byteLength = fileContent.Length; - var output = new List(); - var currentIndex = 0 + 8; // version and num elements - - ParsedUnknownMetadataAttribute currentElement; - while (currentIndex != byteLength && (currentElement = GetElement(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(); - } - public byte[] GenerateBytes(int version, ParsedMetadataFile metaFile) { - var metaDataTagDeSerializer = new MetaDataTagDeSerializer(); - - var data = new List(); data.AddRange(BitConverter.GetBytes(metaFile.Version)); - data.AddRange(BitConverter.GetBytes(metaFile.Items.Count())); - foreach (var item in metaFile.Items) + data.AddRange(BitConverter.GetBytes(metaFile.Attributes.Count())); + foreach (var item in metaFile.Attributes) { - metaDataTagDeSerializer.Serialize(item, out var errorStr) ; + var bytes = metaDataTagDeSerializer.Serialize(item, out var errorStr) ; data.AddRange(ByteParsers.String.Encode(item.Name, out _)); - // data.AddRange(item.DataItem.Bytes); + data.AddRange(bytes); } return data.ToArray(); } + List GetAttributes(byte[] fileContent) + { + var byteLength = fileContent.Length; + var output = new List(); + var currentIndex = 0 + 8; // version and num elements + + ParsedUnknownMetadataAttribute currentElement; + while (currentIndex != byteLength && (currentElement = GetAttribute(currentIndex, fileContent, out currentIndex)) != null) + output.Add(currentElement); + + return output; + } + - ParsedUnknownMetadataAttribute 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}"); diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs index 9a2e4f2fb..94701923a 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs @@ -1,4 +1,5 @@ using System.Reflection; +using CommunityToolkit.Diagnostics; using Shared.ByteParsing; namespace Shared.GameFormats.AnimationMeta.Parsing @@ -258,6 +259,8 @@ List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry) } var typedInstance = attributeInstance as ParsedMetadataAttribute; + Guard.IsNotNull(typedInstance, $"Failed to convert {attributeInstance} into {nameof(ParsedMetadataAttribute)}"); + typedInstance.Name = entry.Name; typedInstance.Data = bytes; errorMessage = null; @@ -268,76 +271,48 @@ List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry) } - public byte[] Serialize(ParsedMetadataAttribute entry, out string? errorMessage) + public byte[]? Serialize(ParsedMetadataAttribute entry, out string? errorMessage) { - var entryInfoList = GetPossibleClassLayoutsForMetaDataAttribute(entry); - if (entryInfoList == null) + var classLayout = GetClassLayoutsForMetaDataAttribute(entry); + if (classLayout == null) { errorMessage = $"Unable to find decoder for serializing {entry.Name}_{entry.Version}"; return null; } - errorMessage = null; - - + // Convert the class to bytes by getting the class layout and serializing each property in order. var data = new List(); - // data.AddRange(BitConverter.GetBytes(metaFile.Version)); - // data.AddRange(BitConverter.GetBytes(metaFile.Items.Count())); - - foreach (var entryInfo in entryInfoList) + foreach (var proptery in classLayout.Properties) { - // var instance = Activator.CreateInstance(entryInfo.Type); - foreach (var proptery in entryInfo.Properties) - { - var parser = ByteParserFactory.Create(proptery.PropertyType); - //try - { - object propertyValue = GetMemberValue(entry, proptery.Name); - var attributeByteValue = parser.Encode(propertyValue); - data.AddRange(attributeByteValue); - } - //catch (Exception e) - //{ - // - // break; - //} - } + var propertyValue = GetMemberValue(entry, proptery.Name); + var parser = ByteParserFactory.Create(proptery.PropertyType); + var attributeByteValue = parser.Encode(propertyValue); + data.AddRange(attributeByteValue); } - + + errorMessage = null; return data.ToArray(); - - return null; } - - // - public static object GetMemberValue(object obj, string memberName) { if (obj == null) - { throw new ArgumentNullException(nameof(obj)); - } - - Type type = obj.GetType(); + + var type = obj.GetType(); // Try to get as a Property - PropertyInfo propInfo = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + 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 - FieldInfo fieldInfo = type.GetField(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + 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}'."); } - // @@ -426,6 +401,20 @@ public ParsedMetadataAttribute CreateDefault(string itemName) 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; + + } + public record EntryInfoResult(Type? Type, List Properties); } diff --git a/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs index 7fa1f5813..26936bcad 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/ParsedMetadataFile.cs @@ -4,13 +4,10 @@ namespace Shared.GameFormats.AnimationMeta.Parsing { 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(); } From b43d1b5a78c99e82ab7319d0052463a42066d262 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Wed, 25 Feb 2026 20:52:53 +0100 Subject: [PATCH 05/12] Code --- .../MetaEditor/Commands/CopyPastCommand.cs | 82 ++++++++++++++----- .../MetaEditor/Commands/SaveCommand.cs | 24 ++---- .../MetaEditor/MetaDataEditorViewModel.cs | 10 ++- .../AnimationMeta/MetaEditor/MetaDataEntry.cs | 61 +------------- .../Parsing/MetaDataTagDeSerializer.cs | 2 + .../AnimationMeta/Parsing/MetaDataTagItem.cs | 22 ----- 6 files changed, 82 insertions(+), 119 deletions(-) delete mode 100644 Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagItem.cs diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs index ae50438ab..00869cb5e 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Drawing.Imaging; using System.Linq; +using System.Reflection; using System.Windows; using Editors.AnimationMeta.Presentation; using Shared.Core.Events; @@ -12,7 +14,7 @@ namespace Editors.AnimationMeta.MetaEditor.Commands public class MetaDataTagCopyItem : ICopyPastItem { public string Description => "Copy object for MetaDataTag"; - public List Items { get; set; } = []; + public List Items { get; set; } = []; } class CopyPastCommand : IUiCommand @@ -33,16 +35,37 @@ public void ExecuteCopy(MetaDataEditorViewModel controller) .ToList(); // Check for errors + foreach (var tag in selectedTags) { - if (string.IsNullOrWhiteSpace(tag.HasError()) == false) + 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 = CreateShallowCopy(item._input); + copyPastItem.Items.Add(copy); + + } + _copyPasteManager.SetCopyItem(copyPastItem); + } + + + /* var metaDataTagDeSerializer = new MetaDataTagDeSerializer(); + + var data = new List(); + + foreach (var item in selectedTags) + { + var bytes = metaDataTagDeSerializer.Serialize(item., out var errorStr); + + + + var copyPastItem = new MetaDataTagCopyItem(); foreach (var tag in selectedTags) { var fileFormatData = tag.GetAsFileFormatData(); @@ -54,36 +77,51 @@ public void ExecuteCopy(MetaDataEditorViewModel controller) }; copyPastItem.Items.Add(entry); } - _copyPasteManager.SetCopyItem(copyPastItem); - } + _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; + controller._metaDataFile.Attributes.AddRange(pastObject.Items); + } + + controller.UpdateView(); + } - foreach (var item in pasteObjects) + 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) { - 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)); - } + // Get the value from the original object and set it on the new copy. + object value = property.GetValue(original); + property.SetValue(copy, value); } - return; } + return copy; } diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index 5c2f24056..3513c8091 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/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,36 +15,32 @@ class SaveCommand : IUiCommand private readonly IPackFileService _packFileService; private readonly IEventHub _eventHub; private readonly IFileSaveService _packFileSaveService; + private readonly IStandardDialogs _standardDialogs; - public SaveCommand(IPackFileService packFileService, IEventHub eventHub, IFileSaveService packFileSaveService) + public SaveCommand(IPackFileService packFileService, IEventHub eventHub, IFileSaveService packFileSaveService, IStandardDialogs standardDialogs) { _packFileService = packFileService; _eventHub = eventHub; _packFileSaveService = packFileSaveService; + _standardDialogs = standardDialogs; } 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, controller._metaDataFile); @@ -66,8 +60,6 @@ public bool Execute(MetaDataEditorViewModel controller) }; _eventHub.Publish(saveEvent); - - return true; } } diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index 6df0ca88c..5cbb91b19 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -46,7 +46,7 @@ public void LoadFile(PackFile file) return; CurrentFile = file; - Tags.Clear(); + DisplayName = file == null ? "" : file.Name; if (file == null) @@ -60,7 +60,13 @@ public void LoadFile(PackFile file) _metaDataFile = loadedMetadataFile; - foreach (var metadataEntry in loadedMetadataFile.Attributes) + UpdateView(); + } + + public void UpdateView() + { + Tags.Clear(); + foreach (var metadataEntry in _metaDataFile.Attributes) { if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta) Tags.Add(new UnkMetaDataEntry(uknMeta)); diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs index b70deece6..fca0418e8 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs @@ -1,21 +1,19 @@ using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; 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 { + public ParsedMetadataAttribute _input; + [ObservableProperty] ObservableCollection _variables = []; [ObservableProperty] string _displayName = ""; @@ -24,7 +22,6 @@ public abstract partial class IMetaDataEntry : ObservableObject [ObservableProperty] int _version; [ObservableProperty] bool _isSelected; - public abstract MetaDataTagItem GetAsFileFormatData(); public abstract string HasError(); } @@ -41,26 +38,17 @@ public UnkMetaDataEntry(ParsedUnknownMetadataAttribute unknownMeta) 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(ParsedMetadataAttribute typedMetaItem, MetaDataTagDeSerializer metaDataTagDeSerializer) { + _input = typedMetaItem; _originalName = typedMetaItem.Name; DisplayName = typedMetaItem.DisplayName; Description = metaDataTagDeSerializer.GetDescriptionSafe(_originalName); @@ -118,47 +106,6 @@ public override string HasError() return null; } - public override MetaDataTagItem GetAsFileFormatData() - { - // Go though all using reflection. - // Get the byte - - - _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 = ""; diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs index 94701923a..927b06e91 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs @@ -4,6 +4,8 @@ namespace Shared.GameFormats.AnimationMeta.Parsing { + // Split into database and serializer + public class MetaDataTagDeSerializer { private readonly Dictionary> _typeTable = []; 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; } - } -} From 564c63d649572e938c775b053d8e2d2855a57ac5 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Thu, 26 Feb 2026 21:13:45 +0100 Subject: [PATCH 06/12] Code --- .../AnimationPack/AnimPackViewModel.cs | 14 +- .../AnimationBinWh3FileToXmlConverter.cs | 6 +- .../DependencyInjectionContainer.cs | 3 - .../MetaEditor/Commands/CopyPastCommand.cs | 76 +---- .../MetaEditor/Commands/NewEntryCommand.cs | 15 +- .../MetaEditor/Commands/SaveCommand.cs | 7 +- .../MetaEditor/MetaDataEditorViewModel.cs | 15 +- .../AnimationMeta/MetaEditor/MetaDataEntry.cs | 4 +- .../SuperView/SuperViewViewModel.cs | 16 +- .../Animation/AnimMetaDataJsonGenerator.cs | 16 +- .../Animation/AnimMetaDataReportGenerator.cs | 16 +- ...agDeSerializer.cs => IMetaDataDatabase.cs} | 276 ++++-------------- .../Parsing/MetaDataFileParser.cs | 229 +++++++++++++-- .../GameFiles/DependencyInjectionContainer.cs | 3 + Shared/SharedCore/Misc/ReflectionHelper.cs | 57 ++++ Shared/SharedCore/Misc/StringSanitizer.cs | 19 +- 16 files changed, 403 insertions(+), 369 deletions(-) rename Shared/GameFiles/AnimationMeta/Parsing/{MetaDataTagDeSerializer.cs => IMetaDataDatabase.cs} (60%) create mode 100644 Shared/SharedCore/Misc/ReflectionHelper.cs 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 0ebfba540..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) diff --git a/Editors/AnimationMeta/DependencyInjectionContainer.cs b/Editors/AnimationMeta/DependencyInjectionContainer.cs index aa5bf5982..d63942db7 100644 --- a/Editors/AnimationMeta/DependencyInjectionContainer.cs +++ b/Editors/AnimationMeta/DependencyInjectionContainer.cs @@ -5,12 +5,10 @@ using Editors.AnimationMeta.SuperView; 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,7 +16,6 @@ public class DependencyInjectionContainer : DependencyContainer { public override void Register(IServiceCollection serviceCollection) { - serviceCollection.AddSingleton(); serviceCollection.AddTransient(); serviceCollection.AddTransient(); diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs index 00869cb5e..166eee946 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Drawing.Imaging; +using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Windows; using Editors.AnimationMeta.Presentation; using Shared.Core.Events; @@ -20,12 +17,12 @@ public class MetaDataTagCopyItem : ICopyPastItem class CopyPastCommand : IUiCommand { private readonly CopyPasteManager _copyPasteManager; - private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + private readonly MetaDataFileParser _metaDataFileParser; - public CopyPastCommand(CopyPasteManager copyPasteManager, MetaDataTagDeSerializer metaDataTagDeSerializer) + public CopyPastCommand(CopyPasteManager copyPasteManager, MetaDataFileParser metaDataFileParser) { _copyPasteManager = copyPasteManager; - _metaDataTagDeSerializer = metaDataTagDeSerializer; + _metaDataFileParser = metaDataFileParser; } public void ExecuteCopy(MetaDataEditorViewModel controller) @@ -47,43 +44,12 @@ public void ExecuteCopy(MetaDataEditorViewModel controller) var copyPastItem = new MetaDataTagCopyItem(); foreach (var item in selectedTags) { - var copy = CreateShallowCopy(item._input); + var copy = ReflectionHelper.CreateShallowCopy(item._input); copyPastItem.Items.Add(copy); } _copyPasteManager.SetCopyItem(copyPastItem); } - - - /* var metaDataTagDeSerializer = new MetaDataTagDeSerializer(); - - var data = new List(); - - foreach (var item in selectedTags) - { - var bytes = metaDataTagDeSerializer.Serialize(item., out var errorStr); - - - - var copyPastItem = new MetaDataTagCopyItem(); - foreach (var tag in selectedTags) - { - var fileFormatData = tag.GetAsFileFormatData(); - var entry = new ParsedUnknownMetadataAttribute() - { - Name = fileFormatData.Name, - Data = fileFormatData.DataItem.Bytes, - Version = tag.Version, - }; - copyPastItem.Items.Add(entry); - } - _copyPasteManager.SetCopyItem(copyPastItem);*/ - - - - - - public void ExecutePaste(MetaDataEditorViewModel controller) { @@ -95,38 +61,6 @@ public void ExecutePaste(MetaDataEditorViewModel controller) controller.UpdateView(); } - - 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/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs index 0a4712806..aeca9dd88 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs @@ -9,17 +9,19 @@ namespace Editors.AnimationMeta.MetaEditor.Commands { internal class NewEntryCommand : IUiCommand { - private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + private readonly MetaDataFileParser _metaDataFileParser; + private readonly IMetaDataDatabase _metaDataDatabase; - public NewEntryCommand(MetaDataTagDeSerializer metaDataTagDeSerializer) + public NewEntryCommand(MetaDataFileParser metaDataFileParser, IMetaDataDatabase metaDataDatabase) { - _metaDataTagDeSerializer = metaDataTagDeSerializer; + _metaDataFileParser = metaDataFileParser; + _metaDataDatabase = metaDataDatabase; } 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 +32,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); controller.Tags.Add(newTagView); } diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index 3513c8091..58b31858c 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs @@ -16,13 +16,15 @@ class SaveCommand : IUiCommand private readonly IEventHub _eventHub; private readonly IFileSaveService _packFileSaveService; private readonly IStandardDialogs _standardDialogs; + private readonly MetaDataFileParser _metaDataFileParser; - public SaveCommand(IPackFileService packFileService, IEventHub eventHub, IFileSaveService packFileSaveService, IStandardDialogs standardDialogs) + 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) @@ -42,8 +44,7 @@ public bool Execute(MetaDataEditorViewModel controller) var path = _packFileService.GetFullPath(controller.CurrentFile); _logger.Here().Information("Creating metadata file. TagCount=" + controller.Tags.Count + " " + path); - var parser = new MetaDataFileParser(); - var bytes = parser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); + var bytes = _metaDataFileParser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); _logger.Here().Information("Saving"); var res = _packFileSaveService.Save(path, bytes, false); if (res != null) diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index 5cbb91b19..d28dbf226 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -13,8 +13,7 @@ namespace Editors.AnimationMeta.Presentation public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterface, ISaveableEditor, IFileEditor { private readonly IUiCommandFactory _uiCommandFactory; - private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; - + private readonly MetaDataFileParser _metaDataFileParser; public ParsedMetadataFile _metaDataFile; [ObservableProperty] string _displayName = "Metadata Editor"; @@ -25,10 +24,10 @@ public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterfac public bool HasUnsavedChanges { get; set; } = false; public PackFile CurrentFile { get; set; } - public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataTagDeSerializer metaDataTagDeSerializer) + public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataFileParser metaDataFileParser) { _uiCommandFactory = uiCommandFactory; - _metaDataTagDeSerializer = metaDataTagDeSerializer; + _metaDataFileParser = metaDataFileParser; } partial void OnSelectedTagChanged(IMetaDataEntry value) @@ -54,8 +53,7 @@ public void LoadFile(PackFile file) var fileContent = CurrentFile.DataSource.ReadData(); - var parser = new MetaDataFileParser(); - var loadedMetadataFile = parser.ParseFile(fileContent, _metaDataTagDeSerializer); + var loadedMetadataFile = _metaDataFileParser.ParseFile(fileContent); MetaDataFileVersion = loadedMetadataFile.Version; _metaDataFile = loadedMetadataFile; @@ -71,7 +69,10 @@ public void UpdateView() if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta) Tags.Add(new UnkMetaDataEntry(uknMeta)); else if (metadataEntry is ParsedMetadataAttribute parsedKnownAttribute) - Tags.Add(new MetaDataEntry(parsedKnownAttribute, _metaDataTagDeSerializer)); + { + var desc = _metaDataFileParser.GetDatabase().GetDescriptionSafe(parsedKnownAttribute.DisplayName); + Tags.Add(new MetaDataEntry(parsedKnownAttribute, desc)); + } else throw new Exception($"{metadataEntry.GetType()} is not a known type for {nameof(MetaDataEditorViewModel)}"); } diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs index fca0418e8..4bd81167b 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs @@ -46,12 +46,12 @@ public class MetaDataEntry : IMetaDataEntry private readonly string _originalName; - public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, MetaDataTagDeSerializer metaDataTagDeSerializer) + public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description) { _input = typedMetaItem; _originalName = typedMetaItem.Name; DisplayName = typedMetaItem.DisplayName; - Description = metaDataTagDeSerializer.GetDescriptionSafe(_originalName); + Description = description; Version = typedMetaItem.Version; var orderedPropertiesList = typedMetaItem.GetType().GetProperties() diff --git a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs index 10b6cf579..2da1b62fe 100644 --- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs +++ b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs @@ -19,7 +19,7 @@ public partial class SuperViewViewModel : EditorHostBase SceneObjectViewModel _asset; private readonly SceneObjectEditor _sceneObjectBuilder; - private readonly MetaDataTagDeSerializer _metaDataTagDeSerializer; + private readonly MetaDataFileParser _metaDataFileParser; private readonly IMetaDataFactory _metaDataFactory; private readonly IPackFileService _packFileService; private readonly IEventHub _eventHub; @@ -38,7 +38,7 @@ public SuperViewViewModel( IUiCommandFactory uiCommandFactory, SceneObjectEditor sceneObjectBuilder, IEditorHostParameters editorHostParameters, - MetaDataTagDeSerializer metaDataTagDeSerializer, + MetaDataFileParser metaDataFileParser, IMetaDataFactory metaDataFactory) : base(editorHostParameters) { @@ -47,7 +47,7 @@ public SuperViewViewModel( _eventHub = eventHub; _uiCommandFactory = uiCommandFactory; _sceneObjectBuilder = sceneObjectBuilder; - _metaDataTagDeSerializer = metaDataTagDeSerializer; + _metaDataFileParser = metaDataFileParser; _metaDataFactory = metaDataFactory; Initialize(); eventHub.Register(this, OnFileSaved); @@ -67,8 +67,8 @@ private void OnFileSaved(ScopedFileSavedEvent evnt) void Initialize() { - PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer); - MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataTagDeSerializer); + PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser); + MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser); var assetViewModel = _sceneObjectViewModelBuilder.CreateAsset("SuperViewRoot", true, "Root", Color.Black,null); SceneObjects.Add(assetViewModel); @@ -86,9 +86,9 @@ void RecreateMetaDataInformation(SceneObject model) 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); + + var persist = _metaDataFileParser.ParseFile(model.PersistMetaData); + var meta = _metaDataFileParser.ParseFile(model.MetaData); model.MetaDataItems = _metaDataFactory.Create(persist, meta, model.MainNode, model, model.Player, SceneObjects[0].FragAndSlotSelection.FragmentList.SelectedItem); } 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 2d2e821a1..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(); } @@ -77,8 +77,8 @@ 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; @@ -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) { diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs b/Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs similarity index 60% rename from Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs rename to Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs index 927b06e91..21f87dfde 100644 --- a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataTagDeSerializer.cs +++ b/Shared/GameFiles/AnimationMeta/Parsing/IMetaDataDatabase.cs @@ -1,23 +1,43 @@ using System.Reflection; -using CommunityToolkit.Diagnostics; -using Shared.ByteParsing; namespace Shared.GameFormats.AnimationMeta.Parsing { - // Split into database and serializer + public interface IMetaDataDatabase + { + string GetDescription(string metaDataTagName); + string GetDescriptionSafe(string metaDataTagName); + List GetSupportedTypes(); + + List GetDefinition(string metadataName); + } - public class MetaDataTagDeSerializer + 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 = @@ -76,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"; @@ -180,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]; @@ -187,6 +227,8 @@ public string GetDescription(string metaDataTagName) public string GetDescriptionSafe(string metaDataTagName) { + EnsureMappingTableCreated(); + if (_descriptionMap.ContainsKey(metaDataTagName) == false) return "Missing"; return _descriptionMap[metaDataTagName]; @@ -194,230 +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); } - - /// - /// 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 - /// - List GetPossibleTypesForMetaDataAttribute(ParsedMetadataAttribute entry) - { - var key = entry.Name + "_" + entry.Version; - if (_typeTable.ContainsKey(key) == false) - return []; - - return _typeTable[key]; - } - - public ParsedMetadataAttribute? DeSerialize(ParsedUnknownMetadataAttribute entry, out string? errorMessage) - { - var possibleClassLayouts = GetPossibleClassLayoutsForMetaDataAttribute(entry); - if (possibleClassLayouts == null) - { - errorMessage = $"Unable to find decoder for deserializing {entry.Name}_{entry.Version}"; - return null; - } - - 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 = GetMemberValue(entry, proptery.Name); - var parser = ByteParserFactory.Create(proptery.PropertyType); - var attributeByteValue = parser.Encode(propertyValue); - data.AddRange(attributeByteValue); - } - - errorMessage = null; - return data.ToArray(); - } - - 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 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) - { - 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; - } - - 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; - - } - - public record EntryInfoResult(Type? Type, List Properties); - } } diff --git a/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs b/Shared/GameFiles/AnimationMeta/Parsing/MetaDataFileParser.cs index f66af5b75..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,15 +12,23 @@ namespace Shared.GameFormats.AnimationMeta.Parsing public class MetaDataFileParser { private readonly ILogger _logger = Logging.Create(); + private readonly IMetaDataDatabase _metaDataDatabase; - public ParsedMetadataFile? 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 ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer metaDataTagDeSerializer) + public ParsedMetadataFile ParseFile(byte[] fileContent) { var contentLength = fileContent.Length; @@ -42,7 +53,7 @@ public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer { try { - var deserializedAttribute = metaDataTagDeSerializer.DeSerialize(attribute, out var errorStr); + var deserializedAttribute = DeSerialize(attribute, out var errorStr); if (deserializedAttribute != null) { outputFile.Attributes.Add(deserializedAttribute); @@ -65,16 +76,12 @@ public ParsedMetadataFile ParseFile(byte[] fileContent, MetaDataTagDeSerializer public byte[] GenerateBytes(int version, ParsedMetadataFile metaFile) { - var metaDataTagDeSerializer = new MetaDataTagDeSerializer(); - 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 = metaDataTagDeSerializer.Serialize(item, out var errorStr) ; - - + var bytes = Serialize(item, out var errorStr) ; data.AddRange(ByteParsers.String.Encode(item.Name, out _)); data.AddRange(bytes); } @@ -105,7 +112,7 @@ ParsedUnknownMetadataAttribute GetAttribute(int startIndex, byte[] data, out int for (; currentIndex < data.Length; currentIndex++) { - if (IsAllCapsCaString(currentIndex, data)) + if (StringSanitizer.IsAllCapsCaString(currentIndex, data)) break; } @@ -129,19 +136,203 @@ ParsedUnknownMetadataAttribute GetAttribute(int startIndex, byte[] data, out int 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/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/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; + } } } From 3a62e870e78fd98a9cea70fef6f71412751eb8a0 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Thu, 26 Feb 2026 21:23:22 +0100 Subject: [PATCH 07/12] Code --- .../MetaEditor/MetaDataAttribute.cs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs b/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs index d57624fc8..2e64078ac 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs @@ -65,19 +65,10 @@ void Validate() } } - - 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(0, 0, 0); @@ -105,26 +96,10 @@ private void OnValueChangedCallback(Vector3 vector) _property.SetValue(_target, value.ToVector4()); } - 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; @@ -143,19 +118,6 @@ private void OnValueChangedCallback(Vector3 vector) var vector3 = Value.GetAsVector3(); _property.SetValue(_target, vector3); } - - 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; - } } } From a9bc126fd7a0390d603b670beb1187892f8bf716 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sun, 1 Mar 2026 07:35:28 +0100 Subject: [PATCH 08/12] Code --- .../DependencyInjectionContainer.cs | 2 +- ...DataAttribute.cs => AttributeViewModel.cs} | 31 ++++-- .../MetaEditor/Commands/NewEntryCommand.cs | 6 +- .../MetaEditor/MetaDataEditorViewModel.cs | 18 +++- ...ataEntry.cs => MetaDataEntryViewModel .cs} | 22 +++-- .../MetaEditor/PropertyViewModel.cs | 59 ------------ .../View/MetaDataAttributeView.xaml | 6 +- .../SuperView/SuperViewViewModel.cs | 35 ++++--- .../Instances/DrawableMetaInstance.cs | 2 +- ...{MetaDataFactory.cs => MetaDataBuilder.cs} | 94 +++++++++++-------- .../View3D/Animation/AnimationSampler.cs | 4 - .../AnimationsContainerComponent.cs | 2 +- .../AnimationMeta/Definitions/AnimatedProp.cs | 6 +- 13 files changed, 138 insertions(+), 149 deletions(-) rename Editors/AnimationMeta/MetaEditor/{MetaDataAttribute.cs => AttributeViewModel.cs} (74%) rename Editors/AnimationMeta/MetaEditor/{MetaDataEntry.cs => MetaDataEntryViewModel .cs} (81%) delete mode 100644 Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs rename Editors/AnimationMeta/SuperView/Visualisation/{MetaDataFactory.cs => MetaDataBuilder.cs} (79%) diff --git a/Editors/AnimationMeta/DependencyInjectionContainer.cs b/Editors/AnimationMeta/DependencyInjectionContainer.cs index d63942db7..ed4f05620 100644 --- a/Editors/AnimationMeta/DependencyInjectionContainer.cs +++ b/Editors/AnimationMeta/DependencyInjectionContainer.cs @@ -22,7 +22,7 @@ public override void Register(IServiceCollection serviceCollection) 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/MetaEditor/MetaDataAttribute.cs b/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs similarity index 74% rename from Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs rename to Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs index 2e64078ac..422241b68 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataAttribute.cs +++ b/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs @@ -5,17 +5,24 @@ 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 partial class MetaDataAttribute : ObservableObject + public class MetaDataAttributeChangedEvent() + { + + } + + public partial class AttributeViewModel : ObservableObject { - private readonly ILogger _logger = Logging.Create(); + 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; @@ -24,11 +31,12 @@ public partial class MetaDataAttribute : ObservableObject [ObservableProperty] bool _isReadOnly = true; [ObservableProperty] bool _isValid = true; - public MetaDataAttribute(IByteParser parser, object value, object target, PropertyInfo property) + public AttributeViewModel(IByteParser parser, object value, object target, PropertyInfo property, IEventHub eventHub) { _parser = parser; _target = target; _property = property; + _eventHub = eventHub; _valueAsString = value.ToString(); Validate(); } @@ -62,19 +70,21 @@ void Validate() _logger.Here().Error(loggingStr); throw new ArgumentException(loggingStr); } + + _eventHub.Publish(new MetaDataAttributeChangedEvent()); } } } - public partial class OrientationMetaDataAttribute : MetaDataAttribute + public partial class OrientationAttributeViewModel : AttributeViewModel { private readonly Vector4Parser _typedParser; [ObservableProperty] Vector3ViewModel _value = new(0, 0, 0); - public OrientationMetaDataAttribute(Vector4Parser parser, Vector4 value, object target, PropertyInfo property) - : base(parser, value, target, property) + public OrientationAttributeViewModel(Vector4Parser parser, Vector4 value, object target, PropertyInfo property, IEventHub eventHub) + : base(parser, value, target, property, eventHub) { _value = new(0, 0, 0, OnValueChangedCallback); @@ -94,17 +104,20 @@ private void OnValueChangedCallback(Vector3 vector) var value = MathUtil.EulerDegreesToQuaternion(vector3); value.Normalize(); _property.SetValue(_target, value.ToVector4()); + + _eventHub.Publish(new MetaDataAttributeChangedEvent()); } } - public partial class VectorMetaDataAttribute : MetaDataAttribute + public partial class VectorAttributeViewModel : AttributeViewModel { private readonly Vector3Parser _parser; [ObservableProperty] Vector3ViewModel _value; - public VectorMetaDataAttribute(Vector3Parser parser, Vector3 value, object target, PropertyInfo property) : base(parser, value, target, property) + public VectorAttributeViewModel(Vector3Parser parser, Vector3 value, object target, PropertyInfo property, IEventHub eventHub) + : base(parser, value, target, property, eventHub) { _value = new(0, 0, 0, OnValueChangedCallback); _parser = parser; @@ -117,6 +130,8 @@ private void OnValueChangedCallback(Vector3 vector) { var vector3 = Value.GetAsVector3(); _property.SetValue(_target, vector3); + + _eventHub.Publish(new MetaDataAttributeChangedEvent()); } } } diff --git a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs index aeca9dd88..507a3c7eb 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs @@ -11,11 +11,13 @@ internal class NewEntryCommand : IUiCommand { private readonly MetaDataFileParser _metaDataFileParser; private readonly IMetaDataDatabase _metaDataDatabase; + private readonly IEventHub _eventHub; - public NewEntryCommand(MetaDataFileParser metaDataFileParser, IMetaDataDatabase metaDataDatabase) + public NewEntryCommand(MetaDataFileParser metaDataFileParser, IMetaDataDatabase metaDataDatabase, IEventHub eventHub) { _metaDataFileParser = metaDataFileParser; _metaDataDatabase = metaDataDatabase; + _eventHub = eventHub; } public void Execute(MetaDataEditorViewModel controller) @@ -34,7 +36,7 @@ public void Execute(MetaDataEditorViewModel controller) { var newEntry = _metaDataFileParser.CreateDefault(model.SelectedItem); var desc = _metaDataDatabase.GetDescriptionSafe(newEntry.DisplayName); - var newTagView = new MetaDataEntry(newEntry, desc); + var newTagView = new MetaDataEntry(newEntry, desc, _eventHub); controller.Tags.Add(newTagView); } diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index d28dbf226..d4219d27d 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs @@ -14,26 +14,34 @@ public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterfac { private readonly IUiCommandFactory _uiCommandFactory; private readonly MetaDataFileParser _metaDataFileParser; + private readonly IEventHub _eventHub; public ParsedMetadataFile _metaDataFile; + public ParsedMetadataAttribute _selectedAttribute; [ObservableProperty] string _displayName = "Metadata Editor"; - [ObservableProperty] IMetaDataEntry _selectedTag; - [ObservableProperty] ObservableCollection _tags = []; + [ObservableProperty] IMetaDataEntryViewModel _selectedTag; + [ObservableProperty] ObservableCollection _tags = []; [ObservableProperty] int _metaDataFileVersion; public bool HasUnsavedChanges { get; set; } = false; public PackFile CurrentFile { get; set; } - public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataFileParser metaDataFileParser) + public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataFileParser metaDataFileParser, IEventHub eventHub) { _uiCommandFactory = uiCommandFactory; _metaDataFileParser = metaDataFileParser; + _eventHub = eventHub; } - partial void OnSelectedTagChanged(IMetaDataEntry value) + partial void OnSelectedTagChanged(IMetaDataEntryViewModel value) { + if(value == null) + _selectedAttribute = null; + else + _selectedAttribute = value._input; + _eventHub.Publish(new MetaDataAttributeChangedEvent()); } public bool Save() => _uiCommandFactory.Create().Execute(this); @@ -71,7 +79,7 @@ public void UpdateView() else if (metadataEntry is ParsedMetadataAttribute parsedKnownAttribute) { var desc = _metaDataFileParser.GetDatabase().GetDescriptionSafe(parsedKnownAttribute.DisplayName); - Tags.Add(new MetaDataEntry(parsedKnownAttribute, desc)); + Tags.Add(new MetaDataEntry(parsedKnownAttribute, desc, _eventHub )); } else throw new Exception($"{metadataEntry.GetType()} is not a known type for {nameof(MetaDataEditorViewModel)}"); diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs similarity index 81% rename from Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs rename to Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs index 4bd81167b..1e0ee06f3 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntry.cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs @@ -6,15 +6,19 @@ 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 abstract partial class IMetaDataEntry : ObservableObject + // Remove the interface and make the unkownClass a property + + + public abstract partial class IMetaDataEntryViewModel : ObservableObject { public ParsedMetadataAttribute _input; - [ObservableProperty] ObservableCollection _variables = []; + [ObservableProperty] ObservableCollection _variables = []; [ObservableProperty] string _displayName = ""; [ObservableProperty] string _description = ""; @@ -25,7 +29,7 @@ public abstract partial class IMetaDataEntry : ObservableObject public abstract string HasError(); } - public class UnkMetaDataEntry : IMetaDataEntry + public class UnkMetaDataEntry : IMetaDataEntryViewModel { private readonly ParsedUnknownMetadataAttribute _input; @@ -41,12 +45,12 @@ public UnkMetaDataEntry(ParsedUnknownMetadataAttribute unknownMeta) public override string HasError() => ""; } - public class MetaDataEntry : IMetaDataEntry + public class MetaDataEntry : IMetaDataEntryViewModel { private readonly string _originalName; - public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description) + public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, IEventHub eventHub) { _input = typedMetaItem; _originalName = typedMetaItem.Name; @@ -68,19 +72,19 @@ public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description) if (string.IsNullOrWhiteSpace(attributeInfo.Description) == false) itemDiscription = attributeInfo.Description + "\n" + itemDiscription; - MetaDataAttribute editableItem = null; + AttributeViewModel editableItem = null; if (attributeInfo.DisplayOverride == MetaDataTagAttribute.DisplayType.EulerVector || value is Vector3) { if (value is Vector3 vector3) - editableItem = new VectorMetaDataAttribute(parser as Vector3Parser, vector3, typedMetaItem, prop); + editableItem = new VectorAttributeViewModel(parser as Vector3Parser, vector3, typedMetaItem, prop, eventHub); else if (value is Vector4 quaternion) - editableItem = new OrientationMetaDataAttribute(parser as Vector4Parser, quaternion, typedMetaItem, prop); + editableItem = new OrientationAttributeViewModel(parser as Vector4Parser, quaternion, typedMetaItem, prop, eventHub); else throw new Exception("Unknown item"); } else { - editableItem = new MetaDataAttribute(parser, value.ToString(), typedMetaItem, prop); + editableItem = new AttributeViewModel(parser, value.ToString(), typedMetaItem, prop, eventHub); } editableItem.Description = itemDiscription; diff --git a/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs b/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs deleted file mode 100644 index 8652dbb3d..000000000 --- a/Editors/AnimationMeta/MetaEditor/PropertyViewModel.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.ComponentModel; -using System.Reflection; - -namespace Editors.AnimationMeta.Presentation -{ - - public abstract class ViewModelBase : INotifyPropertyChanged - { - public event PropertyChangedEventHandler? PropertyChanged; - protected void OnPropertyChanged(string name) - => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); - } - - public class PropertyViewModel : ViewModelBase - { - private readonly object _target; - private readonly PropertyInfo _property; - - public string Name => _property.Name; - public Type PropertyType => _property.PropertyType; - - public object? Value - { - get => _property.GetValue(_target); - set - { - try - { - if (_property.PropertyType == typeof(Single)) - { - - string val = value as string; - var singleValue = Single.Parse(val); - _property.SetValue(_target, singleValue); - - } - else - { - - _property.SetValue(_target, value); - } - - - - OnPropertyChanged(nameof(Value)); - } - catch { } - } - } - - public PropertyViewModel(object target, PropertyInfo property) - { - _target = target; - _property = property; - } - } -} - diff --git a/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml b/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml index facda6317..6f5d642d7 100644 --- a/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml +++ b/Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml @@ -40,7 +40,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -81,7 +81,7 @@ - + diff --git a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs index 2da1b62fe..b417adb5b 100644 --- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs +++ b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs @@ -20,7 +20,7 @@ public partial class SuperViewViewModel : EditorHostBase private readonly SceneObjectEditor _sceneObjectBuilder; private readonly MetaDataFileParser _metaDataFileParser; - private readonly IMetaDataFactory _metaDataFactory; + private readonly IMetaDataBuilder _metaDataFactory; private readonly IPackFileService _packFileService; private readonly IEventHub _eventHub; private readonly IUiCommandFactory _uiCommandFactory; @@ -39,7 +39,7 @@ public SuperViewViewModel( SceneObjectEditor sceneObjectBuilder, IEditorHostParameters editorHostParameters, MetaDataFileParser metaDataFileParser, - IMetaDataFactory metaDataFactory) + IMetaDataBuilder metaDataFactory) : base(editorHostParameters) { DisplayName = "Super view"; @@ -52,6 +52,12 @@ public SuperViewViewModel( 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) @@ -67,8 +73,8 @@ private void OnFileSaved(ScopedFileSavedEvent evnt) void Initialize() { - PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser); - MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser); + PersistentMetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser, _eventHub); + MetaEditor = new MetaDataEditorViewModel(_uiCommandFactory, _metaDataFileParser, _eventHub); var assetViewModel = _sceneObjectViewModelBuilder.CreateAsset("SuperViewRoot", true, "Root", Color.Black,null); SceneObjects.Add(assetViewModel); @@ -79,17 +85,22 @@ void Initialize() OnSceneObjectUpdated(new SceneObjectUpdateEvent(_asset.Data, false, false, false, true)); } - void RecreateMetaDataInformation(SceneObject model) + void RecreateMetaDataInformation(SceneObject modsel) { - foreach (var item in model.MetaDataItems) - item.CleanUp(); - model.MetaDataItems.Clear(); - model.Player.AnimationRules.Clear(); + 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._metaDataFile; + var meta = MetaEditor._metaDataFile; - var persist = _metaDataFileParser.ParseFile(model.PersistMetaData); - var meta = _metaDataFileParser.ParseFile(model.MetaData); - model.MetaDataItems = _metaDataFactory.Create(persist, meta, model.MainNode, model, model.Player, SceneObjects[0].FragAndSlotSelection.FragmentList.SelectedItem); + _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) diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs b/Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs index 9de9acd13..ee2e23a36 100644 --- a/Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs +++ b/Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs @@ -10,7 +10,7 @@ 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/SuperView/Visualisation/MetaDataFactory.cs b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs similarity index 79% rename from Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs rename to Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs index b6f32927f..e32760477 100644 --- a/Editors/AnimationMeta/SuperView/Visualisation/MetaDataFactory.cs +++ b/Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs @@ -25,21 +25,24 @@ namespace Editors.AnimationMeta.SuperView.Visualisation { - public interface IMetaDataFactory + public interface IMetaDataBuilder { - List Create(ParsedMetadataFile persistent, ParsedMetadataFile metaData, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment); + 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, @@ -52,39 +55,42 @@ public MetaDataFactory(ComplexMeshLoader complexMeshLoader, _animationsContainerComponent = animationsContainerComponent; } - public List Create(ParsedMetadataFile persistent, ParsedMetadataFile 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(ParsedMetadataFile 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); @@ -134,9 +140,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); @@ -156,23 +163,30 @@ 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(); // Add to scene root.AddObject(loadedNode); @@ -180,39 +194,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(); @@ -236,7 +252,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 { @@ -245,7 +261,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); @@ -253,18 +269,18 @@ private IMetaDataInstance CreateSplashAttack(SplashAttack_v10 splashAttack, Scen return new DrawableMetaInstance(splashAttack.StartTime, splashAttack.EndTime, node.Name, node); } - private IMetaDataInstance CreateEffect(IEffectMeta 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); var locatorScale = 0.3f; node.AddItem(LineHelper.AddRgbLocator(effect.Position, locatorScale)); - node.AddItem(new WorldTextRenderItem(_resourceLibrary, effect.VfxName, effect.Position)); + 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.EffectStartTime, effect.EffectEndTime, node.Name, node); diff --git a/GameWorld/View3D/Animation/AnimationSampler.cs b/GameWorld/View3D/Animation/AnimationSampler.cs index 8c0713907..0ab3d24db 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 { 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/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 From 4c59d139cc0b12b0ee74d4e108efea1086ee7e3f Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sun, 1 Mar 2026 07:45:52 +0100 Subject: [PATCH 09/12] Functionally working - code cleanup time --- .../Shared/Editors.Shared.Core/Common/SceneObjectEditor.cs | 4 +--- GameWorld/View3D/Animation/AnimationSampler.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) 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/GameWorld/View3D/Animation/AnimationSampler.cs b/GameWorld/View3D/Animation/AnimationSampler.cs index 0ab3d24db..dbe045ce1 100644 --- a/GameWorld/View3D/Animation/AnimationSampler.cs +++ b/GameWorld/View3D/Animation/AnimationSampler.cs @@ -45,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); From 030e2cc97b09e3b01fb48d3e788318f2b89ed774 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sun, 1 Mar 2026 12:28:27 +0100 Subject: [PATCH 10/12] Code --- .../Editors.AnimationVisualEditors.csproj | 12 ++--- .../Editors.AnimationMeta.csproj | 10 ++-- .../MetaEditor/AttributeViewModel.cs | 10 +--- .../MetaEditor/Commands/CopyPastCommand.cs | 2 +- .../MetaEditor/Commands/NewEntryCommand.cs | 2 +- .../MetaEditor/Commands/SaveCommand.cs | 2 +- .../MetaEditor/MetaDataEditorViewModel.cs | 35 +++++++------ .../MetaEditor/MetaDataEntryViewModel .cs | 49 ++++--------------- .../SuperView/SuperViewViewModel.cs | 12 ++--- .../Editors.Shared.Core.csproj | 12 ++--- 10 files changed, 57 insertions(+), 89 deletions(-) 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/AnimationMeta/Editors.AnimationMeta.csproj b/Editors/AnimationMeta/Editors.AnimationMeta.csproj index b515da389..44e560cad 100644 --- a/Editors/AnimationMeta/Editors.AnimationMeta.csproj +++ b/Editors/AnimationMeta/Editors.AnimationMeta.csproj @@ -1,8 +1,10 @@  - - net10.0-windows - true - + + net10.0-windows + enable + true + enable + diff --git a/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs b/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs index 422241b68..af7cd4e86 100644 --- a/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs +++ b/Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs @@ -1,5 +1,4 @@ -using System; -using System.Reflection; +using System.Reflection; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Xna.Framework; using Serilog; @@ -79,8 +78,6 @@ void Validate() public partial class OrientationAttributeViewModel : AttributeViewModel { - private readonly Vector4Parser _typedParser; - [ObservableProperty] Vector3ViewModel _value = new(0, 0, 0); public OrientationAttributeViewModel(Vector4Parser parser, Vector4 value, object target, PropertyInfo property, IEventHub eventHub) @@ -89,8 +86,6 @@ public OrientationAttributeViewModel(Vector4Parser parser, Vector4 value, object _value = new(0, 0, 0, OnValueChangedCallback); - _typedParser = parser; - var q = new Quaternion(value); var eulerRotation = MathUtil.QuaternionToEulerDegree(q); @@ -112,15 +107,12 @@ private void OnValueChangedCallback(Vector3 vector) public partial class VectorAttributeViewModel : AttributeViewModel { - private readonly Vector3Parser _parser; - [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); - _parser = parser; Value.Set(value); IsValid = true; } diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs index 166eee946..2af1d27d2 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs @@ -56,7 +56,7 @@ public void ExecutePaste(MetaDataEditorViewModel controller) var pastObject = _copyPasteManager.GetPasteObject(); if (pastObject != null) { - controller._metaDataFile.Attributes.AddRange(pastObject.Items); + controller.ParsedFile.Attributes.AddRange(pastObject.Items); } controller.UpdateView(); diff --git a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs index 507a3c7eb..3b8afd655 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs @@ -36,7 +36,7 @@ public void Execute(MetaDataEditorViewModel controller) { var newEntry = _metaDataFileParser.CreateDefault(model.SelectedItem); var desc = _metaDataDatabase.GetDescriptionSafe(newEntry.DisplayName); - var newTagView = new MetaDataEntry(newEntry, desc, _eventHub); + var newTagView = new MetaDataEntry(newEntry, desc, _eventHub, true); controller.Tags.Add(newTagView); } diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs index 58b31858c..1e8f760b7 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs +++ b/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs @@ -44,7 +44,7 @@ public bool Execute(MetaDataEditorViewModel controller) var path = _packFileService.GetFullPath(controller.CurrentFile); _logger.Here().Information("Creating metadata file. TagCount=" + controller.Tags.Count + " " + path); - var bytes = _metaDataFileParser.GenerateBytes(controller.MetaDataFileVersion, controller._metaDataFile); + var bytes = _metaDataFileParser.GenerateBytes(controller.MetaDataFileVersion, controller.ParsedFile); _logger.Here().Information("Saving"); var res = _packFileSaveService.Save(path, bytes, false); if (res != null) diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs index d4219d27d..6a6a0be90 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs +++ b/Editors/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; @@ -15,12 +14,12 @@ public partial class MetaDataEditorViewModel : ObservableObject, IEditorInterfac private readonly IUiCommandFactory _uiCommandFactory; private readonly MetaDataFileParser _metaDataFileParser; private readonly IEventHub _eventHub; - public ParsedMetadataFile _metaDataFile; - public ParsedMetadataAttribute _selectedAttribute; + public ParsedMetadataFile? ParsedFile { get; private set; } + public ParsedMetadataAttribute? SelectedAttribute { get; private set; } [ObservableProperty] string _displayName = "Metadata Editor"; - [ObservableProperty] IMetaDataEntryViewModel _selectedTag; - [ObservableProperty] ObservableCollection _tags = []; + [ObservableProperty] MetaDataEntry _selectedTag; + [ObservableProperty] ObservableCollection _tags = []; [ObservableProperty] int _metaDataFileVersion; public bool HasUnsavedChanges { get; set; } = false; @@ -33,13 +32,13 @@ public MetaDataEditorViewModel(IUiCommandFactory uiCommandFactory, MetaDataFileP _eventHub = eventHub; } - partial void OnSelectedTagChanged(IMetaDataEntryViewModel value) + partial void OnSelectedTagChanged(MetaDataEntry value) { if(value == null) - _selectedAttribute = null; + SelectedAttribute = null; else - _selectedAttribute = value._input; + SelectedAttribute = value._input; _eventHub.Publish(new MetaDataAttributeChangedEvent()); } @@ -61,10 +60,8 @@ public void LoadFile(PackFile file) var fileContent = CurrentFile.DataSource.ReadData(); - var loadedMetadataFile = _metaDataFileParser.ParseFile(fileContent); - MetaDataFileVersion = loadedMetadataFile.Version; - - _metaDataFile = loadedMetadataFile; + ParsedFile = _metaDataFileParser.ParseFile(fileContent); + MetaDataFileVersion = ParsedFile.Version; UpdateView(); } @@ -72,14 +69,20 @@ public void LoadFile(PackFile file) public void UpdateView() { Tags.Clear(); - foreach (var metadataEntry in _metaDataFile.Attributes) + if (ParsedFile == null) + return; + + foreach (var metadataEntry in ParsedFile.Attributes) { if (metadataEntry is ParsedUnknownMetadataAttribute uknMeta) - Tags.Add(new UnkMetaDataEntry(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 )); + Tags.Add(new MetaDataEntry(parsedKnownAttribute, desc, _eventHub, true)); } else throw new Exception($"{metadataEntry.GetType()} is not a known type for {nameof(MetaDataEditorViewModel)}"); diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs b/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs index 1e0ee06f3..5e5fdb6d8 100644 --- a/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs +++ b/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.ObjectModel; -using System.Linq; +using System.Collections.ObjectModel; using System.Reflection; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Xna.Framework; @@ -11,52 +9,27 @@ namespace Editors.AnimationMeta.Presentation { - // Remove the interface and make the unkownClass a property - - - public abstract partial class IMetaDataEntryViewModel : ObservableObject + public partial class MetaDataEntry : ObservableObject { public ParsedMetadataAttribute _input; - [ObservableProperty] ObservableCollection _variables = []; - + [ObservableProperty] ObservableCollection _variables = []; [ObservableProperty] string _displayName = ""; [ObservableProperty] string _description = ""; [ObservableProperty] bool _isDecodedCorrectly = false; [ObservableProperty] int _version; [ObservableProperty] bool _isSelected; - public abstract string HasError(); - } - - public class UnkMetaDataEntry : IMetaDataEntryViewModel - { - private readonly ParsedUnknownMetadataAttribute _input; - - public UnkMetaDataEntry(ParsedUnknownMetadataAttribute unknownMeta) - { - _input = unknownMeta; - - IsDecodedCorrectly = false; - DisplayName = unknownMeta.DisplayName; - Version = unknownMeta.Version; - } - - public override string HasError() => ""; - } - - public class MetaDataEntry : IMetaDataEntryViewModel - { - private readonly string _originalName; - - - public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, IEventHub eventHub) + public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, IEventHub eventHub, bool decodedCorrectly) { _input = typedMetaItem; - _originalName = typedMetaItem.Name; DisplayName = typedMetaItem.DisplayName; Description = description; Version = typedMetaItem.Version; + IsDecodedCorrectly = decodedCorrectly; + + if(IsDecodedCorrectly == false) + return; var orderedPropertiesList = typedMetaItem.GetType().GetProperties() .Where(x => x.CanWrite) @@ -72,7 +45,7 @@ public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, if (string.IsNullOrWhiteSpace(attributeInfo.Description) == false) itemDiscription = attributeInfo.Description + "\n" + itemDiscription; - AttributeViewModel editableItem = null; + AttributeViewModel? editableItem = null; if (attributeInfo.DisplayOverride == MetaDataTagAttribute.DisplayType.EulerVector || value is Vector3) { if (value is Vector3 vector3) @@ -93,13 +66,11 @@ public MetaDataEntry(ParsedMetadataAttribute typedMetaItem, string description, Variables.Add(editableItem); } - IsDecodedCorrectly = true; - if (Variables.Count != 0) Variables.First().IsReadOnly = true; } - public override string HasError() + public string? HasError() { foreach (var variable in Variables) { diff --git a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs index b417adb5b..a904aa0b3 100644 --- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs +++ b/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs @@ -50,7 +50,7 @@ public SuperViewViewModel( _metaDataFileParser = metaDataFileParser; _metaDataFactory = metaDataFactory; Initialize(); - eventHub.Register(this, OnFileSaved); + //eventHub.Register(this, OnFileSaved); eventHub.Register(this, OnSceneObjectUpdated); eventHub.Register(this, OnMetaDataAttributeChanged); } @@ -59,7 +59,7 @@ private void OnMetaDataAttributeChanged(MetaDataAttributeChangedEvent @event) { RecreateMetaDataInformation(null); } - + /* private void OnFileSaved(ScopedFileSavedEvent evnt) { var newFile = _packFileService.FindFile(evnt.NewPath); @@ -69,7 +69,7 @@ private void OnFileSaved(ScopedFileSavedEvent evnt) _sceneObjectBuilder.SetMetaFile(_asset.Data, newFile, _asset.Data.PersistMetaData); else throw new Exception($"Unable to determine file owner when reciving a file save event in SuperView. Owner:{evnt.FileOwner}, File:{evnt.NewPath}"); - } + }*/ void Initialize() { @@ -96,10 +96,10 @@ void RecreateMetaDataInformation(SceneObject modsel) item.Data.Player.AnimationRules.Clear(); } - var persist = PersistentMetaEditor._metaDataFile; - var meta = MetaEditor._metaDataFile; + 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.MetaDataItems = _metaDataFactory.Create(persist, meta, MetaEditor.SelectedAttribute, _asset.Data.MainNode, _asset.Data, _asset.Data.Player, _asset.FragAndSlotSelection.FragmentList.SelectedItem); _asset.Data.Player.Refresh(); } 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 + From 5b20cd1726c072a1fa35c8e0e1ab8660bdd739ba Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sun, 1 Mar 2026 12:42:52 +0100 Subject: [PATCH 11/12] Moving stuff around --- AssetEditor.sln | 24 ++++++++++++----- AssetEditor/AssetEditor.csproj | 2 +- .../Editors.AnimationMeta.csproj | 14 ---------- .../Test.AnimationMeta.csproj | 27 +++++++++++++++++++ .../Test.AnimationMeta/UnitTest1.cs | 16 +++++++++++ .../DependencyInjectionContainer.cs | 0 .../AnimationMeta/DevConfig/AnimMetaTool.cs | 4 +-- .../AnimationMeta/DevConfig/SuperView_Rat.cs | 6 ++--- .../Editors.AnimationMeta.csproj | 15 +++++++++++ .../MetaEditor/AttributeViewModel.cs | 0 .../MetaEditor/Commands/CopyPastCommand.cs | 4 +-- .../MetaEditor/Commands/DeleteEntryCommand.cs | 3 +-- .../MetaEditor/Commands/MoveEntryCommand.cs | 2 -- .../MetaEditor/Commands/NewEntryCommand.cs | 0 .../MetaEditor/Commands/SaveCommand.cs | 0 .../MetaEditor/MetaDataEditorViewModel.cs | 0 .../MetaEditor/MetaDataEntryViewModel .cs | 0 .../MetaEditor/View/MainEditorView.xaml | 0 .../MetaEditor/View/MainEditorView.xaml.cs | 0 .../View/MetaDataAttributeView.xaml | 0 .../View/MetaDataAttributeView.xaml.cs | 0 .../MetaEditor/View/MetaDataEntryView.xaml | 0 .../MetaEditor/View/MetaDataEntryView.xaml.cs | 0 .../View/NewMetaDataEntryWindow.xaml | 0 .../View/NewMetaDataEntryWindow.xaml.cs | 0 .../AnimationMeta/SuperView/EditorView.xaml | 0 .../SuperView/EditorView.xaml.cs | 0 .../SuperView/SuperViewViewModel.cs | 10 +++---- .../Instances/AnimatedPropInstance.cs | 0 .../Instances/DrawableMetaInstance.cs | 0 .../Visualisation/MetaDataBuilder.cs | 7 ++--- .../Visualisation/Rules/CopyRootTransform.cs | 0 .../Visualisation/Rules/DockEquipmentRule.cs | 0 .../Visualisation/Rules/TransformBoneRule.cs | 0 34 files changed, 89 insertions(+), 45 deletions(-) delete mode 100644 Editors/AnimationMeta/Editors.AnimationMeta.csproj create mode 100644 Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj create mode 100644 Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs rename Editors/{ => MetaDataEditor}/AnimationMeta/DependencyInjectionContainer.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/DevConfig/AnimMetaTool.cs (93%) rename Editors/{ => MetaDataEditor}/AnimationMeta/DevConfig/SuperView_Rat.cs (97%) create mode 100644 Editors/MetaDataEditor/AnimationMeta/Editors.AnimationMeta.csproj rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/AttributeViewModel.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs (96%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/Commands/DeleteEntryCommand.cs (87%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/Commands/MoveEntryCommand.cs (99%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/Commands/SaveCommand.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MainEditorView.xaml (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MainEditorView.xaml.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/MetaDataEntryView.xaml.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/MetaEditor/View/NewMetaDataEntryWindow.xaml.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/EditorView.xaml (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/EditorView.xaml.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/SuperViewViewModel.cs (96%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs (99%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs (100%) rename Editors/{ => MetaDataEditor}/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs (100%) 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..cd1946483 100644 --- a/AssetEditor/AssetEditor.csproj +++ b/AssetEditor/AssetEditor.csproj @@ -15,11 +15,11 @@ - + diff --git a/Editors/AnimationMeta/Editors.AnimationMeta.csproj b/Editors/AnimationMeta/Editors.AnimationMeta.csproj deleted file mode 100644 index 44e560cad..000000000 --- a/Editors/AnimationMeta/Editors.AnimationMeta.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - net10.0-windows - enable - true - enable - - - - - - - - diff --git a/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj new file mode 100644 index 000000000..b54e0a997 --- /dev/null +++ b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj @@ -0,0 +1,27 @@ + + + + net10.0-windows + latest + enable + enable + false + + + + + + + + + + + + + + + + + + + diff --git a/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs new file mode 100644 index 000000000..9a6c5fb8c --- /dev/null +++ b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs @@ -0,0 +1,16 @@ +namespace Test.AnimationMeta +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} diff --git a/Editors/AnimationMeta/DependencyInjectionContainer.cs b/Editors/MetaDataEditor/AnimationMeta/DependencyInjectionContainer.cs similarity index 100% rename from Editors/AnimationMeta/DependencyInjectionContainer.cs rename to Editors/MetaDataEditor/AnimationMeta/DependencyInjectionContainer.cs 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/AnimationMeta/MetaEditor/AttributeViewModel.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/AttributeViewModel.cs similarity index 100% rename from Editors/AnimationMeta/MetaEditor/AttributeViewModel.cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/AttributeViewModel.cs diff --git a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs similarity index 96% rename from Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs index 2af1d27d2..1637d411c 100644 --- a/Editors/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs +++ b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/CopyPastCommand.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Windows; +using System.Windows; using Editors.AnimationMeta.Presentation; using Shared.Core.Events; using Shared.Core.Misc; 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 100% rename from Editors/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/NewEntryCommand.cs diff --git a/Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/SaveCommand.cs similarity index 100% rename from Editors/AnimationMeta/MetaEditor/Commands/SaveCommand.cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/Commands/SaveCommand.cs diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs similarity index 100% rename from Editors/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEditorViewModel.cs diff --git a/Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs b/Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs similarity index 100% rename from Editors/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/MetaDataEntryViewModel .cs 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 100% rename from Editors/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml rename to Editors/MetaDataEditor/AnimationMeta/MetaEditor/View/MetaDataAttributeView.xaml 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 96% rename from Editors/AnimationMeta/SuperView/SuperViewViewModel.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/SuperViewViewModel.cs index a904aa0b3..ff3d187ec 100644 --- a/Editors/AnimationMeta/SuperView/SuperViewViewModel.cs +++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/SuperViewViewModel.cs @@ -1,6 +1,4 @@ -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; @@ -50,7 +48,7 @@ public SuperViewViewModel( _metaDataFileParser = metaDataFileParser; _metaDataFactory = metaDataFactory; Initialize(); - //eventHub.Register(this, OnFileSaved); + eventHub.Register(this, OnFileSaved); eventHub.Register(this, OnSceneObjectUpdated); eventHub.Register(this, OnMetaDataAttributeChanged); } @@ -59,7 +57,7 @@ private void OnMetaDataAttributeChanged(MetaDataAttributeChangedEvent @event) { RecreateMetaDataInformation(null); } - /* + private void OnFileSaved(ScopedFileSavedEvent evnt) { var newFile = _packFileService.FindFile(evnt.NewPath); @@ -69,7 +67,7 @@ private void OnFileSaved(ScopedFileSavedEvent evnt) _sceneObjectBuilder.SetMetaFile(_asset.Data, newFile, _asset.Data.PersistMetaData); else throw new Exception($"Unable to determine file owner when reciving a file save event in SuperView. Owner:{evnt.FileOwner}, File:{evnt.NewPath}"); - }*/ + } void Initialize() { diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs similarity index 100% rename from Editors/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/AnimatedPropInstance.cs diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs similarity index 100% rename from Editors/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Instances/DrawableMetaInstance.cs diff --git a/Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs similarity index 99% rename from Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs index e32760477..f82321c62 100644 --- a/Editors/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs +++ b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/MetaDataBuilder.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; +using System.Data; using Editors.AnimationMeta.SuperView.Visualisation.Instances; using Editors.AnimationMeta.SuperView.Visualisation.Rules; using Editors.Shared.Core.Common; @@ -24,7 +21,6 @@ namespace Editors.AnimationMeta.SuperView.Visualisation { - public interface IMetaDataBuilder { List Create(ParsedMetadataFile persistent, ParsedMetadataFile metaData, ParsedMetadataAttribute selectedMetaDataAttribute, SceneNode root, ISkeletonProvider skeleton, AnimationPlayer rootPlayer, IAnimationBinGenericFormat fragment); @@ -187,6 +183,7 @@ private IMetaDataInstance CreateAnimatedProp(IAnimatedPropMeta animatedPropMeta, propPlayer.AnimationRules.Add(animationRule); if(rootPlayer.IsPlaying) propPlayer.Play(); + propPlayer.Refresh(); // Add to scene root.AddObject(loadedNode); diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs similarity index 100% rename from Editors/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/CopyRootTransform.cs diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs similarity index 100% rename from Editors/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/DockEquipmentRule.cs diff --git a/Editors/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs b/Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs similarity index 100% rename from Editors/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs rename to Editors/MetaDataEditor/AnimationMeta/SuperView/Visualisation/Rules/TransformBoneRule.cs From 69d0a46dd3bf38df97dde46e57f9ce152ac5ec42 Mon Sep 17 00:00:00 2001 From: ole kristian homelien Date: Sun, 1 Mar 2026 20:30:13 +0100 Subject: [PATCH 12/12] Name space and test --- AssetEditor/AssetEditor.csproj | 1 + AssetEditor/DependencyInjectionContainer.cs | 2 +- .../ViewModels/EditorShortcutViewModel.cs | 2 +- AssetEditor/ViewModels/MainViewModel.cs | 1 - .../MountAnimationCreatorViewModel.cs | 2 +- .../DevConfig/AnimPack_WH3.cs | 2 +- .../Test.AnimationMeta.csproj | 57 +++++++++++-------- .../Test.AnimationMeta/UnitTest1.cs | 38 ++++++++++--- .../AnimationRetargeTool_ComplexUseCase.cs | 2 +- Editors/Audio/DevConfig/AudioEditor_Wh3.cs | 2 +- .../Audio/DevConfig/AudioExplorer_Attila.cs | 2 +- Editors/Audio/DevConfig/AudioExplorer_Wh3.cs | 2 +- .../KitbasherEditor/DevConfig/Kitbash_Karl.cs | 2 +- .../DevConfig/Kitbash_Karl_WH2.cs | 2 +- .../KitbasherEditor/DevConfig/Kitbash_Ox.cs | 2 +- .../KitbasherEditor/DevConfig/Kitbash_Rat.cs | 2 +- .../DevConfig/Kitbash_RomeShield.cs | 2 +- .../LoadAndSave/KitbashEditor_SaveTests.cs | 12 +--- .../LoadAndSave/LoadAndSaveBase.cs | 2 +- .../LoadAndSave/LoadAndSave_Geometry.cs | 2 +- .../LoadAndSave/LoadAndSave_WsModel.cs | 2 +- .../ReferenceModel/BinAnimationViewModel.cs | 2 +- .../SkeletonTool_ComplexUsecase.cs | 2 +- .../TextureEditor/DevConfig/Texture_Karl.cs | 2 +- .../UserInterface/ShaderTextureViewModel.cs | 2 +- .../Events/Global/OpenEditorCommand.cs | 13 ++++- 26 files changed, 98 insertions(+), 64 deletions(-) diff --git a/AssetEditor/AssetEditor.csproj b/AssetEditor/AssetEditor.csproj index cd1946483..85fa332b6 100644 --- a/AssetEditor/AssetEditor.csproj +++ b/AssetEditor/AssetEditor.csproj @@ -7,6 +7,7 @@ AssetEditorIcon.ico true true + enable 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/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/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/Test.AnimationMeta/Test.AnimationMeta.csproj b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj index b54e0a997..28d5004aa 100644 --- a/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj +++ b/Editors/AnimationMeta/Test.AnimationMeta/Test.AnimationMeta.csproj @@ -1,27 +1,38 @@  + + + net10.0-windows + true + enable + enable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + - - net10.0-windows - latest - enable - enable - false - - - - - - - - - - - - - - - - - + + + diff --git a/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs index 9a6c5fb8c..fd2d32cb4 100644 --- a/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs +++ b/Editors/AnimationMeta/Test.AnimationMeta/UnitTest1.cs @@ -1,16 +1,40 @@ -namespace Test.AnimationMeta +using Editors.AnimationMeta.Presentation; +using Shared.Core.Events.Global; +using Test.TestingUtility.Shared; +using Test.TestingUtility.TestUtility; + +namespace Test.AnimationMeta { public class Tests { - [SetUp] - public void Setup() - { - } [Test] - public void Test1() + public void MetaDataEditor_OpenAndVerify() { - Assert.Pass(); + 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/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/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/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/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);