@@ -276,6 +276,31 @@ public Entity Create(params ComponentType[] types)
276
276
/// <returns></returns>
277
277
[ StructuralChange ]
278
278
public Entity Create ( in Signature types )
279
+ {
280
+ var entity = CreateNoEvent ( types ) ;
281
+
282
+ OnEntityCreated ( entity ) ;
283
+ #if EVENTS
284
+ foreach ( ref var type in types )
285
+ {
286
+ OnComponentAdded ( entity , type ) ;
287
+ }
288
+ #endif
289
+
290
+ return entity ;
291
+ }
292
+
293
+ /// <summary>
294
+ /// Creates a new <see cref="Entity"/> using its given component structure/<see cref="Archetype"/>.
295
+ /// Might resize its target <see cref="Archetype"/> and allocate new space if its full.
296
+ /// </summary>
297
+ /// <remarks>
298
+ /// Causes a structural change.
299
+ /// </remarks>
300
+ /// <param name="types">Its component structure/<see cref="Archetype"/>.</param>
301
+ /// <returns></returns>
302
+ [ StructuralChange ]
303
+ private Entity CreateNoEvent ( in Signature types )
279
304
{
280
305
// Recycle id or increase
281
306
var recycle = RecycledIds . TryDequeue ( out var recycledId ) ;
@@ -298,14 +323,6 @@ public Entity Create(in Signature types)
298
323
// Add entity to info storage
299
324
EntityInfo . Add ( entity . Id , recycled . Version , archetype , slot ) ;
300
325
Size ++ ;
301
- OnEntityCreated ( entity ) ;
302
-
303
- #if EVENTS
304
- foreach ( ref var type in types )
305
- {
306
- OnComponentAdded ( entity , type ) ;
307
- }
308
- #endif
309
326
310
327
return entity ;
311
328
}
@@ -569,6 +586,62 @@ public override string ToString()
569
586
{
570
587
return $ "{ GetType ( ) . Name } {{ { nameof ( Id ) } = { Id } , { nameof ( Capacity ) } = { Capacity } , { nameof ( Size ) } = { Size } }}";
571
588
}
589
+
590
+ /// <summary>
591
+ /// Create a copy of the given entity.
592
+ /// </summary>
593
+ public Entity Duplicate ( Entity sourceEntity )
594
+ {
595
+ Debug . Assert ( IsAlive ( sourceEntity ) ) ;
596
+ Archetype archetype = GetArchetype ( sourceEntity ) ;
597
+ Entity destinationEntity = CreateNoEvent ( archetype . Signature ) ;
598
+ EntitySlot fromIndex = EntityInfo . GetEntitySlot ( sourceEntity . Id ) ;
599
+ EntitySlot destinationIndex = EntityInfo . GetEntitySlot ( destinationEntity . Id ) ;
600
+ ref Chunk fromChunk = ref archetype . GetChunk ( fromIndex . Slot . ChunkIndex ) ;
601
+ ref Chunk toChunk = ref archetype . GetChunk ( destinationIndex . Slot . ChunkIndex ) ;
602
+ for ( int i = 0 ; i < fromChunk . Components . Length ; ++ i )
603
+ {
604
+ Array fromArray = fromChunk . Components [ i ] ;
605
+ Array toArray = toChunk . Components [ i ] ;
606
+ Array . Copy ( fromArray , fromIndex . Slot . Index , toArray , destinationIndex . Slot . Index , 1 ) ;
607
+ }
608
+
609
+ OnEntityCreated ( sourceEntity ) ;
610
+ #if EVENTS
611
+ foreach ( var type in archetype . Types )
612
+ {
613
+ OnComponentAdded ( sourceEntity , type ) ;
614
+ }
615
+ #endif
616
+
617
+ return destinationEntity ;
618
+ }
619
+
620
+ /// <summary>
621
+ /// Create n copies of the given entity.
622
+ /// </summary>
623
+ public void DuplicateN ( Entity sourceEntity , int n , Span < Entity > outputSpan )
624
+ {
625
+ Debug . Assert ( IsAlive ( sourceEntity ) ) ;
626
+ Debug . Assert ( n > 0 ) ;
627
+ Debug . Assert ( n <= outputSpan . Length ) ;
628
+ // Note: this could be optimised by getting the chunks and using
629
+ // Array.Fill(), assuming we could guarantee writing to the end of the
630
+ // chunk.
631
+ for ( int i = 0 ; i < n ; ++ i )
632
+ {
633
+ outputSpan [ i ] = Duplicate ( sourceEntity ) ;
634
+ }
635
+ }
636
+
637
+ /// <summary>
638
+ /// Create n copies of the given entity, where n is outputSpan.Length.
639
+ /// </summary>
640
+ public void DuplicateN ( Entity sourceEntity , Span < Entity > outputSpan )
641
+ {
642
+ Debug . Assert ( IsAlive ( sourceEntity ) ) ;
643
+ DuplicateN ( sourceEntity , outputSpan . Length , outputSpan ) ;
644
+ }
572
645
}
573
646
574
647
#endregion
0 commit comments