diff --git a/src/Arch.Tests/ArchetypeTest.cs b/src/Arch.Tests/ArchetypeTest.cs
index d02ff46..bfea697 100644
--- a/src/Arch.Tests/ArchetypeTest.cs
+++ b/src/Arch.Tests/ArchetypeTest.cs
@@ -245,7 +245,6 @@ public void CopyTo([Values(1111,2222,3333)] int sourceAmount, [Values(1111,2222,
// Copy from one chunk into other.
Archetype.Copy(source, destination);
- source.Clear();
var sourceCounter = sourceAmount;
var destinationCounter = destinationAmount;
@@ -358,7 +357,6 @@ public void CopyToShift([Values(1111,2222,3333)] int sourceAmount, [Values(1111,
// Copy from one chunk into other.
Archetype.Copy(source, destination);
- source.Clear();
var requiredChunksForSource = Archetype.GetChunkCapacityFor(source.EntitiesPerChunk, sourceAmount);
var requiredChunksForDestination = Archetype.GetChunkCapacityFor(destination.EntitiesPerChunk, sourceAmount + destinationAmount);
diff --git a/src/Arch.Tests/WorldTest.cs b/src/Arch.Tests/WorldTest.cs
index 0c5d347..d6d47b9 100644
--- a/src/Arch.Tests/WorldTest.cs
+++ b/src/Arch.Tests/WorldTest.cs
@@ -866,4 +866,69 @@ public void GeneratedAdd()
That(_world.GetArchetype(entity2), Is.EqualTo(_world.GetArchetype(entity)));
That(arch, Is.EqualTo(_world.GetArchetype(entity)));
}
+
+ ///
+ /// Checks if the is copied correctly over a new instance.
+ ///
+ [Test]
+ public void Copy()
+ {
+ using var source = World.Create();
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Transform());
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Rotation());
+ source.Create(new Transform());
+
+ var copy = source.Copy();
+
+ That(copy.Size, Is.EqualTo(source.Size));
+ That(copy.Capacity, Is.EqualTo(source.Capacity));
+ That(copy.Archetypes.Count, Is.EqualTo(source.Archetypes.Count));
+ //same amount of entities per archetype
+ for (var index = 0; index < copy.Archetypes.Items.Count; index++)
+ {
+ var copyArchetype = copy.Archetypes.Items[index];
+ var sourceArchetypeExists = source.TryGetArchetype(copyArchetype.Signature, out var sourceArchetype);
+ That(sourceArchetypeExists, Is.True);
+ That(sourceArchetype, Is.Not.Null);
+ That(copyArchetype.Count, Is.EqualTo(sourceArchetype.Count));
+ That(copyArchetype.EntityCount, Is.EqualTo(sourceArchetype.EntityCount));
+ }
+ }
+
+ ///
+ /// Checks if the is copied correctly over a new instance, skipping empty archetypes.
+ ///
+ [Test]
+ public void CopySkipping()
+ {
+ using var source = World.Create();
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Transform());
+ source.Create(new Transform(), new Rotation());
+ source.Create(new Transform());
+ source.Create(new Transform());
+ //this will cause one archetype to be empty and ignored in the copy
+ source.Destroy(source.Create(new Rotation()));
+
+ var copy = source.Copy();
+
+ That(copy.Size, Is.EqualTo(source.Size));
+ //LessThan because one archetype got skipped
+ That(copy.Capacity, Is.LessThan(source.Capacity));
+ That(copy.Archetypes.Count, Is.LessThan(source.Archetypes.Count));
+ //same amount of entities per archetype
+ for (var index = 0; index < copy.Archetypes.Items.Count; index++)
+ {
+ var copyArchetype = copy.Archetypes.Items[index];
+ var sourceArchetypeExists = source.TryGetArchetype(copyArchetype.Signature, out var sourceArchetype);
+ That(sourceArchetypeExists, Is.True);
+ That(sourceArchetype, Is.Not.Null);
+ That(copyArchetype.Count, Is.EqualTo(sourceArchetype.Count));
+ That(copyArchetype.EntityCount, Is.EqualTo(sourceArchetype.EntityCount));
+ }
+ }
}
diff --git a/src/Arch/Core/Archetype.cs b/src/Arch/Core/Archetype.cs
index 931df94..a06537a 100644
--- a/src/Arch/Core/Archetype.cs
+++ b/src/Arch/Core/Archetype.cs
@@ -867,7 +867,8 @@ internal static int GetNextSlots(Archetype archetype, Span slots, int amou
///
/// The source .
/// The destination .
- internal static void Copy(Archetype source, Archetype destination)
+ /// Whether to clear the source Archetype and Chunk counts.
+ internal static void Copy(Archetype source, Archetype destination, bool clearSource = true)
{
// Make sure other archetype can fit additional entities from this archetype.
destination.EnsureEntityCapacity(destination.EntityCount + source.EntityCount);
@@ -880,19 +881,25 @@ internal static void Copy(Archetype source, Archetype destination)
var amountCopied = 0;
var chunkIndex = 0;
+ var amountLeft = sourceChunk.Count;
// Loop over destination chunk and fill them with the source chunk till either the source chunk is empty or theres no more capacity
- for (int destinationChunkIndex = destination.Count; destinationChunkIndex < destination.ChunkCapacity && sourceChunk.Count > 0; destinationChunkIndex++)
+ for (int destinationChunkIndex = destination.Count; destinationChunkIndex < destination.ChunkCapacity && amountLeft > 0; destinationChunkIndex++)
{
// Determine amount that can be copied into destination
ref var destinationChunk = ref destination.GetChunk(destinationChunkIndex);
var remainingCapacity = destinationChunk.Buffer;
- var amountToCopy = Math.Min(sourceChunk.Count, remainingCapacity);
+ var amountToCopy = Math.Min(amountLeft, remainingCapacity);
Chunk.Copy(ref sourceChunk, amountCopied, ref sourceSignature, ref destinationChunk, destinationChunk.Count, amountToCopy);
// Apply copied amount to track the progress
- sourceChunk.Count -= amountToCopy;
+ amountLeft -= amountToCopy;
+ if (clearSource)
+ {
+ sourceChunk.Count -= amountToCopy;
+ }
+
destinationChunk.Count += amountToCopy;
amountCopied += amountToCopy;
chunkIndex = destinationChunkIndex; // Track the last destination chunk we filled, important
@@ -903,8 +910,11 @@ internal static void Copy(Archetype source, Archetype destination)
// Update entity counts
destination.EntityCount += source.EntityCount;
- source.EntityCount = 0;
- source.Count = 0;
+ if (clearSource)
+ {
+ source.EntityCount = 0;
+ source.Count = 0;
+ }
}
///
diff --git a/src/Arch/Core/World.cs b/src/Arch/Core/World.cs
index 5af4c0b..9fdeb4b 100644
--- a/src/Arch/Core/World.cs
+++ b/src/Arch/Core/World.cs
@@ -1744,4 +1744,31 @@ public Signature GetSignature(Entity entity)
}
}
+public partial class World
+{
+ ///
+ /// Creates a deep copy of the world, copying archetypes and chunks.
+ ///
+ /// A newly created World with all data copied from the original.
+ public World Copy()
+ {
+ var copy = Create();
+ var archetypes = Archetypes.Items;
+ for (var index= 0; index < archetypes.Count; index++)
+ {
+ var archetype = archetypes[index];
+ if (archetype.EntityCount <= 0)
+ {
+ continue;
+ }
+
+ var newArchetype = copy.GetOrCreate(archetype.Signature);
+ Archetype.Copy(archetype, newArchetype, false);
+ copy.Size += newArchetype.EntityCount;
+ }
+
+ return copy;
+ }
+}
+
#endregion