Improbable Icon

9.0 Feature Deep Dive: New Launch Configurations

coming-soon

#1

Overview

Launching deployments is a fundamental part of your SpatialOS workflow. It’s never been easy. I mean, have you ever actually tried to understand one of those .pb.json files in order to customise it? :troll:

Let’s have a look an old launch configuration from the Pirates tutorial (deploy-large.pb.json) and compare it to a new one:

Worker Flags

First we have a worker_flagz section:

"worker_flagz": [
      {
        "worker_type": "gsim",
        "flagz": [
          {
            "name": "pirates_max_ships",
            "value": "2000"
          }
        ]
      }
  ],

This section has been renamed subtly to the slightly more sensible flags and moved to a nested field in 9.0. This allows the worker part of your launch configuration to be a lot richer in 9.0. Let’s take a look at the equivalent section in the new format:

"workers": [
    {
      "worker_type": "gsim",
      "flags": [
        {
          "name": "pirates_max_ships",
          "value": "2000"
        }
      ],
    }
    ...

New Feature: In 8.x, it was only possible to define custom flags for the GSim. In 9.0, you can define flags for any worker type!

SpatialOS Flags

Next, we have the SpatialOS flags section. These used to be used to configure SpatialOS behaviour (e.g., the load balancing strategy):

"flagz": [
  {
    "name": "bridge_enable_ping",
    "value": "true"
  },
  {
    "name": "engine_automatic_scaling_enabled",
    "value": "true"
  },
  {
    "name": "engine_start_timeout_seconds",
    "value": "9.999999e+06"
  },
  {
    "name": "entity_activator",
    "value": "improbable.corelib.entity.CoreLibraryEntityActivator"
  },
  {
    "name": "game_chunk_size",
    "value": "50"
  },
  {
    "name": "game_world_edge_length",
    "value": "12000"
  },
  {
    "name": "player_engine_type",
    "value": "UnityClient"
  },
  {
    "name": "scaling_advisor_num_entities_per_worker",
    "value": "100"
  },
  {
    "name": "spatial_index_grid_size",
    "value": "100"
  }
],

Woah! That’s a lot of flags. Unfortunately many of these used to be required in order to get things working properly. It was pretty unclear what some of them did. Others had highly unexpected behaviour.

Good news! In 9.0, all of these flags go away. They have been replaced with understandable, documented and structured JSON :slight_smile:

For comparison, let’s take a look at my new Pirates launch configuration:

"template": "small",
"world": {
    "chunk_edge_length_meters": 50,
    "snapshots": {
      "snapshot_write_period_seconds": 30
    },
    "dimensions": {
      "x_meters": 500,
      "z_meters": 500
    },
}

There are some new things here, so let’s walk through them:

  • template - this defines how many resources I want SpatialOS to initially allocate when spooling up the deployment. If I’m running locally, this will just be a single process.
  • world - everything in this block statically defines the characteristics of the world. It will be extended in the future, but right now you can configure chunk size, snapshot backup frequency, and (critically) the world dimensions! No more manual allocation of GSims and setting of flags with crazy behaviour.

Note: In order to maintain some legacy flows, there is are optional legacy_flags and legacy_javaparams blocks that can be added in order to configure old-style SpatialOS flags. Eventually, these will be removed!

Load Balancing Configuration

We’ve made load balancing configuration a lot simpler in 9.0. It now lives alongside the worker flags block as just another part of how you configure your workers. Let’s take a look at my example from Pirates:

{
      "worker_type": "UnityFSim",
      "load_balancing": {
        "dynamic_loadbalancer": {
          "worker_scaler_config": {
            "constant_config": {
              "num_workers": 1
            }
          },
          "worker_placer_config": {
            "random_params": {}
          },
          "loadbalancer_config": {
            "min_range_meters": 500.0,
            "max_range_meters": 5000.0,
            "speed_meters_per_second": 100.0,
            "expansion_time_millis": 60000
          }
        }
      }

It’s a little verbose at the moment, but there are quite a few possibilities! All of it is documented in case you want to tinker. In future versions, we’ll be making this simpler still.

Javaparams

Next up, this stuff:

"javaparams": [
  {
    "name": "-DCLOUD_LAUNCH_CONFIG",
    "value": "AutomaticEngineStartupLaunchConfig"
  },
  {
    "name": "-DIGNORE_FLAGS_IN_GAME_PROPERTIES_FILE",
    "value": "true"
  },
  {
    "name": "-J-Xms1G"
  },
  {
    "name": "-J-Xmx12G"
  }
],

This used to configure some GSim behaviour. In 9.0, you’ll be doing almost everything from workers, so this can all be removed. For those of you using the GSim extensively, you can make use of the legacy_javaparams block (it has identical behaviour and format) whilst you finish your migration to the worker paradigm.

Nodes

Finally, we have the nodes block. What on earth is this thing?

"nodes": [{
    "name": "master",
    "size": "single",
    "modules": [{
      "name": "ReceptionistModule",
      "params": []
    }, {
      "name": "DevWorldRestApiModule",
      "params": []
    }, {
      "name": "BridgeOracleModule",
      "params": []
    }, {
      "name": "BridgeModuleOracleModule",
      "params": []
    }, {
      "name": "AssetDatabaseModule",
      "params": []
    }, {
      "name": "EngineStartupModuleOracleModule",
      "params": []
    }, {
      "name": "InspectionRestModule",
      "params": []
    }, {
      "name": "PersistenceModule",
      "params": []
    }, {
      "name": "RouterModule",
      "params": []
    }, {
      "name": "WorldAppSupervisorModule",
      "params": []
    }, {
      "name": "WorldAppOracleModule",
      "params": []
    }, {
      "name": "ProfilingModule",
      "params": []
    }]
  }, {
    "name": "gsim_bridge",
    "size": "octa",
    "modules": [{
      "name": "GSimBridgeModule",
      "params": [{
          "name": "gSimNumber",
          "value": "1"
        }, {
          "name": "nee",
          "value": "100"
        }, {
          "name": "nen",
          "value": "100"
        }, {
          "name": "swe",
          "value": "-100"
        }, {
          "name": "swn",
          "value": "-100"
        }]
      },
      {
        "name": "RouterModule",
        "params": []
      }]
    },{
    "name": "fsim",
    "size": "quad",
    "modules": [{
      "name": "EngineStartupModule",
      "params": []
      },
      {
        "name": "AssetDatabaseModule",
        "params": [
        ]
      }]
    },{
      "name": "fsim2",
      "size": "quad",
      "modules": [{
        "name": "EngineStartupModule",
        "params": []
        },
        {
          "name": "AssetDatabaseModule",
          "params": [
          ]
        }]
    }]
  }

It’s massive. It’s scary.

It’s all gone and it’s never coming back.

You remember the template section from above? That’s what replaces this section. Now, you just write "template": "large" and we figure out the rest!

Worker Permissions

This is a new feature in 9.0. With workers now being able to call system commands (e.g,. create an entity, delete an entity), it is important that you have control over exactly which worker types have access to each call - you don’t want malicious players figuring out that they can delete entities, for example!

Worker permissions are again defined alongside the flags and load_balancing blocks:

{
  "worker_type": "UnityFSim",
  "permissions": [
    {
      "all": {}
    }
  ]
}

In 9.0, all workers are allowed to do anything. In the next version of SpatialOS, we will introduce fine-grained access control to this block.

:bomb:

Well, that’s all folks!

Hope you enjoyed this post. Feel free to ask questions if you want to know more. :slight_smile:


Introducing the "coming-soon" tag for version 9.0 :)
#2

And for reference here is my final 9.0-style launch configuration in all of its compact glory! Old vs new.

{
  "template": "small",
  "world": {
    "chunk_edge_length_meters": 50,
    "snapshots": {
      "snapshot_write_period_seconds": 30
    },
    "dimensions": {
      "x_meters": 500,
      "z_meters": 500
    }
  },
  "workers": [
    {
      "worker_type": "gsim",
      "flags": [
        {
          "name": "pirates_max_ships",
          "value": "2000"
        }
      ],
    },
    {
      "worker_type": "UnityFSim",
      "load_balancing": {
        "dynamic_loadbalancer": {
          "worker_scaler_config": {
            "constant_config": {
              "num_workers": 1
            }
          },
          "worker_placer_config": {
            "random_params": {}
          },
          "loadbalancer_config": {
            "min_range_meters": 500.0,
            "max_range_meters": 5000.0,
            "speed_meters_per_second": 100.0,
            "expansion_time_millis": 60000
          }
        }
      },
      "permissions": [
        {
          "all": {}
        }
      ]
    },
    {
      "worker_type": "UnityClient",
      "permissions": [
        {
          "all": {}
        }
      ]
    }
  ]
}