# Photon Bolt

This guide will help you create a headless server on Edgegap for a Unity project using Photon Bolt as its networking solution.

In this guide, we will be using a custom demonstration project as an example.

### Preparing the Unity project

### Clone the Unity project

The first step is to clone the Edgegap demo game project from git. You can do so using this command in your command prompt:

The command will create a folder containing the source Unity project, called `demo-game`.

Once the process is over, you can open Unity Hub and add the project by pressing the `Add` button in the Projects tab then finding the project's folder on your computer:

To open the project, you will need to have the correct version of Unity installed. In our case, we will use Unity `2020.3.3`. You can find it by visiting Unity's download archive: <https://unity3d.com/get-unity/download/archive>.

Once the installation is complete, you can now select the new Unity version through the drop-down menu adjacent to the project name in Unity Hub:

You can now open the Unity project to proceed to the next steps.

### Setting up the game

### Setting up Photon Bolt

#### Add Photon App ID and compile Bolt

For the game to communicate with Photon's services, you will need to add an App to your Photon dashboard. If you do not have an account with Photon yet, you can easily create one on their [website](https://id.photonengine.com/Account/).

Once signed in, you can create an app and give it a name. Every app has its unique `App ID`. You will need to copy and paste this ID in the `Bolt Settings` window within the Unity project:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-85755915f46bb51ed45784518d86ce278e998650%2Funity_photon_bolt_settings.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-fccf1cdf65056d42522cd4405f5a5dfbc5265106%2Funity_photon_bolt_app_id.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you enter the ID, you can close the Bolt Settings window. In the same `Bolt` menu as before, you will have to execute two actions: `Update Prefab Database` and `Compile Assembly`, respectively.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-93c9dc4b160db8a4b12142313da2c48bdb6a05cb%2Funity_photon_bolt_compile.png?alt=media" alt=""><figcaption></figcaption></figure>

At this point, you should be able to launch the game's `StartScene` scene without any errors or warnings in the debug console. However, you cannot start playing on a server just yet.

That concludes the generic changes needed for your Photon Bolt to work. These changes will work both for the clients and servers of your game.

### Preparing a headless server

For your app to work with containers efficiently, you will need to make a few changes to your game to create a "headless server" build. For most projects, this will only require a few straightforward steps.

#### Requirements for the Unity project

First, it is essential to note that Photon Bolt's headless server mode requires loading a scene holding a script called `HeadlessServerManager`.

The generic, unaltered script in question (taken from Bolt's documentation) looks like this:

```cs
using System;
using Bolt.Matchmaking;
using Bolt.Photon;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Bolt.Samples.HeadlessServer
{
    public class HeadlessServerManager : Bolt.GlobalEventListener
    {
        public string Map = "";
        public string GameType = "";
        public string RoomID = "";

        public override void BoltStartBegin(" alt=""><figcaption></figcaption></figure>
        {
            // Register any Protocol Token that are you using
            BoltNetwork.RegisterTokenClass<PhotonRoomProperties>();
        }

        public override void BoltStartDone()
        {
            if (BoltNetwork.IsServer)
            {
                // Create some room custom properties
                PhotonRoomProperties roomProperties = new PhotonRoomProperties();

                roomProperties.AddRoomProperty("t", GameType); // ex: game type
                roomProperties.AddRoomProperty("m", Map); // ex: map id

                roomProperties.IsOpen = true;
                roomProperties.IsVisible = true;

                // If RoomID was not set, create a random one
                if (RoomID.Length == 0)
                {
                    RoomID = Guid.NewGuid().ToString();
                }

                // Create the Photon Room
                BoltMatchmaking.CreateSession(
                    sessionID: RoomID,
                    token: roomProperties,
                    sceneToLoad: Map
                );
            }
        }

        // Use this for initialization
        void Start()
        {
            // Get custom arguments from command line
            Map = GetArg("-m", "-map") ?? Map;
            GameType = GetArg("-t", "-gameType") ?? GameType; // ex: get game type from command line
            RoomID = GetArg("-r", "-room") ?? RoomID;

            // Validate the requested Level
            var validMap = false;

            foreach (string value in BoltScenes.AllScenes)
            {
                if (SceneManager.GetActiveScene().name != value)
                {
                    if (Map == value)
                    {
                        validMap = true;
                        break;
                    }
                }
            }

            if (!validMap)
            {
                BoltLog.Error("Invalid configuration: please verify level name");
                Application.Quit();
            }

            // Start the Server
            BoltLauncher.StartServer();
            DontDestroyOnLoad(this);
        }

        /// <summary>
        /// Utility function to detect if the game instance was started in headless mode.
        /// </summary>
        /// <returns><c>true</c>, if headless mode was ised, <c>false</c> otherwise.</returns>
        public static bool IsHeadlessMode()
        {
            return Environment.CommandLine.Contains("-batchmode") && Environment.CommandLine.Contains("-nographics");
        }

        static string GetArg(params string[] names)
        {
            var args = Environment.GetCommandLineArgs();
            for (int i = 0; i < args.Length; i++)
            {
                foreach (var name in names)
                {
                    if (args[i] == name && args.Length > i + 1)
                    {
                        return args[i + 1];
                    }
                }
            }

            return null;
        }
    }
}
```

Usually, it will be held by an empty GameObject in an empty scene (which will only be used for headless server builds).

The script has been slightly altered for this demo to fit the project's structure, and it is currently placed in an empty GameObject in a scene located in `Assets/Scenes/BoltHeadlessServer`.

#### Adding headless server checks to your game

The above script contains a static utility method called `IsHeadlessMode`, to be used to check if the running game is headless or not. If you are updating an existing project, you might want to add this check to remove or add features for the headless server, like preventing the instantiation of a player character.

#### Build settings

In the `Buid Settings` of the project, add the `BoltHeadlessServer` scene at the very top, so it is the first to be loaded by the server.

Next, choose `Linux` as the target platform and check `Server Build`.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-119e3c54e779d1120313d9dbba22037fbe3670ca%2Funity_photon_bolt_build_settings.png?alt=media" alt=""><figcaption></figcaption></figure>

Now you can build your game under Linux with the above settings.

For **client builds**, do not forget to uncheck the `BoltHeadlessServer` scene and the `IsServer` option so your game functions properly.

For every step concerning the making of a headless server for Photon Bolt, more details are available in the [official documentation](https://doc.photonengine.com/en-us/bolt/current/demos-and-tutorials/headless-server).

### Create a container for the server

If you aren't familiar with Docker or containers, you can learn more by checking out [What is Docker?](https://docs.edgegap.com/docs/tools-and-integrations/container/docker)

To create a container from a Unity project, please refer to [Unity on Docker](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

### Add your app to Edgegap

You can now add your container to Edgegap so it can be hosted everywhere your players are.

If you don't know how to add an app to Edgegap, please refer to the [integration tutorial](https://docs.edgegap.com/learn/orchestration/application-and-versions).

However, you will need to make sure the name of your app is `demo-game` and that it has a version called `v1`. Else, you will need to update these values in the script located in `Assets/Scripts/StaginController.cs`.

Also, within the `Assets/Scripts/StaginController.cs` script, you will find a constant variable called `API_TOKEN`. You will need to create a token from your Edgegap account and paste it as a string into this variable. That token will be used to authorize the API requests sent to Edgegap.

Here is the script in question, with the token from Edgegap in blue and the app parameters in red:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-356f4d51a5c114024fea432e8fcd9b677d3c9e98%2Funity_photon_bolt_staging_controller.png?alt=media" alt=""><figcaption></figcaption></figure>

## Playing the demo game

Finally, you can start a demo game client build to play it. You can either build a client version of the game and launch or play it directly from the Unity interface. Just make sure to start it on the `StartScene` scene.

Once launched, an interface will show up. It contains a text field at the top, two large buttons and a label at the bottom left of the screen showing Bolt's current state.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-3ace5ac3f2d80112f7564e85fdcf8c65d844bf34%2Funity_photon_bolt_demo_game.png?alt=media" alt=""><figcaption></figcaption></figure>

You can copy your API Token from Edgegap into the text field at the top. Once your Token is pasted, you can now press the `Request Server` button to send an API call to Edgegap to start a server.

A few seconds later, you should see the label at the bottom of the interface showing the number of available servers. You will now press the `Connect to a random server` button to join a game and start playing.
