Get SpatialOS

Sites

Menu

How to upgrade

This page explains how to upgrade a project from SpatialOS 10 to 11.0.2.

Background

SpatialOS projects are developed against a specific version of the SpatialOS SDK. The SDK version your project builds against is defined in the spatialos.json file at the root of the project, in the sdk_version field.

You must upgrade through major SDK versions in order. For example, to upgrade from 9.0.4 to 11.0.2, you must upgrade to 10.x.x, then to 11.0.2. To find upgrade guides for older versions, look at the documentation for that version of SpatialOS.

Note: This is a guide for upgrading to the new major version, SpatialOS 11. To upgrade to minor and patch versions, you don’t need to follow this guide. Just run spatial worker clean, then update the version number in spatialos.json.

Upgrading

1. Migrate snapshots to new format

If you have snapshots that you CANNOT regenerate from code (ie snapshots taken from a running deployment), you need to migrate them to the new format.

For instructions, see Migrating snapshots to SpatialOS 11. Note that you can do this after you’ve upgraded your project, as long as you still have access to your project’s code as it was on SpatialOS 10 (eg on a branch).

2. Upgrade your spatial CLI version

  1. Open a terminal in the root directory of your project.
  2. Run spatial update.

3. Upgrade your SpatialOS SDK version

Note: It’s very important you start by running spatial clean. Otherwise, intermediate files won’t be cleaned up properly and may cause issues with the new version.

  1. Open a terminal in the root directory of your project.
  2. Run spatial worker clean.
  3. Open the spatialos.json file at the root of your project.
  4. Replace the string WorkerSdkSchema with standard_library.
  5. Replace the value of sdk_version and the version value of all dependencies with 11.0.2.
  6. Replace all other instances of the version number in the file.

4. Remove the GSim

Before SpatialOS 11, the GSim (a legacy worker type) was required in order to run a deployment. This is no longer the case, and SpatialOS 11 fully removes support for the GSim and parts of the SDK that depended on it.

To remove all GSim code:

  1. Delete the workers/gsim directory and all of its contents.

    You’re unlikely to have any code in the directory. If you do, contact our support.

  2. In all schema files, remove the synchronized and queryable options.

    These keywords only affected the GSim, and so are no longer applicable.

  3. If your project depends on CoreLibrary, remove this dependency:

    Note: If you started your project from a tutorial, you may only have a schema dependency on CoreLibrary, but not actually be using it.

    1. Open the spatialos.json in the root of your project. If it doesn’t mention CoreLibrary, your project doesn’t depend on it, and you can skip to the next section.

      If it mentions CoreLibrary, remove the reference.

    2. Open the spatialos.<worker-type>.worker.json files of your Unity workers, and look at the generated_build_scripts_type field (which exists if you’re using generated build scripts). If it uses unity_corelibrary, change it to unity.

  4. If you’re not using it for anything else, you can uninstall SBT.

5. Update your worker configurations

Your worker configuration files are files which end in .worker.json, and exists within your worker directories. For example, if you are using the Unity SDK then you will most likely have workers/unity/spatialos.UnityClient.worker.json and workers/unity/spatialos.UnityWorker.worker.json.

For each of your worker configuration files,

  1. Replace the string IMPROBABLE_RECEPTIONIST_IP with IMPROBABLE_RECEPTIONIST_HOST.
  2. Remove the asset_context section, if the file contains it.
  3. In the bridge section, take a look at component_delivery. The component delivery settings control which components your workers get sent when they check out an entity.

    If you have checkout_all_initially set to true, you don’t need to do anything else.

    But by default (ie if it’s not mentioned), checkout_all_initially is false. In this case, you need to make sure that the Position and Metadata components are checked out initially - for example, using an override like this:

    "component_delivery": {
        "default": "RELIABLE_ORDERED",
        "override": {
            "improbable.Position": {
                "checkout_initially": true
            },
            "improbable.Metadata": {
                 "checkout_initially": true
            }
        }
    }
    

6. Port project code to use new standard schema library components

SpatialOS 11 has introduced new standard library components to replace older concepts. These components have been built for you, in standard_library.schema, so you don’t need to write any new schema in order to use them. These are: improbable.Position, improbable.Metadata and improbable.Persistence. These components are described in more detail on the Standard schema library page.

There are also some changes to some built-in types used in your .schema files: improbable.Coordinates, improbable.Vector3d and improbable.Vector3f.

6.1. Port schema

To port your schema to use the new components:

6.1.1. Position component

