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
Mentioned this on the Discord a couple times. In my game I have the concept of multiple separated worlds being active and simulated at once, with entities transitioning from one world to another at certain transition points. I also use Relationships for various things (parent-child relationships, material instancing for draw batching, particle emitter batching)
When an entity crosses a transition point, I "move" it by duplicating the entity and erasing the old one. This is where problems come in - GetComponentTypes() also returns the internal Relationship tracking components. You need to use reflection to filter out the relationship components, or you will likely get an AccessViolationException due to the invalid setup post-cloning.
Below is my CloneEntityRecursive method which does this step.
privatestatic Entity CloneEntityRecursive(EntitysourceEntity,WorldtargetWorld,Dictionary<Entity,Entity>oldToNewEntityMap,List<Entity>scripts){if(oldToNewEntityMap.TryGetValue(sourceEntity,out Entity existingEntity)){returnexistingEntity;}
ComponentType[]sourceEntityTypes= sourceEntity.GetComponentTypes().Where(t =>!t.Type.Name.Contains("Relationship")).ToArray();EntitynewSourceEntity= targetWorld.Create(sourceEntityTypes);foreach(ComponentType type in sourceEntityTypes){if(sourceEntity.Get(type)is{} value){
newSourceEntity.Set(value);}}if(sourceEntity.HasRelationship<TransformChild>()){foreach(KeyValuePair<Entity,TransformChild> child in sourceEntity.GetRelationships<TransformChild>()){EntitynewChild= CloneEntityRecursive(child.Key, targetWorld, oldToNewEntityMap, scripts);
newChild.SetTransformParent(newSourceEntity);}}if(sourceEntity.HasRelationship<LogicalChild>()){foreach(KeyValuePair<Entity,LogicalChild> child in sourceEntity.GetRelationships<LogicalChild>()){EntitynewChild= CloneEntityRecursive(child.Key, targetWorld, oldToNewEntityMap, scripts);
newChild.SetTransformParent(newSourceEntity, inheritTransforms:false);}}if(sourceEntity.HasRelationship<EntityScript>()){foreach(KeyValuePair<Entity,EntityScript> script in sourceEntity.GetRelationships<EntityScript>()){EntitynewScriptEntity= CloneEntityRecursive(script.Key, targetWorld, oldToNewEntityMap, scripts);
newScriptEntity.AddRelationship(newSourceEntity,new ScriptAttachedEntity());
newSourceEntity.AddRelationship(newScriptEntity,new EntityScript(script.Value.Script));
Log.Info($"Found script {script.Value.Script.AssetUri.Uri}. Entity {script.Key.Id}");
scripts.Add(newScriptEntity);}}
oldToNewEntityMap[sourceEntity]=newSourceEntity;returnnewSourceEntity;}
and SyncEntities, where I support unpacking one World into another
privatevoidSyncEntities(Worldworld,Span<Entity>entities,List<EntityGuidLookup>newEntityGuidLookups,List<EntityScriptGuidLookup>newEntityScriptGuidLookups,Dictionary<Entity,Entity>newEntityToLevelEntity){foreach(Entity entity in entities){varcomponents= entity.GetComponentTypes().Where(c => c.Type!.GetInterface("IRelationship")isnull).ToArray();EntitynewEntity= world.Create(components);foreach(object? component in entity.GetAllComponents()){if(component isnull){
Log.Error("Component is null");continue;}if(component.GetType().GetInterface("IRelationship")is not null){continue;}
newEntity.Set(component);if(this.entityGuidLookup.TryGetValue((entity, component.GetType()),out EntityGuidLookup lookup)){
newEntityGuidLookups.Add(lookup with{Entity=newEntity});}}if(this.entityScriptGuidLookup.TryGetValue(entity,out EntityScriptGuidLookup scriptLookup)){
newEntityScriptGuidLookups.Add(scriptLookup with{Entity=newEntity});}
newEntityToLevelEntity[newEntity]=entity;}}
Ideally there are 2 changes required here:
1 - The Relationship tracking components are made public so we do not need to resort to magic string name based reflection
2 - Relationship Components are somehow stored separately in the archetype to real components allowing for direct grabbing of the source components
The text was updated successfully, but these errors were encountered:
Mentioned this on the Discord a couple times. In my game I have the concept of multiple separated worlds being active and simulated at once, with entities transitioning from one world to another at certain transition points. I also use Relationships for various things (parent-child relationships, material instancing for draw batching, particle emitter batching)
When an entity crosses a transition point, I "move" it by duplicating the entity and erasing the old one. This is where problems come in -
GetComponentTypes()
also returns the internal Relationship tracking components. You need to use reflection to filter out the relationship components, or you will likely get an AccessViolationException due to the invalid setup post-cloning.Below is my CloneEntityRecursive method which does this step.
and SyncEntities, where I support unpacking one World into another
Ideally there are 2 changes required here:
1 - The Relationship tracking components are made public so we do not need to resort to magic string name based reflection
2 - Relationship Components are somehow stored separately in the archetype to real components allowing for direct grabbing of the source components
The text was updated successfully, but these errors were encountered: