From 2df4aeb207772e1579457732739f5fbbc880be38 Mon Sep 17 00:00:00 2001 From: friflo Date: Thu, 13 Feb 2025 13:05:16 +0100 Subject: [PATCH] Test_StructuralChange_OldBehavior --- src/ECS/Archetype/EntityStore.cs | 2 +- .../Arch/Test_StructuralChangeException.cs | 14 +++ .../Arch/Test_StructuralChange_OldBehavior.cs | 116 ++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/Tests/ECS/Arch/Test_StructuralChange_OldBehavior.cs diff --git a/src/ECS/Archetype/EntityStore.cs b/src/ECS/Archetype/EntityStore.cs index c9eeb989..6c1a32fc 100644 --- a/src/ECS/Archetype/EntityStore.cs +++ b/src/ECS/Archetype/EntityStore.cs @@ -201,7 +201,7 @@ All methods calling MoveEntityTo() have a runtime exception upfront before calli } */ internal static StructuralChangeException StructuralChangeWithinQueryLoop() { - return new StructuralChangeException("within a query loop"); + return new StructuralChangeException("within query loop. See: https://friflo.gitbook.io/friflo.engine.ecs/documentation/query#structuralchangeexception"); } /* diff --git a/src/Tests/ECS/Arch/Test_StructuralChangeException.cs b/src/Tests/ECS/Arch/Test_StructuralChangeException.cs index c6eae2cd..f941ae69 100644 --- a/src/Tests/ECS/Arch/Test_StructuralChangeException.cs +++ b/src/Tests/ECS/Arch/Test_StructuralChangeException.cs @@ -11,6 +11,20 @@ namespace Tests.ECS.Arch { public static class Test_StructuralChangeException { + [Test] + public static void Test_StructuralChangeException_Message() + { + var store = new EntityStore(); + store.CreateEntity(); + foreach (var entity in store.Entities) + { + var e = Assert.Throws(() => { + entity.AddTag(); + }); + Assert.AreEqual("within query loop. See: https://friflo.gitbook.io/friflo.engine.ecs/documentation/query#structuralchangeexception", e!.Message); + } + } + [Test] public static void Test_StructuralChangeException_Entities() { diff --git a/src/Tests/ECS/Arch/Test_StructuralChange_OldBehavior.cs b/src/Tests/ECS/Arch/Test_StructuralChange_OldBehavior.cs new file mode 100644 index 00000000..aa448326 --- /dev/null +++ b/src/Tests/ECS/Arch/Test_StructuralChange_OldBehavior.cs @@ -0,0 +1,116 @@ +using Friflo.Engine.ECS; +using Friflo.Engine.ECS.Serialize; +using NUnit.Framework; + + +// ReSharper disable ConditionalTernaryEqualBranch +// ReSharper disable CompareOfFloatsByEqualityOperator +// ReSharper disable StringLiteralTypo +// ReSharper disable InconsistentNaming +namespace Tests.ECS.Arch { + +public static class Test_StructuralChange_OldBehavior +{ + [Test] + public static void Test_StructuralChange_OldBehavior_no_throw() + { + var store = new EntityStore(); + store.CreateEntity(new MyComponent1(), new MyComponent2(), new MyComponent3(), new MyComponent4(), new MyComponent4()); + { + var query = store.Query(); + query.ThrowOnStructuralChange = false; + foreach (var entity in query.Entities) + { + TestNoExceptions(store, entity); + } + } { + var query = store.Query(); + query.ThrowOnStructuralChange = false; + query.ForEachEntity((ref MyComponent1 _, Entity entity) => + { + TestNoExceptions(store, entity); + }); + }{ + var query = store.Query(); + query.ThrowOnStructuralChange = false; + query.ForEachEntity((ref MyComponent1 _, ref MyComponent2 _, Entity entity) => + { + TestNoExceptions(store, entity); + }); + }{ + var query = store.Query(); + query.ThrowOnStructuralChange = false; + query.ForEachEntity((ref MyComponent1 _, ref MyComponent2 _, ref MyComponent3 _, Entity entity) => + { + TestNoExceptions(store, entity); + }); + }{ + var query = store.Query(); + query.ThrowOnStructuralChange = false; + query.ForEachEntity((ref MyComponent1 _, ref MyComponent2 _, ref MyComponent3 _, ref MyComponent4 _, Entity entity) => + { + TestNoExceptions(store, entity); + }); + }{ + var query = store.Query(); + query.ThrowOnStructuralChange = false; + query.ForEachEntity((ref MyComponent1 _, ref MyComponent2 _, ref MyComponent3 _, ref MyComponent4 _, ref MyComponent5 _, Entity entity) => + { + TestNoExceptions(store, entity); + }); + } + } + + private static void TestNoExceptions(EntityStore store, Entity entity) + { + entity.AddTag(); + entity.RemoveTag(); + + entity.AddComponent(); + entity.RemoveComponent(); + + var buffer = store.GetCommandBuffer(); + buffer.Playback(); + + var entityBatch = new EntityBatch(); + entityBatch.ApplyTo(entity); + + TestMultiAddRemoveNoExceptions(entity); + + var converter = EntityConverter.Default; + var dataEntity = new DataEntity { pid = 1 }; + converter.DataEntityToEntity(dataEntity, store, out _); + } + + + private static void TestMultiAddRemoveNoExceptions(Entity entity) + { + // --- add multiple components + entity.Add(new Position()); + entity.Add(new Position(), new Scale3()); + entity.Add(new Position(), new Scale3(), new Rotation()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2(), new MyComponent3()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2(), new MyComponent3(), new MyComponent4()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2(), new MyComponent3(), new MyComponent4(), new MyComponent5()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2(), new MyComponent3(), new MyComponent4(), new MyComponent5(), new MyComponent6()); + entity.Add(new Position(), new Scale3(), new Rotation(), new MyComponent1(), new MyComponent2(), new MyComponent3(), new MyComponent4(), new MyComponent5(), new MyComponent6(), new MyComponent7()); + + // --- remove multiple components + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + entity.Remove(); + } + +} + +} +