# Photon Bolt

Ce guide vous aidera à créer un serveur sans interface (headless) sur Edgegap pour un projet Unity utilisant Photon Bolt comme solution réseau.

Dans ce guide, nous utiliserons un projet de démonstration personnalisé comme exemple.

### Préparation du projet Unity

### Cloner le projet Unity

La première étape consiste à cloner le projet de jeu démo d’Edgegap depuis git. Vous pouvez le faire avec cette commande dans votre invite de commande :

La commande créera un dossier contenant le projet source Unity, appelé `demo-game`.

Une fois le processus terminé, vous pouvez ouvrir Unity Hub et ajouter le projet en appuyant sur le bouton `Add` dans l’onglet Projects, puis en trouvant le dossier du projet sur votre ordinateur :

Pour ouvrir le projet, vous devez avoir la bonne version d’Unity installée. Dans notre cas, nous utiliserons Unity `2020.3.3`. Vous pouvez la trouver en visitant l’archive des téléchargements d’Unity : <https://unity3d.com/get-unity/download/archive>.

Une fois l’installation terminée, vous pouvez maintenant sélectionner la nouvelle version d’Unity via le menu déroulant adjacent au nom du projet dans Unity Hub :

Vous pouvez maintenant ouvrir le projet Unity pour passer aux étapes suivantes.

### Configuration du jeu

### Configuration de Photon Bolt

#### Ajouter l’App ID Photon et compiler Bolt

Pour que le jeu communique avec les services de Photon, vous devrez ajouter une application à votre tableau de bord Photon. Si vous n’avez pas encore de compte chez Photon, vous pouvez facilement en créer un sur leur [site web](https://id.photonengine.com/Account/).

Une fois connecté, vous pouvez créer une application et lui donner un nom. Chaque application possède son `App ID`unique. Vous devrez copier et coller cet ID dans la fenêtre `Bolt Settings` au sein du projet Unity :

<figure><img src="https://3008966946-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://3008966946-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>

Une fois l’ID saisi, vous pouvez fermer la fenêtre Bolt Settings. Dans le même menu `Bolt` qu’auparavant, vous devrez exécuter deux actions : `Update Prefab Database` et `Compile Assembly`, respectivement.

<figure><img src="https://3008966946-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>

À ce stade, vous devriez pouvoir lancer la scène `StartScene` du jeu sans aucune erreur ni avertissement dans la console de débogage. Cependant, vous ne pouvez pas encore commencer à jouer sur un serveur.

Cela conclut les modifications génériques nécessaires au fonctionnement de votre Photon Bolt. Ces changements fonctionneront à la fois pour les clients et les serveurs de votre jeu.

### Préparation d’un serveur sans interface (headless)

Pour que votre application fonctionne efficacement avec des conteneurs, vous devrez apporter quelques changements à votre jeu pour créer une version « serveur headless ». Pour la plupart des projets, cela ne nécessitera que quelques étapes simples.

#### Exigences pour le projet Unity

Tout d’abord, il est essentiel de noter que le mode serveur headless de Photon Bolt nécessite le chargement d’une scène contenant un script appelé `HeadlessServerManager`.

Le script générique, non modifié, en question (tiré de la documentation de Bolt) ressemble à ceci :

```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();
            private void Awake()
        }

        /// <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;
        }
    }
}
```

Habituellement, il sera placé dans un GameObject vide d’une scène vide (qui ne sera utilisée que pour les builds de serveur headless).

Le script a été légèrement modifié pour cette démo afin de correspondre à la structure du projet et il est actuellement placé dans un GameObject vide dans une scène située dans `Assets/Scenes/BoltHeadlessServer`.

#### Ajout de contrôles du serveur headless à votre jeu

Le script ci-dessus contient une méthode utilitaire statique appelée `IsHeadlessMode`, à utiliser pour vérifier si le jeu en cours d’exécution est headless ou non. Si vous mettez à jour un projet existant, vous voudrez peut-être ajouter cette vérification pour retirer ou ajouter des fonctionnalités pour le serveur headless, comme empêcher l’instanciation d’un personnage joueur.

#### Paramètres de build

Dans l'onglet `Buid Settings` du projet, ajoutez la scène `BoltHeadlessServer` tout en haut, afin qu’elle soit la première chargée par le serveur.

Ensuite, choisissez `Linux` comme plateforme cible et cochez `Server Build`.

<figure><img src="https://3008966946-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>

Vous pouvez maintenant faire un build de votre jeu sous Linux avec les paramètres ci-dessus.

Pour les **builds client**, n’oubliez pas de décocher la scène `BoltHeadlessServer` et l’option `IsServer` afin que votre jeu fonctionne correctement.

Pour chaque étape concernant la création d’un serveur headless pour Photon Bolt, plus de détails sont disponibles dans la [documentation officielle](https://doc.photonengine.com/en-us/bolt/current/demos-and-tutorials/headless-server).

### Créer un conteneur pour le serveur

Si vous n’êtes pas familier avec Docker ou les conteneurs, vous pouvez en apprendre davantage en consultant [Qu’est-ce que Docker ?](https://docs.edgegap.com/docs.edgegap.com-fr/docs/tools-and-integrations/container/docker)

Pour créer un conteneur à partir d’un projet Unity, veuillez vous référer à [Unity sur Docker](https://docs.edgegap.com/docs.edgegap.com-fr/docs/sample-projects/unity-netcodes/broken-reference).

### Ajouter votre application à Edgegap

Vous pouvez maintenant ajouter votre conteneur à Edgegap afin qu’il puisse être hébergé partout où se trouvent vos joueurs.

Si vous ne savez pas comment ajouter une application à Edgegap, veuillez vous référer au [tutoriel d’intégration](https://docs.edgegap.com/docs.edgegap.com-fr/learn/orchestration/application-and-versions).

Cependant, vous devrez vous assurer que le nom de votre application est `demo-game` et qu’elle possède une version appelée `v1`. Sinon, vous devrez mettre à jour ces valeurs dans le script situé dans `Assets/Scripts/StaginController.cs`.

De plus, dans le `Assets/Scripts/StaginController.cs` script, vous trouverez une variable constante appelée `API_TOKEN`. Vous devrez créer un jeton depuis votre compte Edgegap et le coller sous forme de chaîne dans cette variable. Ce jeton sera utilisé pour autoriser les requêtes API envoyées à Edgegap.

Voici le script en question, avec le jeton d’Edgegap en bleu et les paramètres de l’application en rouge :

<figure><img src="https://3008966946-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>

## Jouer au jeu de démonstration

Enfin, vous pouvez lancer un build client du jeu démo pour y jouer. Vous pouvez soit créer une version client du jeu et la lancer, soit y jouer directement depuis l’interface d’Unity. Assurez-vous simplement de le démarrer sur la `StartScene` scène.

Une fois lancé, une interface apparaîtra. Elle contient un champ de texte en haut, deux gros boutons et une étiquette en bas à gauche de l’écran montrant l’état actuel de Bolt.

<figure><img src="https://3008966946-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>

Vous pouvez copier votre API Token depuis Edgegap dans le champ de texte en haut. Une fois votre Token collé, vous pouvez maintenant appuyer sur le bouton `Request Server` pour envoyer un appel API à Edgegap afin de démarrer un serveur.

Quelques secondes plus tard, vous devriez voir l’étiquette en bas de l’interface afficher le nombre de serveurs disponibles. Vous allez maintenant appuyer sur le bouton `Connect to a random server` pour rejoindre une partie et commencer à jouer.
