Get SpatialOS

Sites

Menu
These are the docs for 13.1, an old version of SpatialOS. 13.3 is the newest →

Using Dynamic

The improbable.worker.Dynamic class provides 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.

This allows, for example, a custom View with any desired semantics to be implemented from scratch.

To do this, you would extend Dispatcher, adding data structures such as Map<EntityId, Entity> entities and Map<EntityId, HashSet<Integer>> authority below to track the entities in the worker’s view.

You would then also need to define a class which implements the Dynamic.Handler interface, providing type-safe behaviour in the accept(final Metaclass metaclass) method. Dynamic allows you to implement, for example, a custom View with any desired semantics from scratch.

package docs;

import improbable.worker.*;

public class CustomView extends Dispatcher {
    // Maintain a Map of the entities in this worker's view.
    public final java.util.Map<EntityId, Entity> entities = new java.util.LinkedHashMap<>();
    public final java.util.Map<EntityId, java.util.Map<Integer, Authority>> authority = new java.util.LinkedHashMap<>();

    public <Metaclass extends ComponentMetaclass>
    Authority getAuthority(Metaclass metaclass, EntityId entityId) {
        java.util.Map<Integer, Authority> componentAuthorities = authority.get(entityId);
        if (componentAuthorities == null) {
            return Authority.NOT_AUTHORITATIVE;
        }

        Authority authority = componentAuthorities.get(metaclass.getComponentId());
        return authority != null ? authority : Authority.NOT_AUTHORITATIVE;
    }

    // An implementation of Dynamic.Handler to provide type-safe behaviour for
    // the components.
    private class TrackComponent implements Dynamic.Handler {
        // The Accept method defines the type-safe behaviour.
        // Here, we are specifying callbacks to update our view's state
        // when components are added or removed, when the worker's authority changes,
        // or when we receive component updates.
        @Override
        public <Metaclass extends ComponentMetaclass<Data, Update>, Data, Update>
        void accept(final Metaclass metaclass) {
            onAddComponent(metaclass, op -> {
                Entity entity = entities.get(op.entityId);
                if (entity != null) {
                    entity.add(metaclass, op.data);
                }
                java.util.Map<Integer, Authority> entityAuthority = authority.get(op.entityId);
                if (entityAuthority != null) {
                    entityAuthority.put(metaclass.getComponentId(), Authority.NOT_AUTHORITATIVE);
                }
            });

            onRemoveComponent(metaclass, op -> {
                Entity entity = entities.get(op.entityId);
                if (entity != null) {
                    entity.remove(metaclass);
                }
                java.util.Map<Integer, Authority> entityAuthority = authority.get(op.entityId);
                if (entityAuthority != null) {
                    entityAuthority.remove(metaclass.getComponentId());
                }
            });

            onAuthorityChange(metaclass, op -> {
                java.util.Map<Integer, Authority> entityAuthority = authority.get(op.entityId);
                if (entityAuthority != null) {
                    entityAuthority.put(metaclass.getComponentId(), op.authority);
                }
            });

            onComponentUpdate(metaclass, op -> {
                Entity entity = entities.get(op.entityId);
                if (entity != null) {
                    entity.update(metaclass, op.update);
                }
            });
        }
    }

    public CustomView() {
        // Update the entities Map to reflect when entities are added or removed.
        onAddEntity(op -> {
            entities.put(op.entityId, new Entity());
            authority.put(op.entityId, new java.util.HashMap<>());
        });

        onRemoveEntity(op -> {
            entities.remove(op.entityId);
            authority.remove(op.entityId);
        });

        // Invoke the TrackComponent handler for every component.
        Dynamic.forEachComponent(new TrackComponent());
    }
}

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums