diff --git a/src/ECS/Archetype/Archetype.cs b/src/ECS/Archetype/Archetype.cs index 612493e2..543eb1e9 100644 --- a/src/ECS/Archetype/Archetype.cs +++ b/src/ECS/Archetype/Archetype.cs @@ -308,12 +308,12 @@ internal static void MoveLastComponentsTo(Archetype arch, int newIndex, bool upd } /// Must be used only on case all are - internal static void CopyComponents(Archetype arch, CopyContext context) + internal static void CloneComponents(Archetype arch, CopyContext context) { var sourceIndex = context.source.compIndex; var targetIndex = context.target.compIndex; foreach (var sourceHeap in arch.structHeaps) { - sourceHeap.CopyComponent(sourceIndex, targetIndex, context); + sourceHeap.CloneComponent(sourceIndex, targetIndex, context); } } diff --git a/src/ECS/Archetype/StructHeap.cs b/src/ECS/Archetype/StructHeap.cs index c48bc680..ac32db36 100644 --- a/src/ECS/Archetype/StructHeap.cs +++ b/src/ECS/Archetype/StructHeap.cs @@ -36,7 +36,7 @@ internal abstract class StructHeap : IComponentStash internal abstract void ResizeComponents (int capacity, int count); internal abstract void MoveComponent (int from, int to); internal abstract void CopyComponentTo (int sourcePos, StructHeap target, int targetPos); - internal abstract void CopyComponent (int sourcePos, int targetPos, in CopyContext context); + internal abstract void CloneComponent (int sourcePos, int targetPos, in CopyContext context); internal abstract void SetComponentDefault (int compIndex); internal abstract void SetComponentsDefault (int compIndexStart, int count); internal abstract object GetComponentDebug (int compIndex); diff --git a/src/ECS/Archetype/StructHeap.generic.cs b/src/ECS/Archetype/StructHeap.generic.cs index f2badfa9..33c8c4fc 100644 --- a/src/ECS/Archetype/StructHeap.generic.cs +++ b/src/ECS/Archetype/StructHeap.generic.cs @@ -78,14 +78,21 @@ internal override void CopyComponentTo(int sourcePos, StructHeap target, int tar /// 's.
/// If not serialization must be used. /// - internal override void CopyComponent(int sourcePos, int targetPos, in CopyContext context) + internal override void CloneComponent(int sourcePos, int targetPos, in CopyContext context) { var copyValue = CopyValueUtils.CopyValue; + ref var source = ref components[sourcePos]; + ref var target = ref components[targetPos]; if (copyValue == null) { - components[targetPos] = components[sourcePos]; + target = source; + } else { + copyValue(source, ref target, context); + } + if (!StructInfo.HasIndex) { return; } - copyValue(components[sourcePos], ref components[targetPos], context); + var targetEntity = context.target; + StoreIndex.AddIndex(targetEntity.store, targetEntity.Id, source); } internal override void SetComponentDefault (int compIndex) { diff --git a/src/ECS/Entity/Store/Entities.cs b/src/ECS/Entity/Store/Entities.cs index eebe6b6a..b187b0d9 100644 --- a/src/ECS/Entity/Store/Entities.cs +++ b/src/ECS/Entity/Store/Entities.cs @@ -92,13 +92,12 @@ public Entity CloneEntity(Entity entity) var clone = new Entity(this, id, revision); // var isBlittable = IsBlittable(entity); - - // todo optimize - serialize / deserialize only non blittable components and scripts // if (true) { + var scriptTypeByType = Static.EntitySchema.ScriptTypeByType; // CopyComponents() must be used only in case all component types are blittable var context = new CopyContext(entity, clone); - Archetype.CopyComponents(archetype, context); + Archetype.CloneComponents(archetype, context); if (clone.HasComponent()) { clone.GetComponent() = default; // clear child ids. See child entities note in remarks. } @@ -109,7 +108,8 @@ public Entity CloneEntity(Entity entity) scriptClone.entity = clone; extension.AddScript(clone, scriptClone, scriptType); } - /* } else { + /* keep old implementation using JSON serialization for reference + } else { // --- serialize entity var converter = EntityConverter.Default; converter.EntityToDataEntity(entity, dataBuffer, false); diff --git a/src/Tests/ECS/Entity/Test_Entity.cs b/src/Tests/ECS/Entity/Test_Entity.cs index 8a933bbb..0808d4fd 100644 --- a/src/Tests/ECS/Entity/Test_Entity.cs +++ b/src/Tests/ECS/Entity/Test_Entity.cs @@ -4,6 +4,7 @@ using System.Linq; using Friflo.Engine.ECS; using NUnit.Framework; +using Tests.ECS.Index; using Tests.Utils; using static NUnit.Framework.Assert; @@ -204,7 +205,7 @@ public static void Assert_TryGetEntityById() } [Test] - public static void Test_EntityStore_CloneEntity() + public static void Test_EntityStore_CloneEntity_1() { var store = new EntityStore(PidType.RandomPids); var entity = store.CreateEntity(); @@ -237,7 +238,7 @@ public static void Test_EntityStore_CloneEntity() } [Test] - public static void Test_EntityStore_CopyTo() + public static void Test_EntityStore_CloneEntity_2() { var store = new EntityStore(); var entity1 = store.CreateEntity(); @@ -250,6 +251,25 @@ public static void Test_EntityStore_CopyTo() AreNotSame(list1, list2); } + [Test] + public static void Test_EntityStore_CloneEntity_IndexedComponent() + { + var store = new EntityStore(); + var index = store.ComponentIndex(); + var entity = store.CreateEntity(1); + + entity.AddComponent(new IndexedInt { value = 42 }); + var entities = index[42]; + AreEqual(1, entities.Count); + AreEqual("{ 1 }", entities.Debug()); + + var clone = store.CloneEntity(entity); + AreEqual(42, clone.GetComponent().value); + entities = index[42]; + AreEqual(2, entities.Count); + AreEqual("{ 1, 2 }",entities.Debug()); + } + [Test] public static void Test_EntityStore_CloneEntity_component_exception() {