Use of the improbable.Position component replaces the need for EntityPosition fields (which all entities were required to have).

  1. Search through your .schema files for occurrences of the EntityPosition type.
  2. Delete those properties when you find them.
  3. Adjust property IDs to be sequential,

    For example, if you have a component which looks like this:

    component TransformComponent {
        id = 1002;
        EntityPosition position = 1;
        uint32 rotation = 2;
        event TeleportEvent teleport_event;
    }
    

    Then the entire EntityPosition property must be removed to achieve this result:

    component TransformComponent {
        id = 1002;
        uint32 rotation = 1;
        event TeleportEvent teleport_event;
    }
    

    Note that some property ids may need to be updated accordingly, just as you saw for the rotation property in the above example.

  4. If a component has no properties, events or commands other than one use of the EntityPosition type, delete the entire component.

    If the .schema file only contained that removed component, delete the entire file.

You don’t need to add the improbable.Position component that replaces this: it’s already in your project, as part of the standard schema library.

In step 6.2. below, you’ll make the corresponding required changes to UnitySDK C# code.

6.1.2. Coordinates standard type

The Coordinates type is now made available through the standard schema library. Update your existing uses of Coordinates:

  1. Search through your .schema files for uses of the Coordinates built-in type
  2. Add the following import to those .schema files: import "improbable/standard_library.schema";
  3. If those .schema files are not also in the improbable namespace (i.e. in the project’s schema/improbable/ directory), change all uses in those files of Coordinates to improbable.Coordinates.
6.1.3. Vector3 standard types

Vector3f and Vector3d types are now made available through the standard schema library. Update your existing uses of these types:

  1. Search through your .schema files for uses of the Vector3d and Vector3f built-in types.
  2. Add the following import to those .schema files: import "improbable/vector3.schema";.
  3. If those .schema files are not also in the improbable namespace (i.e. in the project’s schema/improbable/ directory), change all uses in those files of Vector3f to improbable.Vector3f, and all uses in those files of Vector3d to improbable.Vector3d.
6.1.4. Regenerate schema code

Because you’ve made changes to your schema, run spatial worker codegen.

6.2. Port Unity code

To port your Unity worker code:

6.2.1. Coordinates standard type
  1. In files using the Coordinates built-in type, update your imports to include using Improbable;.
  2. Coordinates no longer throws an exception when constructed with NaN parameters. If your code checks for this, you should change that check to use IsFinite().
  3. Due to a bug in the Coordinates class, setters using lowercase .x = to set the x value of a Coordinates object are not available. You can use the uppercase setter (.X =) instead, or create new Coordinates objects when you wish to change a dimensional value.
6.2.2. Vector3 standard type
  1. In files using the Vector3f or Vector3d built-in types, update your imports to remove using improbable.Math; and include using Improbable;.
  2. In files using ToNativeVector(), to convert from Unity Vector3 to either SpatialOS Vector3d or Vector3f, replace their uses with ToSpatialVector3d() and ToSpatialVector3f() respectively.
6.2.3. Entity creation/entity templates

Changes to entity construction syntax require you to make changes to all functions that create entities. This includes both entities added to snapshots, and entities created at runtime.

Some older syntax has been made defunct (the SnapshotEntity type) while other syntax (EntityBuilder) has been added to make inclusion of components and setting of the ACL more clear.

Below are concrete steps for upgrading your entity templates, but first read following example which illustrate how these changes look. The following code snippet may be similar to how your template looked in the previous version (i.e. 10.0) of SpatialOS, and the second snippet shows how it appears after the upgrade.

Before upgrading an entity template function:

public static SnapshotEntity CreateExampleEntityTemplate(Coordinates initialPosition, uint initialRotation, string clientId)
{
    var template = new SnapshotEntity { Prefab = "ExampleEntityPrefabName" };
    template.Add(new TransformComponent.Data(initialPosition, initialRotation));
    template.Add(new ClientAuthorityCheck.Data());

    var permissions = Acl.Build()
        .SetReadAccess(CommonRequirementSets.PhysicsOrVisual)
        .SetWriteAccess<TransformComponent>(CommonRequirementSets.PhysicsOnly)
        .SetWriteAccess<ClientAuthorityCheck>(CommonRequirementSets.SpecificClientOnly(clientId))

    template.SetAcl(permissions);

    return template;
}

After upgrading (using the steps listed below) your entity template function would now look as follows:

