PUN Classic (v1)、PUN 2、Boltはメンテナンスモードとなっております。Unity2022についてはPUN 2でサポートいたしますが、新機能が追加されることはありません。お客様のPUNプロジェクトおよびBoltプロジェクトが停止することはなく、将来にわたってパフォーマンス性能が落ちることはありません。 今後の新しいプロジェクトについては、Photon FusionまたはQuantumへ切り替えていただくようよろしくお願いいたします。

ヘッドレスサーバー

往々にして、より少ないリソースを用いるサーバーを起動したいこともあるでしょう。このような場合には、ゲームのインスタンスをグラフィックインターフェースや人為的な反復をなくして実行する必要があります。これを実現するため、Unityには特殊な引数があり、これらの引数をゲームに渡すことで様々な挙動を実現することが可能です。

Boltはこの点を念頭に置いて構築されているため、ホスティングサービス上にあるゲームの複数のサーバーを実行でき、結果的にプレイヤーはゲームに参加することができます。 これを実現するスクリプトのサンプルを作成済みですので、この点についてはすぐに確認可能です。サンプルスクリプトはbolt_samples/HeadlessServerフォルダ内を確認してください。

ヘッドレスサーバーを起動し、実行するには以下の手順にしたがってください:

  1. デフォルトの設定を変更するには、エディターのHeadlessServer/Scenes/BoltHeadlessServerシーンを開きます。
    1. HeadlessServerHolderゲームオブジェクトをクリックします。
    2. Map (サーバーによってローディングされるシーン名)、Game Type (カスタムプロパティの例) とRoom ID (作成したルームの名前。空白のままの場合にはランダムな名前が作成されます)の値を更新します。
  2. BoltHeadlessServerシーンをインデックス0のシーンとして使用して、ゲームのバージョンを構築します。必ず Bolt Compiler (Assets/Bolt/Compile Assembly)を実行してください。
  3. Command Lineから実行ファイルを開いて実行します:
    • <path/to/your executable>.exe -batchmode -nographics -logFile [-map <other scene>] [-gameType <other game type>] [-room <other room name>];
    • 例: myGame.exe -batchmode -nographics -map Level1 これによって、シーンLevel1向けにサーバーが起動します。
  4. メインシーンでゲームを構築し、クライアントピアとして起動して、通常どおりルームに接続します。

これによって、実際のHeadlessServerManagerクラスのトランスクリプトを開くことができます。このトランスクリプトによってサーバーが起動されゲームが実行されます:

C#

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()
        {
            // 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;
        }
    }
}

もちろん、さらに引数チェックを作成してこのトランスクリプトをカスタマイズすれば、入るポートや異なるゲームモードなどを使用できます。

ゲームでカーソルのロックやプレイヤーのスポーン、音楽などの挙動を、ヘッドレスモードで実行中に無効にしたい場合もあるでしょう。 チュートリアルでは、PlayerCamera.cs内にScreen.lockCursor = trueがあります。ヘッドレスモードでない場合には、カーソルのロックだけを行うよう、スクリプトの編集が可能です。同様のことが、ServerCallbacks.cs内のPlayer.serverPlayer.InstantiateEntity()にも該当します。これを実現するため、ユーティリティ機能であるHeadlessServerManager.IsHeadlessMode()が追加されており、ゲームインスタンスがヘッドレスモードで開始されたかを確認できます。

Back to top