Get SpatialOS

Sites

Menu

Creating and deleting entities

To create or delete an entity, use a “world command”, sent using the SpatialOS utility class.

Note: In order to create or delete an entity, a worker must have permission to do so. For more information, see the Worker permissions page.

You should use SpatialOS.Commands, which requires a MonoBehaviour to have access to a component writer. This means a worker will only be allowed to send a command when it has write access to a component. Requiring a component writer here helps prevent commands accidentally being sent twice: SpatialOS will only let the worker with write access to the component send the command.

Note: In rare circumstances, a worker won’t have access to any component writers (for example, when a client worker is bootstrapping itself). In this case, you can use SpatialOS.WorkerCommands instead: it has an identical interface to SpatialOS.Commands, but doesn’t require a component writer. Doing it this way can lead to problems (commands are more likely to be accidentally sent twice), so only use it when absolutely necessary.

On this page:

Creating an entity

To create an entity, you create the entity’s template, then send the CreateEntity command.

An entity template is an object that specifies all the components that the entity has.

To create an entity, you need:

  • an entity template
  • a component writer (for the reasons described above)
  • the statement using SpatialOS.Commands; and using Improbable;

Note that if you spawn a GameObject yourself, it won’t be associated with an entity, and won’t be synchronized to any other Unity workers: it’ll only exist locally.

1. Create an entity template

Entity templates must have at least these three components:

  • a Position component, which specifies the location of your entity
  • a Metadata component, which has the field entity_type that is used to specify the entity’s prefab name (note that prefab names cannot have spaces)
  • a EntityAcl component, which controls the read and write access that workers have to the entity and its components

Most entities also should have a Persistence component, which means that you want it to persist in snapshots. The EntityBuilder pattern requires you to specify whether or not you want your entity to be persistent.

For more information about these standard components, see the standard schema library) page. For more conceptual information about ACLs, see the Entity ACL page. For information about designing an entity and its components, see the Designing and defining entities page. For information about the required components, see the Standard schema library page.

To create an entity template, make use of the EntityBuilder (in Improbable.Unity.Entity), which defines a pattern to create an entity template. To use the EntityBuilder, you add the required components in order, then add your own components. This order is Position, Metadata, whether or not you want persistence, followed by read ACLs, and then your own components. As you add each component, you also specify which worker can write to the component. For example:

var myEntityTemplate = EntityBuilder.Begin()
	.AddPositionComponent(Vector3.zero, CommonRequirementSets.PhysicsOnly)
	.AddMetadataComponent("MyPrefab")
	.SetPersistence(true)
	.SetReadAcl(CommonRequirementSets.PhysicsOrVisual)
	.Build();

To add additional components, add them after .SetReadAcl() and before .Build():

var myEntityTemplate = EntityBuilder.Begin()
	.AddPositionComponent(Vector3.zero, CommonRequirementSets.PhysicsOnly)
	.AddMetadataComponent("MyPrefab")
	.SetPersistence(true)
	.SetReadAcl(CommonRequirementSets.PhysicsOrVisual)
	.AddComponent<MyComponent>(new MyComponent.Data(), CommonRequirementSets.PhysicsOnly)
	.Build();

If you wish to construct entity templates without using EntityBuilder, you can use the underlying C# API.

Troubleshooting

If you try to add components out of order, or call .Build() before adding the read ACLs, you will see an error like this:

Type `Improbable.Unity.Entity.EntityBuilder.IPersistenceSetter` does not contain a definition for `SetReadAcl` and no extension method `SetReadAcl` of type `Improbable.Unity.Entity.EntityBuilder.IPersistenceSetter` could be found. Are you missing an assembly reference?

To fix this, make sure that you’re calling all the methods in the correct order. For example, in the above case the solution is to call .SetPersistence() after .AddMetadataComponent() and before .SetReadAcl(), so that they appear in the order as shown in the example above.

2. Create an entity

You can create an entity in two ways, both using methods on SpatialOS.Commands:

  • Create an entity
  • Reserve an entity ID, then create the entity

The methods all have a ICommandResponseHandler return type, require an IComponentWriter object for access control, and an optional trailing TimeSpan? timeout argument.

You can call these methods from any MonoBehaviour that has a component writer and the using statement using SpatialOS.Commands.

2a. Create an entity (the easy way)

This is the simplest way to create an entity. It first reserves an entity ID, and then creates an entity with that ID.

Method definition:

ICommandResponseHandler<EntityId> CreateEntity(IComponentWriter writer, Entity template, TimeSpan? timeout)

where:

  • writer is any component writer
  • template is the entity template that specifies which components the entity will have
  • timeout is a length of time. If there’s no response after this length of time, the command is considered to have failed, and any callback is called with a failure message. This argument is optional.

For example:

SpatialOS.Commands.CreateEntity(exampleComponentWriter, myEntityTemplate)
    .OnSuccess(entityId => Debug.Log("Created entity with ID: " + entityId))
    .OnFailure(errorDetails => Debug.Log("Failed to create entity with error: " + errorDetails.ErrorMessage));

This example passes in a callback that checks whether the creation was successful or not, but you don’t need to have a callback if you don’t want one.

2b. Creating an entity (the complicated way)

Alternatively, you can manually reserve an entity ID, then create the entity with that ID. This method provides fewer options for error detection and recovery than the two-step approach.

ReserveEntityId reserves an entity ID that you can use later to create an entity with that ID.

Method definition:

ICommandResponseHandler<EntityId> ReserveEntityId(IComponentWriter writer, TimeSpan? timeout)

where:

  • writer is any component writer
  • timeout is a length of time. If there’s no response after this length of time, the command is considered to have failed, and any callback is called with a failure message. This argument is optional.

This version of CreateEntity creates an entity with a previously-reserved entity ID. The ID must have been reserved by a previous call of ReserveEntityId. You cannot specify an arbitrary ID.

Method definition:

ICommandResponseHandler<EntityId> CreateEntity(IComponentWriter writer, EntityId reservedEntityId, 
Entity template, TimeSpan? timeout)`

where:

  • writer is any component writer
  • reservedEntityId is the ID issued by ReserveEntityId
  • template is the entity template that specifies which components the entity will have
  • timeout is a length of time. If there’s no response after this length of time, the command is considered to have failed, and any callback is called with a failure message. This argument is optional.

Full example of creating an entity

This example uses the simpler method shown in step 2a above.

var myEntityTemplate = EntityBuilder.Begin()
    .AddPositionComponent(Vector3.zero, CommonRequirementSets.PhysicsOnly)
    .AddMetadataComponent("MyPrefab")
    .SetPersistence(true)
    .SetReadAcl(CommonRequirementSets.PhysicsOrVisual)
    .AddComponent<MyComponent>(new MyComponent.Data(), CommonRequirementSets.PhysicsOnly)
    .Build();

// Create the entity based on myEntityTemplate
SpatialOS.Commands.CreateEntity(exampleComponentWriter, myEntityTemplate)
    .OnSuccess(entityId => Debug.Log("Created entity with ID: " + entityId))
    .OnFailure(errorDetails => Debug.Log("Failed to create entity with error: " + errorDetails.ErrorMessage));

Deleting an entity

To delete an entity, you’ll need:

  • a component writer
  • the using statement using SpatialOS.Commands
  • the entity’s EntityID

You can get the EntityID by:

  • querying the world
  • if it’s the current entity/gameobject, using gameObject.EntityId
  • using public static Entity GetLocalEntity(EntityId entityId) on the SpatialOS utility class
  • to get all the entities on the worker, using SpatialOS.Dispatcher public Map<EntityId, Entity> Entities.

DeleteEntity deletes the entity with the given entity ID. Method definition:

ICommandResponseHandler<EntityId> DeleteEntity(IComponentWriter writer, EntityId entityId, TimeSpan? timeout)

where:

  • writer is any component writer
  • entityId is the ID of the entity to be deleted
  • timeout is a length of time. If there’s no response after this length of time, the command is considered to have failed, and any callback is called with a failure message. This argument is optional.

For example:

SpatialOS.Commands.DeleteEntity(exampleComponentWriter, gameObject.EntityId())
    .OnSuccess(entityId => Debug.Log("Deleted entity: " + entityId))
    .OnFailure(errorDetails => Debug.Log("Failed to delete entity with error: " + errorDetails.ErrorMessage));

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums