You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One issue I have ran into is that as relationships use plain old Entity for tracking instead of EntityReference, it is difficult to handle what happens with transient objects.
Consider the following example:
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B.
3- Delete B.
If blindly iterating the TransformChild relationships of A, you will hit an AccessViolation if not checking for IsAlive. Using IsAlive works to prevent the AVE, but causes a further problem shown in this pattern
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B.
3- Delete B.
3- Create entity C
Due to C recycling the ID for B, as far as the system is concerned C is now a child of A.
My solution to this has been to add the idea of "Reciprocal relationships" as well as a custom Destroy function which is aware of them. In my reciprocal relationships feature, it works like this
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B. A TransformParent relationship is created from B to A
3- Destroy B with custom destroy method.
That method looks like this
publicstaticclassEcsUtilities{publicstaticvoidSafeDestroyEntity(Entityentity){Worldworld= World.Worlds[entity.WorldId];CleanRelationship<TransformParent,TransformChild>(entity);CleanRelationship<LogicalParent,LogicalChild>(entity);CleanRelationship<Relationship_MaterialInstanceHost,Relationship_MaterialInstance>(entity);CleanRelationship<ScriptAttachedEntity,EntityScript>(entity);RemoveDependents<TransformChild>(world, entity);RemoveDependents<EntityScript>(world, entity);DetachDependents<Relationship_MaterialInstance>(entity);
world.Destroy(entity);}privatestaticvoidDetachDependents<T>(Entityentity){if(!entity.HasRelationship<T>()){return;}foreach(KeyValuePair<Entity,T> dependent in entity.GetRelationships<T>()){
dependent.Key.RemoveRelationship<T>(entity);}}[SkipLocalsInit]privatestaticvoidRemoveDependents<T>(Worldworld,Entityentity){if(!entity.HasRelationship<T>()){return;}Span<Entity>dependents=stackalloc Entity[16];while(true){if(!entity.HasRelationship<T>()){return;}varcount=0;Relationship<T>relationship= entity.GetRelationships<T>();foreach(KeyValuePair<Entity,T> dependent in relationship){
dependents[count++]= dependent.Key;if(count== dependents.Length){break;}}if(count==0){break;}
Cull(entity, dependents, count);}return;staticvoidCull(Entityentity,Span<Entity>entities,intcount){for(varindex=0;index<count;index++){Entitydependent= entities[index];if(dependent.IsAlive()){
entity.RemoveRelationship<T>(dependent);
SafeDestroyEntity(dependent);}else{
entity.RemoveRelationship<T>(dependent);}}}}privatestaticvoidCleanRelationship<TOwn,TReciprocal>(Entityentity){if(!entity.HasRelationship<TOwn>()){return;}foreach(KeyValuePair<Entity,TOwn> existingParent in entity.GetRelationships<TOwn>()){if(existingParent.Key.HasRelationship<TReciprocal>(entity)){
existingParent.Key.RemoveRelationship<TReciprocal>(entity);}if(entity.HasRelationship<TOwn>(existingParent.Key)){
entity.RemoveRelationship<TOwn>(existingParent.Key);}}}}
There are two things I think would be nice here to have this just work out of the box:
1- (Required) Use EntityReference for relationship tracking, not Entity. This avoids the two scenarios I listed above
2- (Nice to have) The concept of dependent relationships, and that if an entity is deleted any entity with a dependent relationship is also deleted. An example of this would be if a TransformParent is deleted, it's typical for the child entities to also be deleted.
The text was updated successfully, but these errors were encountered:
One issue I have ran into is that as relationships use plain old Entity for tracking instead of EntityReference, it is difficult to handle what happens with transient objects.
Consider the following example:
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B.
3- Delete B.
If blindly iterating the TransformChild relationships of A, you will hit an AccessViolation if not checking for IsAlive. Using IsAlive works to prevent the AVE, but causes a further problem shown in this pattern
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B.
3- Delete B.
3- Create entity C
Due to C recycling the ID for B, as far as the system is concerned C is now a child of A.
My solution to this has been to add the idea of "Reciprocal relationships" as well as a custom Destroy function which is aware of them. In my reciprocal relationships feature, it works like this
1- Create entities A and B.
2- Create a "TransformChild" relationship from A to B. A TransformParent relationship is created from B to A
3- Destroy B with custom destroy method.
That method looks like this
There are two things I think would be nice here to have this just work out of the box:
1- (Required) Use EntityReference for relationship tracking, not Entity. This avoids the two scenarios I listed above
2- (Nice to have) The concept of dependent relationships, and that if an entity is deleted any entity with a dependent relationship is also deleted. An example of this would be if a TransformParent is deleted, it's typical for the child entities to also be deleted.
The text was updated successfully, but these errors were encountered: