Get SpatialOS

Sites

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