public static Entity CreateExampleEntityTemplate(Coordinates initialPosition, uint initialRotation, string clientId)
{
    var template = EntityBuilder.Begin()
        .AddPositionComponent(initialPosition.ToUnityVector(), CommonRequirementSets.PhysicsOnly)
        .AddMetadataComponent("ExampleEntityPrefabName")
        .SetPersistence(true)
        .SetReadAcl(CommonRequirementSets.PhysicsOrVisual)
        .AddComponent(new Rotation.Data(initialRotation), CommonRequirementSets.PhysicsOnly)
        .AddComponent(new ClientAuthorityCheck.Data(initialRotation), CommonRequirementSets.SpecificClientOnly(clientId))
        .Build();
    return template;
}

For more examples of upgraded entity template methods, have a look at the Pirates Tutorial script.

In the above example, the key changes are:

  • use of the new Metadata standard component to store the prefab name.
  • use of the new Position standard component (with the custom TransformComponent converted into Rotation component as it now only relates to rotation).
  • use of the new EntityBuilder syntax to construct the components and component access permissions all in one go.

The following steps will guide you through the process to locate your entity templates and convert them to the new syntax:

  1. Search through your C# code for places that used new Entity() or new SnapshotEntity() to create an entity template. These instances will be followed by the use of .Add() to include components and Acl.Build() as part of setting worker access permissions.
  2. Add the import using Improbable;
  3. Replace the use of = new Entity() or = new SnapshotEntity() with = EntityBuilder.Begin() to begin creating an entity template.
  4. Add the three required standard components which are new in this version, Position, Metadata and Persistence, so that your template construction now looks like: = EntityBuilder.Begin().AddPositionComponent().AddMetadataComponent().AddPersistenceComponent(). Note that the ordering of these functions is important.
  5. For .AddPositionComponent(), pass it two parameters: the first should be the position for the entity to be created at (instead of passing it to the component from which you removed the EntityPosition property), and the second should be WorkerRequirementSet you were previously using ACL of the component from which you removed the EntityPosition property.
  6. Whereas you may previously have been setting your EntityPosition property with a Coordinates type, you must make sure you pass the .AddPositionComponent() function a Unity vector3. You can convert from Coordinates to Unity’s vector3 using .ToUnityVector().
  7. For .AddMetadataComponent(), pass it a string containing the prefab name for this entity. For entity templates which formerly used SnapshotEntity the prefab name would have been specified directly in the template. For entity templates which formerly used the Entity type the prefab name may have been added to the template after construction, but should now be passed into the entity template function so that it can be used as a parameter for the .AddMetadataComponent() function.
  8. For AddPersistenceComponent(), pass it true unless you explicitly do not want this entity to appear in any snapshots.
  9. Chaining onto the end of the EntityBuilder syntax, add a read ACL using the function .SetReadAcl() and pass it as a parameter the same WorkerRequirementSet you were previously passing to the old .SetReadAccess function in the template’s ACL (e.g. CommonRequirementSets.PhysicsOrVisual).
  10. For each use of the .Add() function, previously using to add components to your entity template, change the syntax to .AddComponent() and pass this function two parameters: the first should be the component data object you were already constructing/using in the old syntax, and the second should be the WorkerRequirementSet you were formerly using for that component when using the .SetWriteAccess() on the entity’s ACL.
  11. Add a .Build() function to complete the chain.
  12. Add a final semi-colon to the end of your chain of functions.
  13. Remove any remaining Acl.Build(), .SetReadAccess(), .SetWriteAccess() and Acl.Build() syntax left in the template which is not part of the new EntityBuilder chain.

The new EntityBuilder syntax begins the definition of an entity, adds required components, sets worker read-access, adds yours custom components and sets their write-access permissions in-line. This syntax is able to entirely replace the code you were previously using to add components and set the ACL for a new entity.

6.2.4. Position standard component

As seen in the above upgrade steps for entity templates, there is now a mandatory Position component provided by SpatialOS which replaces the need to have a custom EntityPosition field in one of your components. By removing your old position property you will also need to change where it was previously being used.

For the below description we can imagine that you might have had a TransformComponent in your project’s schema which previously contained both a EntityPosition position and a float rotation, but now only contains the rotation, following the upgrade and use of the Position standard component.

Search through your scripts for uses of a Reader or Writer with component which no longer contains the EntityPosition field (e.g. [Require] TransformComponent.Reader transformReader;). These scripts are affected by the move to using the Position standard component. Some things you might want to change include:

  • Adding a [Require] statement for the Position component, injecting either a Reader or a Writer depending on what was being used with the existing component (e.g. if the script previously required a TransformComponent.Writer then add [Require] Position.Writer positionWriter;).
  • If the script only used the position field in the old component then you may be able to remove the old requirement line altogether (i.e. remove [Require] TransformComponent.Reader transformReader;).
  • Where the script previously read the position information from the old component, be aware that the new Position standard component’s property is coords and so reading from this component will look like: positionReader.Data.coords.
  • Where the script sent updated values for the entity position to SpatialOS using the old component you will need to update these to use the Position component and call .SetCoords on the update object. If you previously had position and rotation properties in the same component and updated them both with a single .Send() call then you will now need to use two separate calls for this purpose, one for the Position component and one for the component containing your rotation property.
