Improbable Icon

Code sample: How to add custom Scripting Defines to the SpatialOS GDK build process


#1

Hey everyone,

We’re currently evaluating the new SpatialOS Unity GDK, and I’m working on porting across a bunch of our existing technology. As I work toward getting the SpatialOS build process to play nice with our existing build implementation I discovered that SpatialOS currently doesn’t seem to support custom Scripting Define Symbols (or at least I couldn’t find any support for it).

To be clear, I’m talking about when you use ‘#if WHATEVER’ in your scripts. Usually you’d define ‘WHATEVER’ in Player Settings->Scripting Define Symbols, but they’re not correctly applied (as you might expect) in the current SpatialOS build process.

We use custom defines all over the place in our games to toggle support for certain platforms, distribution types, etc. - it’s super vital for us that they are supported on a per-platform basis.

I’ve integrated basic support for custom defines into the SpatialOS build process and thought I’d share this with the community. You need to edit three files in the core GDK package:

gdk-for-unity/workers/unity/Packages/com.improbable.gdk.buildsystem/Configuration/BuildEnvironmentConfig.cs - Add a new string to hold our new defines; your file should look something like this:

public SpatialBuildPlatforms BuildPlatforms = SpatialBuildPlatforms.Current;
public BuildOptions BuildOptions = 0;
//TODO: Start edit
public string ScriptingDefineSymbols = string.Empty;
//TODO: End edit

[NonSerialized] public bool ShowBuildOptions = false;
[NonSerialized] public bool ShowBuildPlatforms = false;

gdk-for-unity/workers/unity/Packages/com.improbable.gdk.buildsystem/WorkerBuilder.cs - 1. Change call to BuildWorkerForTarget() on line 115 to this

//TODO: Start edit
//Old: BuildWorkerForTarget(workerType, unityBuildTarget, buildOptions, targetEnvironment);
BuildWorkerForTarget(workerType, unityBuildTarget, buildOptions, targetEnvironment, environmentConfig.ScriptingDefineSymbols);
//TODO: End edit

Still in WorkerBuilder.cs - 2. Change method definition for BuildWorkerForTarget() on line 178 to this:

//TODO: Start edit
//Old: private static void BuildWorkerForTarget(string workerType, BuildTarget buildTarget, BuildOptions buildOptions, BuildEnvironment targetEnvironment)
private static void BuildWorkerForTarget(string workerType, BuildTarget buildTarget, BuildOptions buildOptions, BuildEnvironment targetEnvironment, string ScriptingDefineSymbols = null)
//TODO: End edit

Still in WorkerBuilder.cs - 3. Add this just after the call to GetScenePathsForWorker() on line 183

var spatialOSBuildConfiguration = SpatialOSBuildConfiguration.GetInstance();
var workerBuildData = new WorkerBuildData(workerType, buildTarget);
var scenes = spatialOSBuildConfiguration.GetScenePathsForWorker(workerType);

//TODO: Start edit
if (!string.IsNullOrEmpty(ScriptingDefineSymbols))
{
    string buildDefines = "CROSS_PLATFORM_INPUT;DISABLESTEAMWORKS;SPATIALOS_NETWORKING"; 
    var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
    PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, buildDefines);
}
//TODO: End edit

var buildPlayerOptions = new BuildPlayerOptions
{
    options = buildOptions,
    target = buildTarget,
    scenes = scenes,
    locationPathName = workerBuildData.BuildScratchDirectory
};

gdk-for-unity/workers/unity/Packages/com.improbable.gdk.buildsystem/Configuration/SpatialOSBuildConfigurationEditor.cs - Add this just after line 286:

if (EditorGUI.EndChangeCheck())
{
    EditorUtility.SetDirty(target);
    Undo.RecordObject(target, "Configure build options for worker");

    environmentConfiguration.ShowBuildOptions = showBuildOptions;
    environmentConfiguration.BuildOptions = newBuildOptions;
}

//TODO: Start edit
string currentDefines = environmentConfiguration.ScriptingDefineSymbols;
if (string.IsNullOrEmpty(currentDefines))
{
    //If no defines have been set then we'll use the ones from player settings
    var buildTarget = WorkerBuilder.GetUnityBuildTargets(environmentConfiguration.BuildPlatforms);
    var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget[0]);   //Just use the first platform to fill in the data; this can be customised per-platform in the configuration object
    currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);
}
environmentConfiguration.ScriptingDefineSymbols = EditorGUILayout.TextField("Build Defines", currentDefines);
//TODO: End edit

Once you’ve made those changes you should be able to switch back to your own project and have a look at the ScriptableObject in Assets/Config/BuildConfiguration. There’ll be a new field under Environments called “Build Defines”. Add some defines here (separated by semi-colons) to have these defines carry over to your platform builds.

I’ve got this up and running in a BlankGDKProject project, but your mileage in other project configurations may vary. Give me a shout if you have any problems.

Good luck!

Ben


#3

Hey Ben,

thanks so much for taking the time to work through this and reporting your findings with the community, we really appreciate it!

It might also be worth raising this in GitHub too and we can keep an eye on it as a potential general purpose feature request.

Thanks again for sharing! :slight_smile:

Best,
Nee