diff --git a/src/Artemis.Core.Tests/DataModels/DataModelPathTests.cs b/src/Artemis.Core.Tests/DataModels/DataModelPathTests.cs
index 44c7eb910..6eb3e1709 100644
--- a/src/Artemis.Core.Tests/DataModels/DataModelPathTests.cs
+++ b/src/Artemis.Core.Tests/DataModels/DataModelPathTests.cs
@@ -340,7 +340,7 @@ public class DataModelPathTests : IDisposable
}
[Fact]
- public void RemovingTheDynamicChild_LeavesThePathValid()
+ public void RemovingTheDynamicChild_MakesThePathInvalid()
{
DataModel.AddDynamicChild("Extra", 5);
using DataModelPath path = new(DataModel, "Extra");
@@ -349,25 +349,34 @@ public class DataModelPathTests : IDisposable
DataModel.RemoveDynamicChildByKey("Extra");
- // Pinned as-is: the segment only invalidates the path when the value of the removed child is the data model the
- // segment looks in, rather than when the child it points to is removed. So the path stays valid and reads the
- // default value instead of becoming invalid.
- path.IsValid.ShouldBeTrue();
- path.GetValue().ShouldBe(0);
- invalidated.ShouldBe(0);
+ path.IsValid.ShouldBeFalse();
+ path.GetValue().ShouldBeNull();
+ invalidated.ShouldBe(1);
}
[Fact]
- public void RemovingADynamicDataModel_LeavesThePathThroughItValid()
+ public void RemovingTheDynamicChild_AndAddingItAgain_MakesThePathValidAgain()
+ {
+ DataModel.AddDynamicChild("Extra", 5);
+ using DataModelPath path = new(DataModel, "Extra");
+ DataModel.RemoveDynamicChildByKey("Extra");
+
+ DataModel.AddDynamicChild("Extra", 6);
+
+ path.IsValid.ShouldBeTrue();
+ path.GetValue().ShouldBe(6);
+ }
+
+ [Fact]
+ public void RemovingADynamicDataModel_MakesThePathThroughItInvalid()
{
DataModel.AddDynamicChild("Extra", new TestChildDataModel {Integer = 4}, "Extra data");
using DataModelPath path = new(DataModel, "Extra.Integer");
DataModel.RemoveDynamicChildByKey("Extra");
- // Pinned as-is, see RemovingTheDynamicChild_LeavesThePathValid
- path.IsValid.ShouldBeTrue();
- path.GetValue().ShouldBe(0);
+ path.IsValid.ShouldBeFalse();
+ path.GetValue().ShouldBeNull();
}
[Fact]
@@ -450,20 +459,17 @@ public class DataModelPathTests : IDisposable
}
[Fact]
- public void NewPath_DoesNotFollowTheStoreUntilItIsSaved()
+ public void NewPath_FollowsTheStoreWithoutBeingSaved()
{
using DataModelPath path = new(DataModel, "Integer");
- // Pinned as-is: the constructors call Save before the path is set up, while it is still invalid, so nothing is
- // saved and the entity has no data model ID. The path only reacts to its data model leaving and returning to the
- // store once Save is called. Looks like Save should be called after Initialize.
- path.Entity.DataModelId.ShouldBeNull();
- path.Entity.Path.ShouldBe("");
+ path.Entity.DataModelId.ShouldBe(_module.Id);
+ path.Entity.Path.ShouldBe("Integer");
RemoveFromStore();
- path.IsValid.ShouldBeTrue();
- path.Target.ShouldBeSameAs(DataModel);
+ path.IsValid.ShouldBeFalse();
+ path.Target.ShouldBeNull();
}
[Fact]
@@ -540,7 +546,7 @@ public class DataModelPathTests : IDisposable
}
[Fact]
- public void InvalidPath_CannotFallBackToATypeOutsideTheCoreLibraries()
+ public void InvalidPath_FallsBackToATypeOutsideTheCoreLibraries()
{
using DataModelPath valid = new(DataModel, "Enum");
valid.Save();
@@ -548,9 +554,15 @@ public class DataModelPathTests : IDisposable
using DataModelPath path = new(new DataModelPathEntity {Path = "Enum", DataModelId = "Missing-12345678", Type = valid.Entity.Type});
- // Pinned as-is: the type is saved by its full name without the assembly, which Type.GetType can only find in
- // Artemis.Core and the .NET libraries, so types from plugins (and SkiaSharp, like SKColor) can't be found again.
- path.GetPropertyType().ShouldBeNull();
+ path.GetPropertyType().ShouldBe(typeof(TestEnum));
+ }
+
+ [Fact]
+ public void InvalidPath_FallsBackToASkiaSharpType()
+ {
+ using DataModelPath path = new(new DataModelPathEntity {Path = "Color", DataModelId = "Missing-12345678", Type = typeof(SKColor).FullName});
+
+ path.GetPropertyType().ShouldBe(typeof(SKColor));
}
[Fact]
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
index 62ebd93bb..9039e6792 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs
@@ -29,8 +29,8 @@ public class DataModelPath : IStorageModel, IDisposable, IPluginFeatureDependent
_segments = [];
- Save();
Initialize();
+ Save();
SubscribeToDataModelStore();
}
@@ -47,8 +47,8 @@ public class DataModelPath : IStorageModel, IDisposable, IPluginFeatureDependent
_segments = [];
- Save();
Initialize();
+ Save();
SubscribeToDataModelStore();
}
@@ -67,8 +67,8 @@ public class DataModelPath : IStorageModel, IDisposable, IPluginFeatureDependent
_segments = [];
- Save();
Initialize();
+ Save();
SubscribeToDataModelStore();
}
@@ -165,11 +165,20 @@ public class DataModelPath : IStorageModel, IDisposable, IPluginFeatureDependent
// Fall back to stored type
if (!string.IsNullOrWhiteSpace(Entity.Type))
- return Type.GetType(Entity.Type);
+ return FindType(Entity.Type);
return null;
}
+ private static Type? FindType(string fullName)
+ {
+ // The type is stored without its assembly, Type.GetType only finds it in Artemis.Core and the .NET libraries. Types
+ // of plugins and other libraries (like SKColor) are found by looking through the loaded assemblies
+ return Type.GetType(fullName) ?? AppDomain.CurrentDomain.GetAssemblies()
+ .Select(assembly => assembly.GetType(fullName))
+ .FirstOrDefault(type => type != null);
+ }
+
///
/// Gets the property description of the property this path points to
///
diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
index f1c71bd34..c1db971bc 100644
--- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
+++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs
@@ -286,8 +286,16 @@ public class DataModelPathSegment : IDisposable
private void DynamicChildOnDynamicChildRemoved(object? sender, DynamicDataModelChildEventArgs e)
{
- if (e.DynamicChild.BaseValue == _dynamicDataModel)
+ // Like when a child is added, initialize the path again so it no longer points to the removed child
+ if (e.Key == Identifier)
+ {
DataModelPath.Invalidate();
+ DataModelPath.Initialize();
+ }
+ else if (e.DynamicChild.BaseValue == _dynamicDataModel)
+ {
+ DataModelPath.Invalidate();
+ }
}
///