6.2.5. Access EntityId within a callback payload from some Unity SDK functions

The callbacks for methods in Improbable.Unity.Core.IWorldCommander and Improbable.Unity.Core.ICommandSender have changed:

  1. Replace references to EntityId received from ReserveEntityId callback with [callbackPayload].ReservedEntityId.
  2. Replace references to EntityId received from CreateEntity callback with [callbackPayload].CreatedEntityId.
  3. Replace references to EntityId received from DeleteEntity callback with [callbackPayload].DeletedEntityId.

You can upgrade your uses of these by searching for ReserveEntityId, CreateEntity and DeleteEntity and updating any accessing of a returned EntityId so that it is now retrieved from within the callback payload.

For example:

Before upgrading the following command might previously have been used for spawning an entity for a new player:

SpatialOS.Commands.ReserveEntityId(playerSpawning)
  .OnFailure(_ =>
  {
    Debug.LogError("Failed to Reserve EntityId for Player. Retrying...");
    SpawnPlayerWithReservedId(clientWorkerId);
  })
  .OnSuccess(reservedEntityId =>
  {
      SpawnPlayer(clientWorkerId, reservedEntityId);
  });

After upgrading this command would be modified to access the reserved entity id stored within the callback payload of OnSuccess (named ‘result’ in this example):

SpatialOS.Commands.ReserveEntityId(playerSpawning)
  .OnFailure(_ =>
  {
    Debug.LogError("Failed to Reserve EntityId for Player. Retrying...");
    SpawnPlayerWithReservedId(clientWorkerId);
  })
  .OnSuccess(result =>
  {
    SpawnPlayer(clientWorkerId, result.ReservedEntityId);
  });
6.2.6. Universe API becomes LocalEntities API

The confusingly named Universe API, which allows access to information about all entities the worker has checked out, has been renamed:

  1. Search through your code for uses of SpatialOS.Universe.
  2. Replace these uses with LocalEntities.Instance.

For example,

Before upgrading if your script checked whether the worker knew about an entity with a particular id it might look like this:

SpatialOS.Universe.ContainsEntity(targetEntityId);

After upgrading this would look like this:

LocalEntities.Instance.ContainsEntity(targetEntityId);

6.3 Port Unreal code

To port your Unreal worker code:

  1. If you were using the type Coordinates in any of your schemas:

    • Required schema changes:

      Update the type to improbable.Coordinates wherever the type is referenced in components or when nested in other types, and update your schema to import improbable/standard_library.schema.

    • Required C++ code changes:

      Add the include directive to #include <improbable/standard_library.h> in your C++ code.

  2. If you were using Vector3f, or Vector3d in your schemas:

    • Required schema changes:

      Update their types to improbable.Vector3d and improbable.Vector3f respectively wherever the types are referenced in components or nested in other types, and update your schema to import improbable/vector3.schema.

    • Required C++ changes:

      Add the include directive to #include <improbable/vector3.h> in your C++ code.

  3. Update all code that creates entities to use the new standard library components:

    We recommend that you replace your old entity template creation with the new Entity builder API, but if you do not wish to migrate to that API you can still add the necessary components using the old API as shown below:

    This includes both entities added to snapshots, and entities created at runtime

    1. Remove your custom position component (which you deleted from your schema earlier), and replace it with improbable.Position.

      Use the include directive #include <improbable/standard_library.h> in your .cpp files.

    2. Replace any SnapshotEntity with an Entity. The only difference is that SnapshotEntity included a prefab property.

      On all of these entities, add the new standard component Improbable.Metadata, and use its entity_type property to store the prefab name.

      Use the include directive #include <improbable/standard_library.h> in your .cpp files.

    3. On all entities you want to persist in your snapshots (likely to be all of them), add the new standard component improbable.Persistence.

      Use the include directive #include <improbable/standard_library.h> in your cpp files.

    4. Modify the existing improbable.EntityAcl component to match the new, simplified structure.

  4. Remove all references to the macro IMPROBABLE_MATH_NO_PROTO as this is no longer required.

  5. Replace all instances in your project where you refer to an entity id as an int with the new entity id wrapper class FEntityId, which requires you to include EntityId.h.

  6. Remove the asset_context section from your worker configuration files (e.g. spatialos.UnrealClient.worker.json and spatialos.UnrealWorker.worker.json).

  7. Replace all the IMPROBABLE_RECEPTIONIST_IP variables with IMPROBABLE_RECEPTIONIST_HOST in your worker configuration files (e.g. spatialos.UnrealClient.worker.json and spatialos.UnrealWorker.worker.json).

  8. Replace the name of the WorkerSdkSchema with standard_library under the dependencies section in your projects spatialos.json file.

  9. Replace all your calls to the function ProcessEvents on your SpatialOS object with calls to the new member function ProcessOps.

  10. Migrate your code to use the new entity pipeline.

    1. Remove all references to the class FEntitySpawner.
    2. Add the following snippet to the section where you call ProcessOps:
      SpatialOSInstance->GetEntityPipeline()->ProcessOps(SpatialOSInstance->GetView(), SpatialOSInstance->GetConnection(), GetWorld());
    
    1. Create a new EntityRegistryto a persistent class such as your GameInstance.
    2. Replace the section where you previously registered your entity blueprint paths with the following code:
      auto EntitySpawnerBlock = NewObject<USimpleEntitySpawnerBlock>();
      EntitySpawnerBlock->Init(EntityRegistry);
      SpatialOSInstance->GetEntityPipeline()->AddBlock(EntitySpawnerBlock);
    
    
      TArray<FString> BlueprintPaths;
      BlueprintPaths.Add(TEXT(ENTITY_BLUEPRINTS_FOLDER));
    
    
      EntityRegistry->RegisterEntityBlueprints(BlueprintPaths);
    

    The variable EntityRegistry in the snippet above should be the UEntityRegistry class you created in the previous step. The class USimpleEntitySpawnerBlock is provided as the default implementation of a custom block in the entity pipeline and can be used as a reference point if you intend to implement your own blocks.

6.4. Port other worker code

To port non-Unity SDK worker code, update all code that creates entities to use the new standard library components:

This includes both entities added to snapshots, and entities created at runtime.

  1. Remove the custom position component you deleted from your schema, and replace it with Improbable.Position.
  2. Modify the existing Improbable.EntityAcl component to match the new, simplified structure.

  3. On all entities you want to persist in your snapshots (likely to be all of them), add the new standard components Improbable.Position, Improbable.Metadata and Improbable.Persistence.

  4. Replace any SnapshotEntity with an Entity. If you still need the prefab property, replace it with the new standard component Improbable.Metadata, using the entity_type property to store the prefab name.

  5. Modify the existing Improbable.EntityAcl component to match the new, simplified structure.

7. Move to new .Connect() behaviour

Previous versions of SpatialOS had incorrect behaviour when connecting to SpatialOS failed; this has been fixed in 11.0.2.

Unity SDK:

  • Previously: when SpatialOS.Connect() failed, it incorrectly triggered the callbacks registered to both OnConnected and OnDisconnected.
  • Now: when SpatialOS.Connect() fails, it only triggers callbacks registered to the new OnFailedConnection.

Unreal SDK:

  • Previously: when USpatialOS::Connect() failed, it incorrectly triggered the callbacks registered to OnDisconnected.
  • Now: when USpatialOS::Connect() fails, it triggers callbacks registered to OnFailedConnection.

To upgrade:

  1. Check where you’re using OnConnected and OnDisconnected.
  2. In these places:
    1. Check that the things you want called when .Connect() succeeds are registered to OnConnected.
    2. Move any things you want called when .Connect() fails to OnFailedConnection.
    3. Check that the things registered to OnDisconnected are only what you want called on .Disconnect().

8. Address API breaking changes

Run spatial worker build. You should now see:

  • commands syntax warnings (don’t worry about these - you can upgrade them at another time)
  • compilation errors
  • package NotFound errors

Each of the compilation and package not found errors will be caused by a breaking change listed in the release notes.

If you’re using the Unity SDK, make sure to check the changes for the C# SDK, as some of these will affect you too.

  1. For each compilation error, find the relevant breaking change release note, and upgrade to the new API.
  2. Run spatial worker build again.
  3. Repeat steps 1 and 2 until your project compiles!

If your project doesn’t compile after you have finished the upgrade guide because of a missing dependency on CoreLibrary, contact support.

The end

You’ve now upgraded to SpatialOS 11.0.2. Great! Take a look at the release notes to learn more about what’s new in the latest SpatialOS version.

Let us know how the upgrade went on the SpatialOS forums!

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums