Try SpatialOS

Sites

Menu

Using the Dynamic class

All code examples in this section assume using Improbable.Worker; and using Example; (the generated code namespace).

The Improbable.Worker.Dynamic class is a way to execute arbitrary component-related logic in a type-safe way even when the component is not known statically.

Dynamic.ForComponent will invoke a custom handler for a component with a specific ID. Dynamic.ForEachComponent will invoke a custom handler for every known component.

These handlers have enough information to register Dispatcher callbacks, manipulate component updates and data, and so on.

Example of usage

Dynamic allows you to implement, for example, a custom View with any desired semantics from scratch:

using Improbable;
using Improbable.Collections;
using Improbable.Worker;

public sealed class CustomView : Dispatcher
{
    // Maintain a Map of the entities in this worker's view.
    private readonly Map<EntityId, Entity> entities = new Map<EntityId, Entity>();

    private readonly Map<EntityId, Map<uint, Authority>> authorityMap =
        new Map<EntityId, Map<uint, Authority>>();

    // Current component data for all entities in the worker's view.
    public Map<EntityId, Entity> Entities
    {
        get { return entities; }
    }

    // Current authority delegations.
    public Map<EntityId, Map<uint, Authority>> AuthorityMap
    {
        get { return authorityMap; }
    }


    // Helper function that checks if the worker has authority over a particular component of a
    // particular entity.
    public Authority GetAuthority<C>(EntityId entityId) where C : IComponentMetaclass, new()
    {
        Map<uint, Authority> entityAuthority;
        if (!authorityMap.TryGetValue(entityId, out entityAuthority))
        {
            return Authority.NotAuthoritative;
        }

        Authority componentAuthority;
        return entityAuthority.TryGetValue(Dynamic.GetComponentId<C>(), out componentAuthority) ? componentAuthority : Authority.NotAuthoritative;
    }

    // An implementation of Dynamic.Handler to provide type-safe behaviour for 
    // the components.
    private class TrackComponent : Dynamic.Handler
    {
        private readonly CustomView view;

        public TrackComponent(CustomView view)
        {
            this.view = view;
        }

        // Define the type-safe behaviour in the Accept method. 
        // Here, we are specifying callbacks to update our view's entities map
        // when components are added or removed, when the worker's authority
        // over an entity changes or when we receive component updates.
        public void Accept<C>(C metaclass) where C : IComponentMetaclass
        {
            view.OnAddComponent<C>(op =>
            {
                if (view.Entities.ContainsKey(op.EntityId))
                {
                    view.Entities[op.EntityId].Add<C>(op.Data);
                }
                if (view.AuthorityMap.ContainsKey(op.EntityId))
                {
                    view.AuthorityMap[op.EntityId][metaclass.ComponentId] = Authority.NotAuthoritative;
                }
            });
            view.OnRemoveComponent<C>(op =>
            {
                if (view.Entities.ContainsKey(op.EntityId))
                {
                    view.Entities[op.EntityId].Remove<C>();
                }
                if (view.AuthorityMap.ContainsKey(op.EntityId))
                {
                    view.AuthorityMap[op.EntityId].Remove(metaclass.ComponentId);
                }
            });
            view.OnAuthorityChange<C>(op =>
            {
                if (view.AuthorityMap.ContainsKey(op.EntityId))
                {
                    view.AuthorityMap[op.EntityId][metaclass.ComponentId] = op.Authority;
                }
            });
            view.OnComponentUpdate<C>(op =>
            {
                if (view.Entities.ContainsKey(op.EntityId))
                {
                    view.Entities[op.EntityId].Update<C>(op.Update);
                }
            });
        }
    }

    public CustomView()
    {
        // When entities are added or removed, the Entities map is updated.
        OnAddEntity(op =>
        {
            Entities.Add(op.EntityId, new Entity());
            AuthorityMap.Add(op.EntityId, new Map<uint, Authority>());
        });
        OnRemoveEntity(op =>
        {
            Entities.Remove(op.EntityId);
            AuthorityMap.Remove(op.EntityId);
        });
        // Invoke the TrackComponent handler for every component.
        Dynamic.ForEachComponent(new TrackComponent(this));
    }
}

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums