Sites

Menu
These are the docs for 12.2, an old version of SpatialOS. The docs for this version are frozen: we do not correct, update or republish them. 14.2 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