Search Unity

Helpful extension methods for GetSingleton and GetSingletonEntity

Discussion in 'Entity Component System' started by aveakrause, Mar 13, 2020.

  1. aveakrause

    aveakrause

    Joined:
    Oct 3, 2018
    Posts:
    70
    I noticed that GetSingleton and GetSingletonEntity both throw an InvalidOperationException if the entity count is != 1. Figured I'd share so others may benefit, or maybe get Unity to structure the 2 methods more like my extension method.

    (code decompiled from Entities.dll)
    Code (CSharp):
    1. if (GetIndexInEntityQuery(TypeManager.GetTypeIndex<T>()) != 1)
    2. {
    3.     throw new InvalidOperationException($"GetSingleton<{typeof(T)}>() requires that {typeof(T)} is the only component type in its archetype.");
    4. }
    5. int entityCount = CalculateEntityCount();
    6. if (entityCount != 1)
    7. {
    8.     throw new InvalidOperationException($"GetSingleton<{typeof(T)}>() requires that exactly one {typeof(T)} exists but there are {entityCount}.");
    9. }
    Since it is expected that sometimes a singleton entity might not always be exactly 1, such as when you restart a scene, throwing in this case is bad. I wanted a good way to get the data without potentially crashing my game, I'd rather work in a broken state than crash. You could do EntityQuery.CalculateEntityCount(), but Unity is already doing that, so I see no reason to do it twice. So I wrote these 2 methods.

    They take out variables and return true/false so you can just check this really quick in an if.

    Code (CSharp):
    1. namespace AveaUtils
    2. {
    3.     public static class EntityUtils
    4.     {
    5.         public static bool TryGetSingleton<T>(this EntityQuery query, out T singletonComponent) where T : struct, IComponentData
    6.         {
    7.             try
    8.             {
    9.                 singletonComponent = query.GetSingleton<T>();
    10.                 return true;
    11.             }
    12.             catch (InvalidOperationException)
    13.             {
    14.                 singletonComponent = default;
    15.                 return false;
    16.             }
    17.         }
    18.  
    19.         public static bool TryGetSingletonEntity(this EntityQuery query, out Entity entity)
    20.         {
    21.             try
    22.             {
    23.                 entity = query.GetSingletonEntity();
    24.                 return true;
    25.             }
    26.             catch (InvalidOperationException)
    27.             {
    28.                 entity = Entity.Null;
    29.                 return false;
    30.             }
    31.         }
    32.     }
    33. }
    Here's and example of how you may use them.

    Code (CSharp):
    1. CameraSettingsComponent cameraSettingsComponent;
    2. if(!cameraQuery.TryGetSingleton<CameraSettingsComponent>(out cameraSettingsComponent))
    3.     return;
     
    bb8_1 and adammpolak like this.
  2. adammpolak

    adammpolak

    Joined:
    Sep 9, 2018
    Posts:
    450
    Seems like this made it into ECS 17?
     
    bb8_1 likes this.