Access
Connect cross-platform accounts & identity management
using AccelByte.Server;
AccelByteServerPlugin.GetDedicatedServer().LoginWithClientCredentials(
result =>
{
if (result.IsError)
{
Debug.Log($"Server login failed");
}
else
{
Debug.Log("Server login successful");
}
});
AccelByteServerPlugin.GetDedicatedServerManager().RegisterLocalServer(ip, portNumber, name, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Local Server to DSM failed");
}
else
{
Debug.Log("Register Local Server to DSM successful");
}
});
AccelByteServerPlugin.GetDedicatedServerManager().GetSessionId(dsmResult =>
{
if (dsmResult.IsError)
{
Debug.Log("Failed Get Session Id");
}
else
{
Debug.Log("Successfully Get Session Id");
}
});
AccelByteServerPlugin.GetMatchmaking().QuerySessionStatus(dsmResult.Value.session_id,
queryResult =>
{
if (queryResult.IsError)
{
Debug.Log("Failed Query Session Status");
}
else
{
Debug.Log("Successfully Query Session Status");
}
});
AccelByteServerPlugin.GetDedicatedServerManager().DeregisterLocalServer(result =>
{
if (result.IsError)
{
Debug.Log("Failed Deregister Local Server");
}
else
{
Debug.Log("Successfully Deregister Local Server");
}
});
AccelByteServerPlugin.GetDedicatedServerManager().ShutdownServer(true,
result =>
{
if (result.IsError)
{
Debug.Log("Failed Shutdown Server");
}
else
{
Debug.Log("Successfully Shutdown Server");
}
});
In this tutorial, you will learn how to integrate Armada with your game and test it on your local PC or in the AccelByte Server by uploading the server image. This guide assumes that you have already implemented the Lobby (opens new window), Friends (opens new window), Party (opens new window), and Matchmaking (opens new window) services.
Since server implementation with Armada can vary for each game, you can familiarize yourself with other concepts and classes in the ServerModels.cs file inside the plugin SDK.
Before continuing, ensure that you have configured your AccelByteServerSDKConfig.json. Follow this tutorial (opens new window) to configure the server SDK.
We will start by adding simple Armada logic into the game.
using AccelByte.Server;
// Function called to Login by client credentials for the server.
public void LoginServer(int port, bool isLocal)
{
AccelByteServerPlugin.GetDedicatedServer().LoginWithClientCredentials(result =>
{
if (result.IsError)
{
// If we error, grab the Error Code and Message to print in the Log
Debug.Log($"Server login failed : {result.Error.Code}: {result.Error.Message}");
}
else
{
Debug.Log("Server login successful");
// Some actions
}
});
}
Log in with your client credentials and replace the actions comments as per the following code:
// Function called to Log in by client credentials for the server.
public static void LoginServer(int port, bool isLocal)
{
...
else
{
Debug.Log("Server login successful");
if (isLocal)
{
// Set local IP, server name, port
string ip = "127.0.0.1";
string name = $"localds-{DeviceProvider.GetFromSystemInfo().DeviceId}";
uint portNumber = Convert.ToUInt32(port);
// Register Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterLocalServer(ip, portNumber, name, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Local Server to DSM failed");
}
else
{
Debug.Log("Register Local Server to DSM successful");
}
});
}
}
});
}
void Start()
{
#if UNITY_SERVER
LoginServer("7777", false);
#endif
}
Build and run the project as a server build. Your server log will read Server login successful and Register Local Server to DSM successful if the action has been completed successfully. You can also check in the Admin Portal to see if your local Dedicated Server has successfully registered in the DSM.
TROUBLESHOOTING
If you encounter a Server login failed: message, check your login credentials, API URLs, or the other configs in your AccelByteServerSDKConfig.json file.
public void GetMatchInfo()
{
// Get session id/ match id from DSM
AccelByteServerPlugin.GetDedicatedServerManager().GetSessionId(dsmResult =>
{
if (dsmResult.IsError)
{
Debug.Log("Failed Get Session Id");
}
else
{
Debug.Log("Successfully Get Session Id");
// Query Session Status to get match info from Matchmaking
AccelByteServerPlugin.GetMatchmaking().QuerySessionStatus(dsmResult.Value.session_id, queryResult =>
{
if (queryResult.IsError)
{
Debug.Log("Failed Query Session Status");
}
else
{
Debug.Log("Successfully Query Session Status. The game mode is: " + queryResult.Value.game_mode);
}
});
}
});
}
public void UnregisterServer(bool isLocal)
{
if (isLocal)
{
// Deregister Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().DeregisterLocalServer(result =>
{
if (result.IsError)
{
Debug.Log("Failed Deregister Local Server");
}
else
{
Debug.Log("Successfully Deregister Local Server");
}
});
}
}
void OnApplicationQuit()
{
#if UNITY_SERVER
UnregisterServer(false);
#endif
}
// Function called to Login by client credentials for the server.
public void LoginServer(int port, bool isLocal)
{
...
else
{
Debug.Log("Server login successful");
if (!isLocal)
{
// Register Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterServer(port, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Server to DSM failed");
}
else
{
Debug.Log("Register Server to DSM successful");
}
});
}
});
}
To obtain match information, use the same logic from Step 6.
Create a Deregister or Shutdown Dedicated Server from Dedicated Server Manager script by modifying the following in the deregistration script that you have already created in Step 7:
public static void UnregisterServer(bool isLocal)
{
if (!isLocal)
{
// Shutdown Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().ShutdownServer(true, result =>
{
if (result.IsError)
{
Debug.Log("Failed Shutdown Server");
}
else
{
Debug.Log("Successfully Shutdown Server");
}
});
}
}
void Start()
{
#if UNITY_SERVER
LoginServer("7777", true);
#endif
}
Modify the boolean in the OnApplicationQuit() function.
void OnApplicationQuit()
{
#if UNITY_SERVER
UnregisterServer(true);
#endif
}
Now you can build your server and upload the image into the AccelByte Server. Follow this guide (opens new window) to upload the image to the AccelByte Server. Once completed, your server should be automatically created when the client gets a DS Updated notification event from the Matchmaking service.
NOTE
Congratulations! You have now learnt how to use Armada!
Continue on for a step by step example of the code implementation.
public static class ArmadaHandler
public static void LoginServer(int port, bool isLocal) { … }
public static void LoginServer(int port, bool isLocal)
{
AccelByteServerPlugin.GetDedicatedServer().LoginWithClientCredentials(result =>
{
if (result.IsError)
{
// If we error, grab the Error Code and Message to print in the Log
Debug.Log($"Server login failed : {result.Error.Code}: {result.Error.Message}");
}
else
{
Debug.Log("Server login successful");
if (!isLocal)
{
// Register Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterServer(port, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Server to DSM failed");
}
else
{
Debug.Log("Register Server to DSM successful");
}
});
}
else
{
string ip = "127.0.0.1";
string name = $"localds-{DeviceProvider.GetFromSystemInfo().DeviceId}";
uint portNumber = Convert.ToUInt32(port);
// Register Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterLocalServer(ip, portNumber, name, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Local Server to DSM failed");
}
else
{
Debug.Log("Register Local Server to DSM successful");
}
});
}
}
});
}
public static void GetPlayerInfo(ResultCallback<MatchmakingResult> callback)
{
// Get session id/ match id from DSM
AccelByteServerPlugin.GetDedicatedServerManager().GetSessionId(dsmResult =>
{
if (dsmResult.IsError)
{
Debug.Log("Failed Get Session Id");
callback.TryError(dsmResult.Error);
}
else
{
// Query Session Status to get match info from Matchmaking
AccelByteServerPlugin.GetMatchmaking().QuerySessionStatus(dsmResult.Value.session_id, queryResult =>
{
if (queryResult.IsError)
{
Debug.Log("Failed Query Session Status");
callback.TryError(queryResult.Error);
}
else
{
// Return error if status is not matched
if (queryResult.Value.status != AccelByte.Models.MatchmakingStatus.matched)
{
Debug.Log("Matchmaking status is not matched");
// Return error callback
callback.TryError(queryResult.Error);
}
// Return success callback
callback.TryOk(queryResult.Value);
}
});
}
});
}
public static void UnregisterServer(bool isLocal) { … }
public static void UnregisterServer(bool isLocal)
{
if (isLocal)
{
// Deregister Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().DeregisterLocalServer(result =>
{
if (result.IsError)
{
Debug.Log("Failed Deregister Local Server");
}
else
{
Debug.Log("Successfully Deregister Local Server");
Application.Quit();
}
});
}
else
{
// Shutdown Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().ShutdownServer(true, result =>
{
if (result.IsError)
{
Debug.Log("Failed Shutdown Server");
}
else
{
Debug.Log("Successfully Shutdown Server");
Application.Quit();
}
});
}
}
private bool isLocal = false;
internal void OnAccelByteServerStarted(int port)
{
// Get the local command line argument for the local test
isLocal = ConnectionHandler.GetLocalArgument();
ArmadaHandler.LoginServer(port, isLocal);
}
public override void OnStartServer()
{
base.OnStartServer();
GameplayManager.OnAccelByteServerStarted(transport.ServerUri().Port);
GameplayManager.OnServerStarted();
}
void OnServerStartClient(NetworkConnection conn, ServerStartClientMessage msg)
{
playerInfos.Add(conn, new PlayerInfo { playerId = msg.playerId, displayName = msg.displayName });
PlayerInfo playerInfo = playerInfos[conn];
ArmadaHandler.GetPlayerInfo(result =>
{
if (result.IsError) return;
bool isPartyA = true;
bool foundPlayer = false;
// Get total player from game mode in result
totalPlayers = result.Value.game_mode.ToGameMode().GetTotalPlayers();
// Check if the user exists and assign the party
foreach (var ally in result.Value.matching_allies)
{
foreach (var party in ally.matching_parties)
{
foreach (var user in party.party_members)
{
if (user.user_id == playerInfo.playerId)
{
playerInfo.isPartyA = isPartyA;
foundPlayer = true;
break;
}
}
if (foundPlayer) break;
}
if (foundPlayer) break;
isPartyA = !isPartyA;
}
// Remove player info if the player is not registered in the current match
if (!foundPlayer)
{
playerInfos.Remove(conn);
return;
}
totalPlayersConnected++;
Debug.Log($"Total player Connected : {totalPlayersConnected}/{totalPlayers}");
// Update player infos dictionary
playerInfos[conn] = playerInfo;
Debug.Log(string.Format("Player {0} is joining in the party {1}", playerInfo.displayName, playerInfo.isPartyA ? "A" : "B"));
// Start the game if total players connected and total players are same
if (totalPlayersConnected == totalPlayers)
{
foreach (NetworkConnection connection in playerInfos.Keys)
{
connection.Send(new ClientStartClientResponseMessage { });
}
if (isServer)
{
StartCoroutine(CountdownTimer());
}
}
});
}
private void OnApplicationQuit()
{
#if UNITY_SERVER
ArmadaHandler.UnregisterServer(isLocal);
#endif
}
IEnumerator CloseServer(int timeout = 30)
{
Debug.Log("Start countdown to close server");
for (int i = 0; i < timeout; i++)
{
yield return new WaitForSeconds(1.0f);
}
ArmadaHandler.UnregisterServer(isLocal);
}
void OnServerStopTimerMessage(NetworkConnection conn, ServerRequestStopTimerMessage msg)
{
totalPlayersStop++;
PlayerInfo playerInfo = playerInfos[conn];
playerInfo.playerScoreTime = mainTime;
playerInfos[conn] = playerInfo;
Debug.Log($"Total player Stop: {totalPlayersStop}/{totalPlayers}");
if (totalPlayersStop == totalPlayers)
{
StartCoroutine(CloseServer());
OnServerStopGameplay();
}
}
Build your server and upload your server image to the AccelByte Server.
Once completed, you can test your build. To test on your local PC, run the local server with the command line argument -local. You can either create a shortcut or a batch file to test local servers. If you want to create a batch file, you can use the following example: batch file.
@ECHO ON
start Server/Justice-Unity-Tutorial-Project.exe local
Congratulations! You have fully implemented the Armada Service and successfully installed the AccelByte Unity SDK and AccelByte Config file.
// Copyright (c) 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using System;
using System.Collections.Generic;
using UnityEngine;
using AccelByte.Server;
using AccelByte.Api;
using AccelByte.Core;
using AccelByte.Models;
public static class ArmadaHandler
{
/// <summary>
/// Server login with the server client credentials and register DS to DSM
/// </summary>
/// <param name="port"> </param>
/// <param name="isLocal"></param>
public static void LoginServer(int port, bool isLocal)
{
AccelByteServerPlugin.GetDedicatedServer().LoginWithClientCredentials(result =>
{
if (result.IsError)
{
// If we error, grab the Error Code and Message to print in the Log
Debug.Log($"Server login failed : {result.Error.Code}: {result.Error.Message}");
}
else
{
Debug.Log("Server login successful");
if (!isLocal)
{
// Register Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterServer(port, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Server to DSM failed");
}
else
{
Debug.Log("Register Server to DSM successful");
}
});
}
else
{
string ip = "127.0.0.1";
string name = $"localds-{DeviceProvider.GetFromSystemInfo().DeviceId}";
uint portNumber = Convert.ToUInt32(port);
// Register Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().RegisterLocalServer(ip, portNumber, name, registerResult =>
{
if (registerResult.IsError)
{
Debug.Log("Register Local Server to DSM failed");
}
else
{
Debug.Log("Register Local Server to DSM successful");
}
});
}
}
});
}
/// <summary>
/// Unregister DS from DSM and quit the app
/// </summary>
/// <param name="isLocal"> Unregister local DS if the value is true</param>
public static void UnregisterServer(bool isLocal)
{
if (isLocal)
{
// Deregister Local Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().DeregisterLocalServer(result =>
{
if (result.IsError)
{
Debug.Log("Failed Deregister Local Server");
}
else
{
Debug.Log("Successfully Deregister Local Server");
Application.Quit();
}
});
}
else
{
// Shutdown Server to DSM
AccelByteServerPlugin.GetDedicatedServerManager().ShutdownServer(true, result =>
{
if (result.IsError)
{
Debug.Log("Failed Shutdown Server");
}
else
{
Debug.Log("Successfully Shutdown Server");
Application.Quit();
}
});
}
}
/// <summary>
/// DS queries match info from Matchmaking (MM)
/// </summary>
/// <param name="callback"> Return match info callback</param>
public static void GetPlayerInfo(ResultCallback<MatchmakingResult> callback)
{
// Get session id/ match id from DSM
AccelByteServerPlugin.GetDedicatedServerManager().GetSessionId(dsmResult =>
{
if (dsmResult.IsError)
{
Debug.Log("Failed Get Session Id");
callback.TryError(dsmResult.Error);
}
else
{
// Query Session Status to get match info from Matchmaking
AccelByteServerPlugin.GetMatchmaking().QuerySessionStatus(dsmResult.Value.session_id, queryResult =>
{
if (queryResult.IsError)
{
Debug.Log("Failed Query Session Status");
callback.TryError(queryResult.Error);
}
else
{
// Return error if status is not matched
if (queryResult.Value.status != AccelByte.Models.MatchmakingStatus.matched)
{
Debug.Log("Matchmaking status is not matched");
// Return error callback
callback.TryError(queryResult.Error);
}
// Return success callback
callback.TryOk(queryResult.Value);
}
});
}
});
}
}
// Copyright (c) 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using Mirror;
using System;
using UnityEngine;
public class WatchTimeNetworkManager : NetworkManager
{
[SerializeField]
private GameplayManager GameplayManager;
public override void Start()
{
base.Start();
#if !UNITY_SERVER
// Change ip and port based on DS info in the client
networkAddress = ConnectionHandler.ip;
gameObject.GetComponent<kcp2k.KcpTransport>().Port = ConnectionHandler.uPort;
// Auto start the client connection
StartClient();
#endif
}
#region Client System Callbacks
/// <summary>
/// Called on the client when connected to a server.
/// <para>The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects.</para>
/// </summary>
/// <param name="conn">Connection to the server.</param>
public override void OnClientConnect(NetworkConnection conn)
{
base.OnClientConnect(conn);
GameplayManager.OnPlayerStarted();
}
#endregion
#region Start & Stop Callbacks
/// <summary>
/// Called when a server is started - including when a host is started.
/// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
/// </summary>
public override void OnStartServer()
{
base.OnStartServer();
GameplayManager.OnAccelByteServerStarted(transport.ServerUri().Port);
GameplayManager.OnServerStarted();
}
#endregion
/// <summary>
/// Called when the server stop the client connections
/// </summary>
public override void OnStopClient()
{
base.OnStopClient();
GameplayManager.OnPlayerDisconnected();
}
}
// Copyright (c) 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using AccelByte.Api;
using Mirror;
public class GameplayManager : NetworkBehaviour
{
[SerializeField]
private GameplayInterface gameCanvas;
private int totalPlayersConnected = 0;
private int totalPlayersStop = 0;
private int totalPlayers = 0;
private bool isLocal = false;
private double targetTime;
private double mainTime;
internal static readonly Dictionary<NetworkConnection, PlayerInfo> playerInfos = new Dictionary<NetworkConnection, PlayerInfo>();
/// <summary>
/// Called by server to login by credentials
/// </summary>
/// <param name="port"></param>
internal void OnAccelByteServerStarted(int port)
{
// Get the local command line argument for the local test
isLocal = ConnectionHandler.GetLocalArgument();
ArmadaHandler.LoginServer(port, isLocal);
}
/// <summary>
/// Called on Start Server
/// </summary>
internal void OnServerStarted()
{
if (!NetworkServer.active) return;
NetworkServer.RegisterHandler<ServerStartClientMessage>(OnServerStartClient);
NetworkServer.RegisterHandler<ServerRequestStopTimerMessage>(OnServerStopTimerMessage);
}
/// <summary>
/// Called on Client connect to server
/// </summary>
internal void OnPlayerStarted()
{
if (!NetworkClient.active) return;
NetworkClient.RegisterHandler<ClientStartClientResponseMessage>(OnStartClientResponse);
NetworkClient.RegisterHandler<ClientUpdateCountdownTimerMessage>(OnUpdateCountdownTime);
NetworkClient.RegisterHandler<ClientChangeToGameplayStateMessage>(OnChangeToGameplayState);
NetworkClient.RegisterHandler<ClientUpdateMainTimeMessage>(OnUpdateMainTime);
NetworkClient.RegisterHandler<ClientOnAllPlayerStopTime>(OnAllClientStopTime);
// Current user's userId and displayName
string userId = AccelBytePlugin.GetUser().Session.UserId;
string displayName = LobbyHandler.Instance.partyHandler.partyMembers[userId];
NetworkClient.connection.Send(new ServerStartClientMessage { playerId = userId, displayName = displayName });
// Set the user id inside the gameplay interface player id. this to check after gameplay ended, the interface will know where their current player information by matching the player id
gameCanvas.playerId = userId;
}
/// <summary>
/// Called on Client disconnect
/// </summary>
internal void OnPlayerDisconnected()
{
gameCanvas.ChangePanel(GameplayInterfaceState.None);
}
/// <summary>
/// Send message to server that player press the stop button
/// </summary>
public void RequestStopTime()
{
NetworkClient.connection.Send(new ServerRequestStopTimerMessage { });
}
/// <summary>
/// Server set player's info
/// </summary>
/// <param name="conn"> player's network connection</param>
/// <param name="msg"> message that contains player's info</param>
void OnServerStartClient(NetworkConnection conn, ServerStartClientMessage msg)
{
playerInfos.Add(conn, new PlayerInfo { playerId = msg.playerId, displayName = msg.displayName });
PlayerInfo playerInfo = playerInfos[conn];
ArmadaHandler.GetPlayerInfo(result =>
{
if (result.IsError) return;
bool isPartyA = true;
bool foundPlayer = false;
// Get total player from game mode in result
totalPlayers = result.Value.game_mode.ToGameMode().GetTotalPlayers();
// Check if the user exists and assign the party
foreach (var ally in result.Value.matching_allies)
{
foreach (var party in ally.matching_parties)
{
foreach (var user in party.party_members)
{
if (user.user_id == playerInfo.playerId)
{
playerInfo.isPartyA = isPartyA;
foundPlayer = true;
break;
}
}
if (foundPlayer) break;
}
if (foundPlayer) break;
isPartyA = !isPartyA;
}
// Remove player info if the player is not registered in the current match
if (!foundPlayer)
{
playerInfos.Remove(conn);
return;
}
totalPlayersConnected++;
Debug.Log($"Total player Connected : {totalPlayersConnected}/{totalPlayers}");
// Update player infos dictionary
playerInfos[conn] = playerInfo;
Debug.Log(string.Format("Player {0} is joining in the party {1}", playerInfo.displayName, playerInfo.isPartyA ? "A" : "B"));
// Start the game if total players connected and total players are same
if (totalPlayersConnected == totalPlayers)
{
foreach (NetworkConnection connection in playerInfos.Keys)
{
connection.Send(new ClientStartClientResponseMessage { });
}
if (isServer)
{
StartCoroutine(CountdownTimer());
}
}
});
}
/// <summary>
/// Server set the player stop time
/// </summary>
/// <param name="conn"> player's network connection</param>
/// <param name="msg"> server's message</param>
void OnServerStopTimerMessage(NetworkConnection conn, ServerRequestStopTimerMessage msg)
{
totalPlayersStop++;
PlayerInfo playerInfo = playerInfos[conn];
playerInfo.playerScoreTime = mainTime;
playerInfos[conn] = playerInfo;
Debug.Log($"Total player Stop: {totalPlayersStop}/{totalPlayers}");
if (totalPlayersStop == totalPlayers)
{
StartCoroutine(CloseServer());
OnServerStopGameplay();
}
}
/// <summary>
/// Server finish the round since all players have pressed the stop button
/// </summary>
void OnServerStopGameplay()
{
StopCoroutine("StopWatch");
List<NetworkConnection> keysToUpdate = new List<NetworkConnection>();
keysToUpdate.AddRange(playerInfos.Keys.ToArray());
List<double> scores = new List<double>();
for (int i = 0; i < keysToUpdate.Count; i++)
{
scores.Add(Mathf.Abs((float)(targetTime - playerInfos.Values.ToArray()[i].playerScoreTime)));
}
double currentHigherScore = 99999999.0f; // in this case the lower value is the winner
for (int i = 0; i < scores.Count; i++)
{
if (scores[i] < currentHigherScore)
{
currentHigherScore = scores[i];
}
}
int highscoreIndex = scores.FindIndex(x => x == currentHigherScore);
for (int i = 0; i < keysToUpdate.Count; i++)
{
PlayerInfo playerInformation = playerInfos[keysToUpdate[i]];
if (playerInformation.isPartyA == playerInfos[keysToUpdate[highscoreIndex]].isPartyA)
{
playerInformation.isWin = true;
}
else
{
playerInformation.isWin = false;
}
playerInfos[keysToUpdate[i]] = playerInformation;
}
foreach (NetworkConnection connection in playerInfos.Keys)
{
connection.Send(new ClientOnAllPlayerStopTime { allPlayerInfos = playerInfos.Values.ToArray(), targetTime = targetTime });
}
}
/// <summary>
/// Coroutine: Update loading countdown from 3 to 0
/// </summary>
/// <returns> wait for 1 second</returns>
IEnumerator CountdownTimer()
{
for (int countdown = 3; countdown >= 0; countdown--)
{
foreach (NetworkConnection connection in playerInfos.Keys)
{
if (isServer)
{
connection.Send(new ClientUpdateCountdownTimerMessage { time = countdown });
}
}
yield return new WaitForSeconds(1.0f);
if (countdown == 0)
{
// Set target time
// random target time with range a to b seconds
targetTime = Random.Range(3.0f, 9.0f);
// send targetTime value to all client
foreach (NetworkConnection connection in playerInfos.Keys)
{
connection.Send(new ClientChangeToGameplayStateMessage { targetTime = targetTime });
}
StartCoroutine(MainTime());
}
}
}
/// <summary>
/// Coroutine: Update current running mainTime
/// </summary>
/// <returns></returns>
IEnumerator MainTime()
{
while (true)
{
mainTime += Time.deltaTime;
foreach (NetworkConnection connection in playerInfos.Keys)
{
connection.Send(new ClientUpdateMainTimeMessage { mainTime = mainTime });
}
yield return null;
}
}
/// <summary>
/// Unregister server and close the server automatically after the time is timeout
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
IEnumerator CloseServer(int timeout = 30)
{
Debug.Log("Start countdown to close server");
for (int i = 0; i < timeout; i++)
{
yield return new WaitForSeconds(1.0f);
}
ArmadaHandler.UnregisterServer(isLocal);
}
/// <summary>
/// On client start, change panel to ReadyPanel
/// </summary>
/// <param name="msg"> client's message</param>
void OnStartClientResponse(ClientStartClientResponseMessage msg)
{
gameCanvas.ChangePanel(GameplayInterfaceState.Loading);
}
/// <summary>
/// On loading countdown, update LoadingPanel's UI
/// </summary>
/// <param name="msg"></param>
void OnUpdateCountdownTime(ClientUpdateCountdownTimerMessage msg)
{
gameCanvas.UpdateLoadingPanelUI(msg.time);
}
/// <summary>
/// Change panel to GameplayPanel and start the game
/// </summary>
/// <param name="msg"></param>
void OnChangeToGameplayState(ClientChangeToGameplayStateMessage msg)
{
gameCanvas.ChangePanel(GameplayInterfaceState.Gameplay);
gameCanvas.UpdateTargetTimeUI(msg.targetTime);
}
/// <summary>
/// On current mainTime update, update mainTime to its UI
/// </summary>
/// <param name="msg"></param>
void OnUpdateMainTime(ClientUpdateMainTimeMessage msg)
{
gameCanvas.UpdateMainTimeUI(msg.mainTime);
}
/// <summary>
/// On all players have pressed the stop button, finish the game
/// </summary>
/// <param name="msg"></param>
void OnAllClientStopTime(ClientOnAllPlayerStopTime msg)
{
gameCanvas.ChangePanel(GameplayInterfaceState.Result);
gameCanvas.UpdateResultPanelUI(msg.allPlayerInfos, msg.targetTime);
}
private void OnApplicationQuit()
{
#if UNITY_SERVER
ArmadaHandler.UnregisterServer(isLocal);
#endif
}
}