@@ -276,6 +276,31 @@ public Entity Create(params ComponentType[] types)
276276 /// <returns></returns>
277277 [ StructuralChange ]
278278 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 )
279304 {
280305 // Recycle id or increase
281306 var recycle = RecycledIds . TryDequeue ( out var recycledId ) ;
@@ -298,14 +323,6 @@ public Entity Create(in Signature types)
298323 // Add entity to info storage
299324 EntityInfo . Add ( entity . Id , recycled . Version , archetype , slot ) ;
300325 Size ++ ;
301- OnEntityCreated ( entity ) ;
302-
303- #if EVENTS
304- foreach ( ref var type in types )
305- {
306- OnComponentAdded ( entity , type ) ;
307- }
308- #endif
309326
310327 return entity ;
311328 }
@@ -569,6 +586,62 @@ public override string ToString()
569586 {
570587 return $ "{ GetType ( ) . Name } {{ { nameof ( Id ) } = { Id } , { nameof ( Capacity ) } = { Capacity } , { nameof ( Size ) } = { Size } }}";
571588 }
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+ }
572645}
573646
574647#endregion
0 commit comments