Worker build configuration
You can use the build scripts generated by SpatialOS, or write custom ones.
To get started quickly, and when you need something that just works, use the generated build scripts. But if you want to use a different build system, or need to integrate your SpatialOS project with an existing build pipeline, use custom build scripts.
You specify which you’re using (and how to build the worker) in the build
field of a
worker configuration file (worker.json
).
What the build scripts do
Regardless of the language or game engine used the ultimate goal of a worker build is to:
- Create a worker binary from the worker sources, schema-generated code, and worker dependencies (worker SDK, external libraries, etc.).
- Create a zip file containing the worker binary with a name matching the value for the
artifact_name
specified in the worker launch configuration for each platform the binary supports. By convention zip files for artifacts are named<WorkerType>@<Platform>.zip
. - Place the zip file in the
build/assembly/worker
directory relative to the root of your SpatialOS application.
The worker build configuration is designed to provide flexibility in the way sources are structured and built. Some canonical examples are the Unity, C# and Java generated build scripts which rely on different build systems for projects with a different structure.
Using generated build scripts
Generated build scripts contain the steps needed to build the worker for each platform (Windows, macOS and Linux),
and are executed when you run spatial worker build
.
To use generated build scripts, in your worker.json
files, set the build
> generated_build_scripts_type
field.
If you don’t set this field, your worker will not use generated build scripts.
For example, to build a UnityWorker using the generated build scripts:
{
"build": {
"generated_build_scripts_type": "unity",
"tasks_filename": "spatialos.unity.worker.build.json"
}
}
Supported worker types
The following worker types have generated build scripts:
unity
unreal
csharp
(using xbuild)csharp_msbuild
java
The script names are:
- UnityWorker:
spatialos.unity.worker.build.json
- UnityClient:
spatialos.unity.client.build.json
- UnrealWorker:
Game/Intermediate/Improbable/spatialos.unreal.worker.build.json
- UnrealClient:
Game/Intermediate/Improbable/spatialos.unreal.client.build.json
- C# (both versions):
spatialos.csharp.build.json
- Java:
spatialos.java.build.json
Notes
You can reduce build times by only building for a specific
platform (for example spatial worker build --target=Windows
, or macOS
, or Linux
), or for a specific target
(for example, using the Unity build scripts,
spatial worker build --target=development
for local deployments).
If you have two workers in the same directory, note that:
- If they both use generated build scripts, they must use the same value for
generated_build_scripts_type
. - If one worker uses generated build scripts and the other a custom one, the custom build script’s name
should be different from those of the
spatialos.*.build.json
files specified above. Otherwise, it might be overwritten.
Using custom build scripts
The worker configuration file (worker.json
)
build
field can specify either a set of tasks to be run (which must include Build
, Codegen
, and Clean
) in a
tasks
list field, or the name of a file containing this task
list.
For example, to define a set of tasks directly, use a build file with the following structure:
{
"build": {
"tasks": [
{
"name": "Clean",
"steps": [
{
"name": "Run make clean",
"command": "make",
"arguments": ["clean"]
}
...
]
}
...
]
}
}
Alternatively, you can define a set of tasks in a standalone file, named for example build.json
:
{
"tasks": [
{
"name": "Clean",
"steps": [
{
"name": "Run make clean",
"command": "make",
"arguments": ["clean"]
}
...
]
}
...
]
}
And add a reference to it in the main build file by using the tasks_filename
field:
{
"build": {
"tasks_filename": "build.json"
}
}
Tasks
Each task has a name
and a set of steps which are performed in the order they are defined when the task is run. A
task can also have an optional description
. In turn each step must contain a name
and a list of arguments
.
Optional fields are:
- A
command
that should be used to run this step. - A
working_path
that specifies the directory in which the step will be executed. Default is the worker’s directory. - An
env
map that allows you to specify environment variables that should be set with specific values for this step to run. The mapping is from string to string. - A
target
that specifies for which target this should be run (default: any target). It should be used together with the--target=<string>
option of thespatial worker build
command. Targets are arbitrary, case-insensitive, strings. - A
description
with a string telling what this step does.
If no command
is specified the arguments
are interpreted as a command (i.e worker_package
, process_schema
,
etc.) of spatial
and its parameters. The first argument can also be invoke
, invoke-task
whose effects are
described below.
Defining invoke-task
steps
invoke-task
causes another task in this configuration to be run. For example, the canonical Build
task invokes
Codegen
as its first step:
...
"steps": [
{
"name": "Codegen",
"arguments": ["invoke-task", "Codegen"]
},
]
...
Defining invoke
steps
invoke
provides a user-friendly, cross-platform way to invoke specific external tools, such as unity-csharp-
compiler
. For a complete list of the supported commands, run spatial invoke --help
.
Defining custom steps
When a command
is present the contents of arguments
is appended to it and the resulting string is executed. This is
done outside of a shell so you will need to use bash
as command
in order to access tools like cp
and mv
.
...
"steps": [
{
"name": "Clean",
"command": "make",
"arguments": ["clean"]
},
]
...
Common spatial
commands for build tasks
In cases not covered by the generated build scripts it’s up to you to decide what
works best for your project. Examples of tools commonly used for these steps are
MSBuild, CMake,
Bazel and Gradle. Some projects will even use multiple different build
systems for different workers. There are some spatial
commands which are often useful when writing
custom build scripts:
spatial schema generate
generates schema output for different target languages. For example:... { "name": "Codegen", "steps": [ { "name": "C++", "arguments": [ "process_schema", "generate", "--cachePath=.spatialos/schema_codegen_cache", "--output=generated", "--language=cpp" ] } ] } ...
spatial worker package unpack
installs worker packages. For example:
... { "name": "Build", "steps": [ { "name": "Codegen", "arguments": [ "invoke-task", "Codegen" ] }, { "name": "Install dependencies", "arguments": [ "worker_package", "unpack" ] } ... ] } ...
spatial file zip
is a portable zip archiver. It is usually used for a build target in a specific build system:<!-- Inside CsharpWorker.targets --> <Target Name="AfterBuild"> <PropertyGroup> <OutputArtifact>"../../build/assembly/worker/$(AssemblyName)"</OutputArtifact> <!-- Avoiding shell globbing on *nix --> <InputGlob>"*"</InputGlob> <WorkerPackageCommand>spatial</WorkerPackageCommand> </PropertyGroup> <Exec Command="$(WorkerPackageCommand) file zip --basePath="$(TargetDir.Replace('\', '/'))" --output=$(OutputArtifact) --worker_platform=$(WorkerPlatform) $(InputGlob)" /> </Target>
// Inside build.gradle task linux_assembly(type: Exec, dependsOn: 'jar') { executable 'spatial' args('file', 'zip', '--basePath=build/libs', '--output=../../build/assembly/worker/' + rootProject.name, '--worker_platform=linux', '--log_level=debug', rootProject.name + '.jar') }
The benefit of defining build tasks is being able to use the standard spatial codegen
, spatial build
, and spatial
clean
commands to perform common operations. However, you have the flexibility to keep your builds decoupled from the
spatial
CLI as long as the required targets are produced at the end. An example of this are the generated project and targets files for C# which allow MSBuild and Visual Studio to take full control of the builds.