Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Iterating over a collection of datatypes and calling SetComponentData

Discussion in 'Entity Component System' started by AlexAdach, Jul 27, 2023.

  1. AlexAdach

    AlexAdach

    Joined:
    Jan 25, 2023
    Posts:
    24
    I grouped a bunch of data components in a dictionary in one of my monobehavior classes. I had added an interface ISystemManagerData to each of these components, and grouped them by that type. Is there any way to cast their types into their original types so that I can use them to call EntityManger.SetComponentData?

    Example:
    Code (CSharp):
    1.     public class CharacterNavigationSystemManager : SystemManagerBase
    2.     {
    3.         public EnemyRandomNavTargetGeneratorData EnemyRandomNavTargetGeneratorData;
    4.         public EnemySetFixedNavTargetData EnemySetFixedNavTargetData;
    5.  
    6.         protected override void Start()
    7.         {
    8.             systems = new Dictionary<SystemHandle, ISystemManagerData>()
    9.             {
    10.                 { world.GetExistingSystem<EnemyRandomNavTargetGeneratorSystem>(), EnemyRandomNavTargetGeneratorData },
    11.                 { world.GetExistingSystem<EnemySetFixedNavTargetSystem>(), EnemySetFixedNavTargetData }
    12.  
    13.             };
    14.         }
    15.  
    16.         protected override void Update()
    17.         {
    18.             base.Update();
    19.         }
    20.     }
    21.  
    22.    public class SystemManagerBase : MonoBehaviour
    23.     {
    24.         protected World world => World.DefaultGameObjectInjectionWorld;
    25.         protected WorldUnmanaged worldUnmanaged => World.DefaultGameObjectInjectionWorld.Unmanaged;
    26.         protected Dictionary<SystemHandle, ISystemManagerData> systems;
    27.         protected MethodInfo SetComponentDataGeneric;
    28.         // Start is called before the first frame update
    29.         protected virtual void Awake()
    30.         {
    31.             //var SetComponentDataGeneric = world.EntityManager.GetType().GetMethod("SetComponentData");
    32.         }
    33.         protected virtual void Start()
    34.         {
    35.         }
    36.        
    37.         protected virtual void Update()
    38.         {
    39.             foreach (var system in systems)
    40.             {
    41.                 var state = worldUnmanaged.ResolveSystemStateRef(system.Key);
    42.                 state.Enabled = system.Value.Enabled;
    43.                
    44.             }
    45.             //UpdateAllComoponentValues();
    46.         }
    47.         protected virtual void OnValidate()
    48.         {
    49.         }
    50.         //Here's my latest chat gpt reflection nonesense. I tried a bunch of different approaches here.
    51.         private void UpdateAllComoponentValues()
    52.         {
    53.             if (!world.IsCreated)
    54.                 return;
    55.             {
    56.                 foreach (var system in systems)
    57.                 {
    58.                     var componentData = system.Value;
    59.                     Type componentType = componentData.GetType();
    60.                     Type[] parameterTypes = new Type[] { typeof(SystemHandle), componentType };
    61.                     var methodType = world.EntityManager.GetType().GetMethod("SetComponentData", parameterTypes);
    62.                     methodType.Invoke(null, new object[] { system.Key, componentData });
    63.                     MethodInfo genericMethod = methodType.MakeGenericMethod(componentType);
    64.                     genericMethod.Invoke(system.Key, new object[] { componentData });
    65.                     //IComponentData data = system.Value;
    66.                     //Type T = system.Value.GetType().MakeGenericType();
    67.                 }
    68.             }
    69.         }
    70.     }
    71.  
    72.  
    73.  
    74.  
    75.  
    76.  
    77.  
     
  2. AlexAdach

    AlexAdach

    Joined:
    Jan 25, 2023
    Posts:
    24
    I ended up adding this method to all of my ISystemManagerData components
    Code (CSharp):
    1.        void ISystemManagerData.SetSystemData(EntityManager entityManager, SystemHandle handle)
    2.         {
    3.             entityManager.SetComponentData(handle, this);
    4.         }
    edit: nvm this doesn't work since once I add the monobehavior properties to my dictionary the values are copied and making any changes to the properties won't affect the dictionary entries so when it iterates nothing happens.
     
    Last edited: Jul 27, 2023
  3. AlexAdach

    AlexAdach

    Joined:
    Jan 25, 2023
    Posts:
    24
    so instead. I made a wrapper class for the system component data so that I can hold a reference in a collection and automatically iterate over it in Update().

    Code (CSharp):
    1.     [Serializable]
    2.     public class DataRefWrapper<T> : ISystemManagerWrapper where T : unmanaged, IComponentData
    3.     {
    4.         public bool Enabled { get; set; }
    5.         public T Data;
    6.         public SystemHandle SystemHandle { get; set; }
    7.  
    8.        
    9.         void ISystemManagerWrapper.SetData()
    10.         {
    11.             World.DefaultGameObjectInjectionWorld.EntityManager.SetComponentData<T>(SystemHandle, Data);
    12.         }
    13.     }
    and then you can define them as a monobehavior property

    Code (CSharp):
    1. public DataRefWrapper<SpawnEnemiesRandomData> SpawnEnemiesRandomData;
    where SpawnEnemiesRandomData is the actual IComponentData that the system has.