

Creating and deleting entities

All code examples in this section assume you have defined a MyComponents function as described in Providing components, and set up the following preamble:

#include <improbable/standard_library.h>
#include <improbable/worker.h>
#include <example.h>

using namespace improbable;


Using the worker::Connection, a worker can request SpatialOS to:

For all of these methods:

  • They return an worker::RequestId request ID. This can be used to match a request with its response. The type parameter C depends on the type of request being sent.
  • The request can fail, so check the StatusCode in the Op in the callback, and retry as necessary. The caller will always get a response callback, but it might be due to a timeout.

Entity ID Reservations

It is possible to reserve entity IDs before creating entities.

Note: Entity ID reservations can expire at an arbitrary time in the future, without warning. Therefore, it is not guaranteed that the reserved entity ID will be still be valid by the time you create an entity with it. For this reason, we recommend creating entities without reserving IDs, and instead using the automatically assigned entity ID returned in CreateEntityResponseOp.

Reserve a range of entity IDs using the Connection method SendReserveEntityIdsRequest. SendReserveEntityIdsRequest takes an optional timeout.

You’ll receive the response via the Dispatcher callback OnReserveEntityIdsResponse. If the operation succeeds, the response contains an entity ID, which is the first in a contiguous range guaranteed to be unused in the current deployment, and the corresponding number of entity IDs in the reserved range.

If the operation fails, the entity ID is not set, and the number of entity IDs in the reserved range is 0.

The Op in the callback is ReserveEntityIdsResponseOp.

Create an entity

Create an entity using the Connection method SendCreateEntityRequest, which takes:

You’ll receive the response via the Dispatcher callback OnCreateEntityResponse. If the operation succeeds, the response contains the ID of the newly created entity.

Delete an entity

Delete an entity using the Connection method SendDeleteEntityRequest, which takes:

  • an entity ID
  • an optional timeout

You’ll receive the response via the Dispatcher callback OnDeleteEntityResponse. The response contains no additional data.



worker::RequestId<worker::CreateEntityRequest> entity_creation_request_id;
worker::RequestId<worker::DeleteEntityRequest> entity_deletion_request_id;

constexpr uint32_t kTimeoutMillis = 500;

void CreateDeleteEntity(worker::Connection& connection, worker::Dispatcher& dispatcher) {
  // Reserve an entity ID.
  worker::RequestId<worker::ReserveEntityIdsRequest> entity_id_reservation_request_id =
      connection.SendReserveEntityIdsRequest(1, kTimeoutMillis);

  dispatcher.OnReserveEntityIdsResponse([entity_id_reservation_request_id, &connection](
                                            const worker::ReserveEntityIdsResponseOp& op) {
    if (op.RequestId == entity_id_reservation_request_id &&
        op.StatusCode == worker::StatusCode::kSuccess) {
      // ID reservation was successful - create an entity with the reserved ID.
      worker::Entity entity;
      entity.Add<improbable::Position>({{1, 2, 3}});
      auto result = connection.SendCreateEntityRequest(entity, op.FirstEntityId, kTimeoutMillis);
      // Check no errors occurred.
      if (result) {
        entity_creation_request_id = *result;
      } else {
        connection.SendLogMessage(worker::LogLevel::kError, "CreateDeleteEntity",

  // When the creation succeeds, delete the entity.
  dispatcher.OnCreateEntityResponse([&connection](const worker::CreateEntityResponseOp& op) {
    if (op.RequestId == entity_creation_request_id &&
        op.StatusCode == worker::StatusCode::kSuccess) {
      entity_deletion_request_id = connection.SendDeleteEntityRequest(*op.EntityId, kTimeoutMillis);

  // When the deletion succeeds, we're done.
  dispatcher.OnDeleteEntityResponse([](const worker::DeleteEntityResponseOp& op) {
    if (op.RequestId == entity_deletion_request_id &&
        op.StatusCode == worker::StatusCode::kSuccess) {
      // Test successful!

Entity ACLs

Entity ACLs are exposed to the worker as a component, and can be manipulated as any other component. It’s worth reading Handing over authority and Worker attributes and worker requirements for more information.

ACLs are set at entity creation time, but can be modified dynamically at runtime by the worker that has write access authority over the EntityAcl component.

Example of creating an ACL

This example adds an EntityAcl to an Entity given a CommandRequestOp to make a specific worker (as opposed to, potentially, a set of workers) qualify for write access authority over a component. Specifically:

  • The entity will be visible to workers that have the “client” or “physics” worker attribute (in other words, workers that are in the “client” or “physics” layer).
  • Any worker with “physics” as its attribute can have write access authority over the entity’s Position and EntityAcl components.
  • The worker which issued the CommandRequestOp is the only worker that can have write access authority over the PlayerControls component.


template <typename C>
void AddComponentDelegations(const worker::CommandRequestOp<C>& op, worker::Entity& entity) {
  static const std::string physics = "physics";
  static const std::string client = "client";

  // since attribute set includes the caller's unique attribute.
  improbable::WorkerAttributeSet callerWorkerAttributeSet{{"workerId:" + op.CallerWorkerId}};
  improbable::WorkerRequirementSet callerWorkerRequirementSet{

  worker::List<std::string> physicsWorkerAttributeSet{physics};

  improbable::WorkerRequirementSet physicsWorkerRequirementSet{

  improbable::WorkerRequirementSet clientOrPhysicsRequirementSet{

  // the caller worker.
  worker::Map<worker::ComponentId, improbable::WorkerRequirementSet> componentAcl{
      {improbable::Position::ComponentId, physicsWorkerRequirementSet},
      {EntityAcl::ComponentId, physicsWorkerRequirementSet},
      {example::PlayerControls::ComponentId, callerWorkerRequirementSet}};

      EntityAcl::Data{/* read */ clientOrPhysicsRequirementSet, /* write */ componentAcl});

Example of changing write access authority

The worker that has write access authority over the EntityAcl component can decide to give the write access authority over position (or any other component) to a different worker.

In order to do this, you need to modify EntityAcl.Data, mapping Position.ComponentId to callerWorkerRequirementSet (created above). This change can be made using the method below:

// Take a copy of the EntityAclData argument, so that this method doesn't modify the original one.
DelegateComponent(improbable::EntityAclData acl, worker::ComponentId componentId,
                  const improbable::WorkerRequirementSet& requirementSet) {
  // assuming the componentAcl option is not empty.
  acl.component_write_acl().insert({{componentId, requirementSet}});
  return acl;

For these changes to take effect, the worker that has write access authority over the EntityAcl component needs send the changes through a component update.

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums