Get SpatialOS

Sites

Menu

Distributing with Steam

This page tells you how to distribute a Unity SpatialOS game via Steam, using the Steamworks SDK to authenticate a player.

Note: Steam integration is currently only supported for Unity clients.

Before you start

Note that, in order to integrate your game with Steam, you’ll need to acquire the means to publish a game on Steam, and pass the Steam Direct process.

1. Prerequisites for Steam integration

If you haven’t already:

  1. Register with Steamworks.
  2. Submit your game to Steam Direct and complete the process.

Once you’ve done that, you’ll need to get in touch with us:

  1. Find your Steam AppID.

    You’ll be given an AppID once you’ve completed the Steam Direct process.

  2. Generate a Steam Web API key by following these instructions.

  3. Get in touch: ask us to add your AppID and Web API key to your project.

    Important: Only send this information privately to Improbable staff.

    Don’t post your AppID or WebAPI key publicly.

2. Integrate Steamworks into your project

In this step, you’ll implement a simple version of Steam integration that lets you launch Unity clients using Steam.

To do this:

  1. In your SpatialOS project, install Steamworks.NET into your workers/unity project by following these instructions.
  2. In SteamManager.cs (in workers/unity/Assets/Scripts/Steamwork.NET), implement the following method:

    // Return steam access token as a hexadecimal string.
    public static string GetSteamTicketString()
    {
        var steamTicketData = new byte[1024];
        uint steamTicketLength;
        HAuthTicket hAuthTicket =  SteamUser.GetAuthSessionTicket(
                            steamTicketData,
                            1024,
                            out steamTicketLength);
        if (hAuthTicket == HAuthTicket.Invalid)
        {
            throw new System.Exception("Couldn't get valid steam ticket.");
        }
        return BitConverter.ToString(
                steamTicketData,
                0,
                (int)steamTicketLength
                ).Replace("-", "");
    }
    
  3. In Bootstrap.cs (normally located on a single GameEntry object located in both your UnityWorker and UnityClient scenes), implement the following method:

    private void StartGameWithSteamAuthentication()
    {
        // Set the auth to Steam and include the token from the Steam API.
        // "steam_deployment" should be a tag on the deployment Steam clients will use
        // Make sure we don't connect to "localhost" or a custom IP but use the locator instead
        Configuration.SpatialOsApplication.DeploymentTag = "steam_deployment";
        Configuration.Networking.SteamToken = SteamManager.GetSteamTicketString();
        Configuration.Networking.Ip = Defaults.LocatorAddress;
        SpatialOS.ApplyConfiguration(Configuration);
        SpatialOS.Connect(gameObject);
    }
    
  4. Create and manage a conditional callback to make sure that SteamUser.GetAuthSessionTicket() is only called after Steamworks has been initialised:

    1. In Steammanager.cs, add the following method delegate as a class member variable:

      public static Action StartGameCallback = delegate {};
      
    2. At the end of Awake(), after m_bInitialized = SteamAPI.Init() (ie after Steamworks has been initialised) call this method by adding the following line:

      StartGameCallback();
      
    3. In Bootstrap.cs, in Start(), replace the line SpatialOS.Connect(gameObject); with the following lines:

      if (!SteamManager.Initialized)
      {
          // Defer the StartGameWithSteamAuthentication() call to after Steamworks has been initialised
          SteamManager.StartGameCallback = StartGameWithSteamAuthentication;
      }
      else
      {
          // Safely call StartGameWithSteamAuthentication(), SteamManager.StartGameCallback() will now do nothing when called in Awake()
          StartGameWithSteamAuthentication();
      }
      

3. Set up command-line arguments

At this stage, you can start a game client from Steam. However, the current implementation has several side effects:

  • UnityClients can only be started from Steam and nowhere else.
  • UnityWorkers won’t connect.
  • The Launcher will no longer work.

To fix these problems, you can wrap the Steam logic in a check for a command-line argument: steamClient. This argument will be present when you launch a client from Steam. But it won’t be there when you launch a client from the Launcher, or when you run UnityWorkers.

To do this:

  1. Open Bootstrap.cs.
  2. In the Start() method, replace the above logic with the following lines:

    if (WorkerConfiguration.GetCommandLineValue(System.Environment.GetCommandLineArgs(), "steamClient", false))
    {
        // For Unity clients that were started from Steam
        if (!SteamManager.Initialized)
        {
            // Defer the StartGameWithSteamAuthentication()
            // call to after Steamworks has been initialised
            SteamManager.StartGameCallback = StartGameWithSteamAuthentication;
        }
        else
        {
            // Safely call StartGameWithSteamAuthentication() after Steamworks has been initialised.
            // SteamManager.StartGameCallback() will do nothing in Awake()
            StartGameWithSteamAuthentication();
        }
    }
    else
    {
        // For Unity Clients started from the Improbable Launcher and UnityWorkers
        SpatialOS.Connect(gameObject);
    }
    

4. Upload the game client

  1. Build your workers.
  2. Find the zipped version of the client executable called UnityClient@<your-target-platform>.zip in <spatialos-project-root>/build/assembly/worker, and unzip it.
  3. Upload the unzipped content to SteamPipe using the ContentBuilder.

    For details on how to do this, see the SteamPipe documentation.

  4. On the Steamworks App Admin page, navigate to Installation > General.

  5. Create a new Launch Option with the following settings:

    • Executable: Your client executable, for example UnityClient@Windows.exe or UnityClient@Mac.app.
    • Arguments: +appName <your SpatialOS project name> +assetDatabaseStrategy Streaming +steamClient true
      • +appName needs to be set to your SpatialOS project name, as specified in your spatialos.json.
      • +assetDatabaseStrategy Streaming specifies that entity prefabs loaded as part of your project assemblies will be downloaded to the game client at runtime.
      • +steamClient true means that clients launched from Steam will use Steam authentication, using the logic you implemented in step 3 above.

5. Tag deployments

Any deployments that use Steam clients must have the tag "steam_deployment".

To add this tag to all deployments of your project:

  1. Open Bootstrap.cs.
  2. In StartGameWithSteamAuthentication(), add the following line:

    EngineConfiguration.Instance.DeploymentTag = "steam_deployment";
    

Alternatively, you can:

  • Add the tag when launching a deployment by using:

    spatial cloud launch [...] --tags=steam_deployment
    
  • After you’ve launched a deployment, add the tag from the console:

    Tag the deployment with steam_deployment

What’s next

You’ve now successfully integrated your game with Steam!

To generate and manage access keys which will allow you to distribute your game, take a look at the SteamWorks packages documentation.

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums