Search Unity

Question Best way to use systems globally?

Discussion in 'Entity Component System' started by metageist, Jun 5, 2023.

  1. metageist

    metageist

    Joined:
    Mar 16, 2019
    Posts:
    27
    I made a static method in a system for a method I need to access from other parts of my code.
    I was wondering the following:
    1. Does this work properly in Entities 1.0?
    2. What is the best practice?

    Code (CSharp):
    1.         public static CellCoordinatesData FindCellCoordinatesDataFromInt3(int3 hcoo)
    2.         {
    3.             CellFindSystem current = World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged<CellFindSystem>();
    4.             NativeArray<CellCoordinatesData> result = new(1, Allocator.TempJob);
    5.             var lookupHandle = new FindCoordsFromInt3Job
    6.             {
    7.                 target = hcoo,
    8.                 coordsLookup = current.GetComponentTypeHandle<CellCoordinatesData>(true),
    9.                 foundCoords = result
    10.             }.ScheduleParallel(current.GetEntityQuery(typeof(CellCoordinatesData)), current.Dependency);
    11.  
    12.             lookupHandle.Complete();
    13.             var found = result[0];
    14.             result.Dispose();
    15.             return found;
    16.         }
    Paired IJobChunk:
    Code (CSharp):
    1. [BurstCompile]
    2.         public struct FindCoordsFromInt3Job : IJobChunk
    3.         {
    4.             [ReadOnly] public ComponentTypeHandle<CellCoordinatesData> coordsLookup;
    5.             public int3 target;
    6.             public NativeArray<CellCoordinatesData> foundCoords;
    7.  
    8.             public void Execute(in ArchetypeChunk chunk, int chunkIndex, bool useMask, in v128 mask)
    9.             {
    10.                 var coordsAccess = chunk.GetNativeArray(ref coordsLookup);
    11.                 var enumerator = new ChunkEntityEnumerator(useMask, mask, chunk.Count);
    12.                 while (enumerator.NextEntityIndex(out int i))
    13.                 {
    14.                     if (coordsAccess[i].cubeCoordsFlat.Equals(target))
    15.                     {
    16.                         foundCoords[0] = coordsAccess[i];
    17.                         return;
    18.                     }
    19.                 }
    20.             }
    21.         }
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    1. Should be no difference, except in system access.
    2. Best practice is not to do it at all.
    Reverse control and feed data from the system to the MonoBehaviour via SystemBase.

    Alternatively - wrap logic & job scheduling inside an actual system method. Should look better.
    Result container can be passed as ref as well. For single value use NativeReference<T>.
     
  3. metageist

    metageist

    Joined:
    Mar 16, 2019
    Posts:
    27
    I also am starting to get a grasp on singleton entities which can really help streamline interactivity between systems.

    I guess my real question would be: Is calling World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged<[systemname]>()'s EntityManager the best practice way to trigger ECS functionality from outside ECS (such as from GameObjects or user interface)?
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    EntityManager is universal per World. So if you need to - you can always just cache the EntityManager itself.
    (its a reference struct)

    Otherwise, keep logic inside systems and cache system reference.

    Or you can iterate over component objects with query & managed system (SystemBase).
    So no need to call in from the outside. (use .AddComponentObject<T> to add a MonoBehaviour / ScriptableObject / any other UnityEngine.Object)
     
  5. metageist

    metageist

    Joined:
    Mar 16, 2019
    Posts:
    27
    I'm getting this error at line 4 in this instance of using this method now. This wasn't an issue in 0.51.

    Assets\Scripts\DOTS\Systems\SOtoBlobSystem.cs(81,39): error CS0120: An object reference is required for the non-static field, method, or property 'SOtoBlobSystem.__query_1883632248_1'

    Code (CSharp):
    1. public static StatBlob GetStat(Stat stat)
    2.         {
    3.             SOtoBlobSystem sys = World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged<SOtoBlobSystem>();
    4.             var singletonStatBuffer = sys.GetSingletonBuffer<BakedStats>(true);
    5.             foreach (var item in singletonStatBuffer)
    6.             {
    7.                 if (item.stat.Value.ID == stat.ID) { return item.stat.Value; }
    8.             }
    9.             Debug.LogWarning($"No baked stat found for {stat.name} !");
    10.             return new StatBlob();
    11.         }