Skip to content

Moving queries to the Bridge layer (Pull Data from DOTS Layer)

What

Sometimes our MonoBehaviours are querying the ECS World directly. Here's an example from ResourcesDialog before the refactoring:

    public sealed class ResourcesDialog : AAnimatedCloseableDialog {
        public bool TryGetResourceAmountAndEntity(long resourceId, out ResourceAmount resourceAmount, out Entity entity) {
            using EntityQuery entityQuery = _context.EntityManager.CreateEntityQuery(ComponentType.ReadOnly<ResourceAmount>());
            using NativeArray<Entity> entities = entityQuery.ToEntityArray(Allocator.Temp);
            using NativeArray<ResourceAmount> resourceAmounts = entityQuery.ToComponentDataArray<ResourceAmount>(Allocator.Temp);
            for (int index = 0; index < resourceAmounts.Length; index++) {
                if (resourceAmounts[index].ResourceEntryRef.Id != resourceId) {
                    continue;
                }

                resourceAmount = resourceAmounts[index];
                entity = entities[index];
                return true;
            }

            resourceAmount = default;
            entity = Entity.Null;
            return false;
        }
    }

Why

The Managed Layer ideally shouldn't know about any DOTS features and shouldn't query the ECS World directly, the Bridge Layer is responsible for that.

How

We can move the queries to our Bridge classes and since they're systems, they have full access to SystemAPI and we can create simpler and more performant code.

    internal sealed partial class ResourceUiBridgeSystem : SystemBase {
        private bool TryGetResourceAmountAndEntity(
            long resourceId,
            out ResourceReference resourceAmount,
            out Entity resourceEntity
        ) {
            foreach ((ResourceReference resourceReference, Entity entity) in SystemAPI.Query<ResourceReference>()
                         .WithEntityAccess()) {
                if (resourceReference.ResourceEntryRef.Id != resourceId) {
                    continue;
                }

                resourceAmount = resourceReference;
                resourceEntity = entity;
                return true;
            }

            resourceAmount = default;
            resourceEntity = Entity.Null;
            return false;
        }
    }