Get SpatialOS

Sites

Menu

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