Created
January 8, 2021 02:31
-
-
Save LukmanaAfif/d3c8a78bc6e4d4b7006da6573f1086bc to your computer and use it in GitHub Desktop.
AccelByte Sample Game Unity - Matchmaking Logic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region AccelByte MatchMaking Functions | |
/// <summary> | |
/// Find match function by calling lobby matchmaking | |
/// Get latencies from available game server regions from Quality of Service | |
/// Latencies can be used for matchmaking to determine which region has the lowest latency | |
/// </summary> | |
private void FindMatch() | |
{ | |
if (connectToLocal) | |
{ | |
lobbyLogic.abLobby.StartMatchmaking(gameMode, accelByteManager.LocalDSName, OnFindMatch); | |
} | |
else | |
{ | |
var regionIndex = UIHandlerLobbyComponent.regionSelectorDropdown.value; | |
var selectedLatency = qosLatencies.Values.ToList()[regionIndex]; | |
var selectedRegion = qosLatencies.Keys.ToList()[regionIndex]; | |
Dictionary<string, int> latencies = new Dictionary<string, int>(1){{selectedRegion, selectedLatency}}; | |
if (!selectedRegion.IsNullOrEmpty() && selectedLatency > 0) | |
{ | |
#if FORCE_PROVIDER_AWS | |
Dictionary<string, int> availableRegion = new Dictionary<string, int>(); | |
foreach (KeyValuePair<string, int> region in latencies) | |
{ | |
Debug.Log("[LobbyLogic] FindMatch region :" + region.Key + " latency: " + region.Value); | |
if (region.Key == "ap-southeast-1" || region.Key == "us-west-2") | |
{ | |
Debug.Log("[LobbyLogic] FindMatch FORCE connect to region :" + region.Key + " latency: " + region.Value); | |
availableRegion.Add(region.Key,region.Value); | |
} | |
} | |
lobbyLogic.abLobby.StartMatchmaking(gameMode, LightFantasticConfig.DS_TARGET_VERSION, availableRegion, OnFindMatch); | |
return; | |
#else | |
lobbyLogic.abLobby.StartMatchmaking(gameMode, "", LightFantasticConfig.DS_TARGET_VERSION, latencies, OnFindMatch); | |
#endif //FORCE_PROVIDER_AWS | |
} | |
else | |
{ | |
lobbyLogic.abLobby.StartMatchmaking(gameMode, "", LightFantasticConfig.DS_TARGET_VERSION, OnFindMatch); | |
} | |
} | |
} | |
/// <summary> | |
/// Matchmaking required the player to a party | |
/// When the player does not included in a party yet, then create a party first | |
/// </summary> | |
private void FindMatchButtonClicked() | |
{ | |
if (!lobbyLogic.partyLogic.GetIsLocalPlayerInParty()) | |
{ | |
lobbyLogic.abLobby.CreateParty(OnPartyCreatedFindMatch); | |
} | |
else | |
{ | |
FindMatch(); | |
} | |
} | |
/// <summary> | |
/// Cancel matchmaking bound on cancel matchmaking button | |
/// </summary> | |
private void FindMatchCancelClicked() | |
{ | |
lobbyLogic.abLobby.CancelMatchmaking(gameMode, OnFindMatchCanceled); | |
} | |
/// <summary> | |
/// The game is using auto accept then ready consent callback thrown from lobby service | |
/// This function can be used for accepting ready consent by bind it to accept popup button | |
/// abMatchmakingNotif.MatchID will be filled when the match has been found | |
/// </summary> | |
public void OnAcceptReadyForMatchClicked() | |
{ | |
if (abMatchmakingNotif != null) | |
{ | |
lobbyLogic.abLobby.ConfirmReadyForMatch(abMatchmakingNotif.matchId, OnReadyForMatchConfirmation); | |
} | |
UIHandlerLobbyComponent.popupMatchConfirmation.gameObject.SetActive(false); | |
} | |
/// <summary> | |
/// The game is using auto accept then ready consent callback thrown from lobby service | |
/// This function can be used for decline ready consent by bind it to decline popup button | |
/// </summary> | |
public void OnDeclineReadyForMatchClicked() | |
{ | |
lobbyLogic.abLobby.CancelMatchmaking(gameMode, OnFindMatchCanceled); | |
UIHandlerLobbyComponent.popupMatchConfirmation.gameObject.SetActive(false); | |
} | |
/// <summary> | |
/// Connect to game server once the game client knows once the game server is ready | |
/// </summary> | |
private bool allowToConnectServer = true; | |
IEnumerator WaitForGameServerReady(string ip, string port) | |
{ | |
if (allowToConnectServer) | |
{ | |
allowToConnectServer = false; | |
bool isActive = true; | |
while (isActive) | |
{ | |
yield return new WaitForSecondsRealtime(1.0f); | |
if (connectToLocal) | |
{ | |
ip = ipConnectToLocal; | |
port = portConnectToLocal; | |
} | |
multiplayerConnect.SetIPAddressPort(ip, port); | |
multiplayerConnect.Connect(); | |
isActive = false; | |
} | |
} | |
} | |
/// <summary> | |
/// Show matchmaking board once the callback from find match triggered | |
/// </summary> | |
/// <param name="show"> switch either to show and hide UI </param> | |
/// <param name="gameFound"> show the state of the match has been found </param> | |
public void ShowMatchmakingBoard(bool show, bool gameFound = false) | |
{ | |
// If there's matchmaking board shown, disable the [ONLINE] and [LOCAL] button | |
UIHandlerLobbyComponent.matchmakingButtonCollection.SetInteractable(PlayMatchButtonsScript.ButtonList.OnlineButton, !show); | |
UIHandlerLobbyComponent.matchmakingButtonCollection.SetInteractable(PlayMatchButtonsScript.ButtonList.LocalButton, !show); | |
UIHandlerLobbyComponent.matchmakingBoard.waitingTimerLayout.gameObject.SetActive(false); | |
UIHandlerLobbyComponent.matchmakingBoard.gameObject.SetActive(show); | |
if (!show) | |
{ | |
UIHandlerLobbyComponent.matchmakingBoard.TerminateCountdown(); | |
} | |
if (gameFound) | |
{ | |
UIHandlerLobbyComponent.matchmakingBoard.gameObject.SetActive(true); | |
} | |
else | |
{ | |
UIHandlerLobbyComponent.matchmakingBoard.waitingTimerLayout.gameObject.SetActive(true); | |
} | |
} | |
/// <summary> | |
/// Game server using this function to host a game match | |
/// multiplayerConnect referenced multiplayer menu from Forge Networking | |
/// </summary> | |
public void HostingGameServer() | |
{ | |
multiplayerConnect.Host(); | |
} | |
/// <summary> | |
/// Game client function to connect to game server | |
/// multiplayerConnect referenced multiplayer menu from Forge Networking | |
/// </summary> | |
public void ConnecttoGameServer() | |
{ | |
multiplayerConnect.Connect(); | |
} | |
/// <summary> | |
/// Show prompt panel to choose "RETRY" or "CANCEL" matchmaking | |
/// </summary> | |
private void OnFailedMatchmaking(string reason) | |
{ | |
lobbyLogic.abLobby.CancelMatchmaking(gameMode, OnFindMatchCanceled); | |
UIHandlerLobbyComponent.matchmakingFailedPromptPanel.SetText("MATCHMAKING FAILED", reason); | |
UIHandlerLobbyComponent.matchmakingFailedPromptPanel.Show(); | |
} | |
#endregion | |
#region AccelByte MatchMaking Notification Callbacks | |
/// <summary> | |
/// Callback from MatchmakingCompleted event of Lobby service | |
/// This will be triggered if the player is in a party and the party leader do matchmaking | |
/// </summary> | |
/// <param name="result"> callback result that consist of a match id and matchmaking status </param> | |
private void OnFindMatchCompleted(Result<MatchmakingNotif> result) | |
{ | |
if (result.IsError) | |
{ | |
Debug.Log("OnFindMatchCompleted failed:" + result.Error.Message); | |
Debug.Log("OnFindMatchCompleted Response Code::" + result.Error.Code); | |
} | |
else | |
{ | |
Debug.Log("OnFindMatchCompleted Finding matchmaking Completed"); | |
Debug.Log("OnFindMatchCompleted Match Found: " + result.Value.matchId); | |
Debug.Log(" Match status: " + result.Value.status); | |
Debug.Log(" Expected match status: " + MatchmakingNotifStatus.done.ToString()); | |
abMatchmakingNotif = result.Value; | |
lobbyLogic.abLobby.ConfirmReadyForMatch(abMatchmakingNotif.matchId, OnReadyForMatchConfirmation); | |
UIHandlerLobbyComponent.matchmakingBoard.StartCountdown(MatchmakingWaitingPhase.ConfirmingMatch, | |
delegate | |
{ | |
OnFailedMatchmaking("Timeout to confirm matchmaking"); | |
}); | |
// if the player is in a party and the match is complete | |
if (result.Value.status == MatchmakingNotifStatus.done.ToString()) | |
{ | |
lobbyLogic.WriteInDebugBox(" Match Found: " + result.Value.matchId); | |
} | |
// if the player is in a party and the party leader start a matchmaking | |
else if (result.Value.status == MatchmakingNotifStatus.start.ToString()) | |
{ | |
MainThreadTaskRunner.Instance.Run(delegate | |
{ | |
ShowMatchmakingBoard(true); | |
}); | |
UIHandlerLobbyComponent.matchmakingBoard.StartCountdown(MatchmakingWaitingPhase.FindMatch, | |
delegate | |
{ | |
OnFailedMatchmaking("Timeout to finding match"); | |
}); | |
UIHandlerLobbyComponent.matchmakingBoard.SetGameMode(gameModeEnum); | |
} | |
// if the player is in a party and the party leader cancel the current matchmaking | |
else if (result.Value.status == MatchmakingNotifStatus.cancel.ToString()) | |
{ | |
MainThreadTaskRunner.Instance.Run(delegate | |
{ | |
ShowMatchmakingBoard(false); | |
}); | |
} | |
} | |
} | |
/// <summary> | |
/// Callback event from DSUpdated of Lobby service | |
/// The data are retrieved from DSM containing the current status of game server that being spawned | |
/// Will be triggered multiple times each time will be udpated with the most current status | |
/// CREATING : The DS is being spawned by DSM | |
/// READY : The DS is ready to use, the game client can start to jump in to the game server | |
/// BUSY : The DS is currently being used | |
/// </summary> | |
/// <param name="result"> Callback result of the current DS status </param> | |
private void OnSuccessMatch(Result<DsNotif> result) | |
{ | |
if (result.IsError) | |
{ | |
Debug.Log("OnSuccessMatch failed:" + result.Error.Message); | |
Debug.Log("OnSuccessMatch Response Code::" + result.Error.Code); | |
MainThreadTaskRunner.Instance.Run(delegate | |
{ | |
OnFailedMatchmaking("An error occurs in the dedicated server manager"); | |
}); | |
} | |
else | |
{ | |
if (result.Value.isOK == "false" && !connectToLocal) | |
{ | |
MainThreadTaskRunner.Instance.Run(delegate | |
{ | |
OnFailedMatchmaking("Failed to create a dedicated server"); | |
}); | |
return; | |
} | |
UIHandlerLobbyComponent.matchmakingBoard.StartCountdown(MatchmakingWaitingPhase.WaitingDSM, | |
delegate { OnFailedMatchmaking("Spawning a dedicated server timed out"); }); | |
Debug.Log("OnSuccessMatch success match completed"); | |
// DSM on process creating DS | |
if (result.Value.status == DSNotifStatus.CREATING.ToString()) | |
{ | |
Debug.Log("Waiting for the game server!"); | |
} | |
// DS is ready | |
else if (result.Value.status == DSNotifStatus.READY.ToString()) | |
{ | |
// Set IP and port to persistent and connect to the game | |
Debug.Log("Entering the game!"); | |
Debug.Log("Lobby OnSuccessMatch Connect"); | |
MainThreadTaskRunner.Instance.Run(() => { StartCoroutine(WaitForGameServerReady(result.Value.ip, result.Value.port.ToString())); }); | |
} | |
else if (result.Value.status == DSNotifStatus.BUSY.ToString()) | |
{ | |
Debug.Log("Entering the game!"); | |
Debug.Log("Lobby OnSuccessMatch Connect"); | |
Debug.Log("ip: " + result.Value.ip + "port: " + result.Value.port); | |
MainThreadTaskRunner.Instance.Run(() => { StartCoroutine(WaitForGameServerReady(result.Value.ip, result.Value.port.ToString())); }); | |
} | |
Debug.Log("OnSuccessMatch ip: " + result.Value.ip + "port: " + result.Value.port); | |
lobbyLogic.WriteInDebugBox("Match Success status " + result.Value?.status + " isOK " + result.Value.isOK + " pod: " + result.Value.podName); | |
lobbyLogic.WriteInDebugBox("Match Success IP: " + result.Value.ip + " Port: " + result.Value.port); | |
ShowMatchmakingBoard(true, true); | |
abDSNotif = result.Value; | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment