SDKを使用してサーバーをセットアップする - AccelByte Multiplayer Servers (AMS) を使用した専用サーバー - (Unityモジュール)
注釈:本資料はAI技術を用いて翻訳されています。
AMS専用サーバーのフローを理解する
AccelByte Multiplayer Servers (AMS) によってゲームサーバーがどのように管理されるかのフローを確認してください。詳細については、AGS SDKを使用してAMSに専用サーバーを統合するガイドのAMS専用サーバーの状態について参照してください。
ラッパーを開く
これで、AccelByte Gaming Services (AGS) Game SDKが提供するAMS機能を使用する準備が整いました。
Byte Warsプロジェクトは、AGS Game SDKを使用する際にAMS関連の機能をキャッシュおよび処理するラッパーとして機能するMultiplayerDSAMSWrapperという名前のラッパークラスを使用します。
MultiplayerDSAMSWrapperクラスは、AccelByte Game SDKが提供するServerApiClient、ServerAMS、およびServerDSHubクラスを使用します。これらはAGSと連携して、サーバーの登録と登録解除、DS HubとAMSからの通知の受信、マルチプレイヤー機能の処理を可能にします。
スターターパックの内容
このチュートリアルに従うには、MultiplayerDSAMSWrapper_Starterというスターターラッパークラスを使用します。このラッパーは以下のファイルで定義されています:
- C#ファイル:
/Assets/Resources/Modules/Play/MultiplayerDSEssentials/Scripts/MultiplayerDSAMSWrapper_Starter.cs
MultiplayerDSAMSWrapper_Starterクラスには、以下のいくつかの事前定義されたコンポーネントがあります。
-
AGS SDKインターフェースを参照するためのヘルパー変数。これらの変数は、ラッパーが初期化されるときに割り当てられます。
private DedicatedServer ds;
private ServerAMS ams;
private ServerDSHub dsHub;
private void OnEnable()
{
ams = AccelByteSDK.GetServerRegistry().GetAMS(autoCreate: true, autoConnect: true);
if (ams == null)
{
BytewarsLogger.LogWarning("AMS interface is invalid. This interface only support packaged server using development build.");
return;
}
ds = AccelByteSDK.GetServerRegistry().GetApi().GetDedicatedServer();
if (ds == null)
{
BytewarsLogger.LogWarning("Dedicated Server interface is invalid. This interface only support packaged server using development build.");
return;
}
dsHub = AccelByteSDK.GetServerRegistry().GetApi().GetDsHub();
if (dsHub == null)
{
BytewarsLogger.LogWarning("DSHub interface is invalid. This interface only support packaged server using development build.");
return;
}
} -
AMS通知を受信したときに呼び出されるパブリックデリゲート。
public event Action OnAMSConnectionOpened = delegate { };
public event Action OnAMSConnectionClosed = delegate { };
public event Action OnAMSDrainSignalReceived = delegate { }; -
サーバーをシャットダウンするためのヘルパー変数と関数。
private readonly int ServerShutdownDelay = 10;
private void ShutdownServer()
{
BytewarsLogger.Log("Shutting down server.");
#if UNITY_EDITOR
UnityEditor.EditorApplication.ExitPlaymode();
#else
Application.Quit();
#endif
}
サーバーログイン
ゲームサーバーは、前のチュートリアル(IAMのセットアップ)で設定したAMSにアクセスするためにログインする必要があります。サーバーログインを実行するには、MultiplayerDSAMSWrapper_Starterクラスを開き、以下の関数を作成してリクエストを送信します。この関数は、後でサーバー登録時に使用します。
private void LoginServer(ResultCallback onComplete)
{
BytewarsLogger.Log("Start server login.");
ds?.LoginWithClientCredentials((result) =>
{
if (result.IsError)
{
BytewarsLogger.LogWarning($"Failed to login server. Error {result.Error.Code}: {result.Error.Message}");
}
else
{
BytewarsLogger.LogWarning("Success to login server.");
}
onComplete?.Invoke(result);
});
}
サーバーの登録
サーバーがゲームセッションを提供するためにAMSによって管理および認識されるように、AMSとDSHubに登録する必要があります。
-
MultiplayerDSAMSWrapper_Starterクラスを開き、以下の関数を作成してサーバー登録リクエストを送信します。private void RegisterServer()
{
ams.OnOpen -= RegisterServer;
string dsId = AccelByteSDK.GetServerConfig().DsId;
if (string.IsNullOrEmpty(dsId))
{
BytewarsLogger.LogWarning("Failed to register server. DSId is invalid.");
return;
}
BytewarsLogger.Log("Registering server.");
ams?.SendReadyMessage();
dsHub?.Connect(dsId);
} -
次に、AMSとDSHubの接続が確立されたときにリッスンするために、これらのコールバック関数を作成します。
private void OnAMSConnected()
{
BytewarsLogger.Log("Server connected to AMS.");
OnAMSConnectionOpened?.Invoke();
}private void OnDSHubConnected()
{
BytewarsLogger.Log($"Server connected to DSHub");
} -
サーバーがクレームされたときにもリッスンできます。ゲームキャッシュにゲームセッションIDを保存するだけで、これを処理する新しい関数を作成しましょう。このセッションIDは、ゲームセッションIDを必要とするAPIをサーバーから呼び出す場合に役立ちます。
private void OnServerClaimed(Result<ServerClaimedNotification> result)
{
if (result.IsError)
{
BytewarsLogger.LogWarning($"Failed to claim server. Error {result.Error.Code}: {result.Error.Message}");
return;
}
BytewarsLogger.Log($"Success to claim server. Session ID: {result.Value.sessionId}");
GameData.ServerSessionID = result.Value.sessionId;
} -
OnEnable()関数で、以下のコードを追加して、ラッパーが初期化されたときにサーバーログインリクエストを送信し、その後サーバーを登録します。また、AMSとDSHubのイベントをリッスンするためにデリゲートをバインドするコードを追加します。private void OnEnable()
{
...
ams.OnOpen += OnAMSConnected;
dsHub.OnConnected += OnDSHubConnected;
dsHub.MatchmakingV2ServerClaimed += OnServerClaimed;
LoginServer((result) =>
{
if (ams.IsConnected)
{
RegisterServer();
}
else
{
ams.OnOpen += RegisterServer;
}
});
} -
次に、
OnDisable()関数でラッパーが非初期化されたときにデリゲートをアンバインドします。private void OnDisable()
{
...
if (ams != null)
{
ams.OnOpen -= OnAMSConnected;
}
if (dsHub != null)
{
dsHub.OnConnected -= OnDSHubConnected;
dsHub.MatchmakingV2ServerClaimed -= OnServerClaimed;
}
}
サーバーの登録解除
ゲームセッションが終了したときなど、サーバーをシャットダウンする前に、未使用のゾンビサーバーを避けるために、まずAMSとDSHubからサーバーの登録を解除する必要があります。
-
MultiplayerDSAMSWrapper_Starterクラスを開き、以下の関数を作成してサーバー登録解除リクエストを送信します。private void DeregisterServer()
{
BytewarsLogger.Log("Deregistering server.");
ams?.Disconnect();
dsHub?.Disconnect();
} -
次に、AMSとDSHubが切断されたときにリッスンするために、これらのコールバック関数を作成します。
private void OnAMSDisconnected(WsCloseCode closeCode)
{
BytewarsLogger.Log($"Server disconnected from AMS. Close code: {closeCode}");
OnAMSConnectionClosed?.Invoke();
}private void OnDSHubDisconnected(WsCloseCode closeCode)
{
BytewarsLogger.Log($"Server disconnected from DSHub. Close code: {closeCode}");
// If disconnected abnormally, try to reconnect.
if (closeCode is WsCloseCode.Undefined or WsCloseCode.Abnormal or WsCloseCode.NoStatus)
{
string dsId = AccelByteSDK.GetServerConfig().DsId;
if (string.IsNullOrEmpty(dsId))
{
BytewarsLogger.LogWarning("Failed to reconnecting server to DSHub. DSId is invalid.");
}
BytewarsLogger.Log("Reconnecting server to DSHub.");
dsHub?.Connect(dsId);
}
} -
サーバーがバックエンドからゲームセッション終了通知を受信したとき(セッションがタイムアウトしたときなど)を処理する新しい関数を作成します。
private void OnGameSessionEnded(Result<SessionEndedNotification> result)
{
if (result.IsError)
{
BytewarsLogger.LogWarning($"Failed handle on game session ended. Error {result.Error.Code}: {result.Error.Message}");
return;
}
BytewarsLogger.Log($"Recieved game session ended. Session ID: {result.Value.SessionId}. Shutting down server.");
GameManager.Instance.StartShutdownCountdown(ServerShutdownDelay);
} -
OnEnable()関数で、以下のコードを追加して、ゲームセッションが終了したとき(ゲームオーバーまたはゲームセッション終了通知の受信のいずれか)にサーバー登録解除シーケンスを呼び出し、登録解除が完了したらサーバーをシャットダウンします。private void OnEnable()
{
...
ams.Disconnected += OnAMSDisconnected;
dsHub.OnDisconnected += OnDSHubDisconnected;
dsHub.GameSessionV2Ended += OnGameSessionEnded;
OnAMSConnectionClosed += ShutdownServer;
GameManager.Instance.OnDeregisterServer += DeregisterServer;
} -
次に、
OnDisable()関数でラッパーが非初期化されたときにデリゲートをアンバインドします。private void OnDisable()
{
...
if (ams != null)
{
ams.Disconnected -= OnAMSDisconnected;
}
if (dsHub != null)
{
dsHub.OnDisconnected -= OnDSHubDisconnected;
dsHub.GameSessionV2Ended -= OnGameSessionEnded;
}
OnAMSConnectionClosed -= ShutdownServer;
GameManager.Instance.OnDeregisterServer -= DeregisterServer;
}
ドレイン状態の処理
ドレイン信号は、サーバーが実行されている仮想マシン(VM)が削除予定であることをサーバーに通知します。理想的には、サーバーはプレイヤーにサービスを提供していないときにのみシャットダウンする必要があります。まだプレイヤーにサービスを提供している場合は、実行を継続してドレイン信号を無視する必要があります。ドレイン動作の詳細については、このページを参照してください。
Byte Warsでは、ドレイン信号を次のように処理します:
Wait for 10 seconds状態は、セッション情報の更新の潜在的な遅延に対応します。これは、更新が受信される直前にサーバーがバックエンドでクレームされ、早期のクレイム信号をトリガーする可能性があるケースを防ぐのに役立ちます。
-
MultiplayerDSAMSWrapper_Starterクラスを開き、ドレインロジックを処理する関数を作成します。この関数は、サーバーが現在アクティブなゲームセッションをホストしているかどうかをチェックします。セッションがアクティブな場合、ドレイン信号を無視してサーバーを実行し続けます。private void ExecuteDrainSignal()
{
if (string.IsNullOrEmpty(GameData.ServerSessionID))
{
BytewarsLogger.Log("ServerSessionID is empty, executing drain logic now!");
OnAMSDrainSignalReceived?.Invoke();
}
else
{
BytewarsLogger.Log("ServerSessionID is not empty, drain ignored until session ends.");
}
} -
専用サーバーがAMSからドレイン信号を受信したときに呼び出される関数を作成します。この関数は遅延を開始し、遅延が完了した後に
ExecuteDrainSignal()関数を実行します。private void OnAMSDrainReceived()
{
// Get the delay config from launch param.
const string keyword = "-DrainLogicDelayInSecs=";
if (!float.TryParse(TutorialModuleUtil.GetLaunchParamValue(keyword), out float delay))
{
delay = ServerShutdownDelay;
BytewarsLogger.Log("Could not parse drain delay launch param. Fallback to use default delay.");
}
// Execute drain logic after a delay to accommodate session info update delay.
BytewarsLogger.Log($"DS received drain signal from AMS. Delaying {delay} seconds to execute drain logic.");
Invoke(nameof(ExecuteDrainSignal), delay);
} -
OnEnable()関数で、以下のコードを追加して、ドレイン信号を受信したときにサーバー登録解除をトリガーします。private void OnEnable()
{
...
ams.OnDrainReceived += OnAMSDrainReceived;
OnAMSDrainSignalReceived += DeregisterServer;
} -
次に、
OnDisable()関数でラッパーが非初期化されたときにデリゲートをアンバインドします。private void OnDisable()
{
...
if (ams != null)
{
ams.OnDrainReceived -= OnAMSDrainReceived;
}
OnAMSDrainSignalReceived -= DeregisterServer;
}
リソース
- ByteWarsリポジトリ内のファイルへのGitHubリンク: