using System.Collections; using UnityEngine; using UnityEngine.Networking; namespace Mirror.Cloud.ListServerService { public sealed class ListServerServerApi : ListServerBaseApi, IListServerServerApi { const int PingInterval = 20; const int MaxPingFails = 15; ServerJson currentServer; string serverId; Coroutine _pingCoroutine; /// /// If the server has already been added /// bool added; /// /// if a request is currently sending /// bool sending; /// /// If an update request was recently sent /// bool skipNextPing; /// /// How many failed pings in a row /// int pingFails = 0; public bool ServerInList => added; public ListServerServerApi(ICoroutineRunner runner, IRequestCreator requestCreator) : base(runner, requestCreator) { } public void Shutdown() { stopPingCoroutine(); if (added) { removeServerWithoutCoroutine(); } added = false; } public void AddServer(ServerJson server) { if (added) { Logger.LogWarning("AddServer called when server was already adding or added"); return; } bool valid = server.Validate(); if (!valid) { return; } runner.StartCoroutine(addServer(server)); } public void UpdateServer(int newPlayerCount) { if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); return; } currentServer.playerCount = newPlayerCount; UpdateServer(currentServer); } public void UpdateServer(ServerJson server) { // TODO, use PartialServerJson as Arg Instead if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); return; } PartialServerJson partialServer = new PartialServerJson { displayName = server.displayName, playerCount = server.playerCount, maxPlayerCount = server.maxPlayerCount, customData = server.customData, }; partialServer.Validate(); runner.StartCoroutine(updateServer(partialServer)); } public void RemoveServer() { if (!added) { return; } if (string.IsNullOrEmpty(serverId)) { Logger.LogWarning("Can not remove server because serverId was empty"); return; } stopPingCoroutine(); runner.StartCoroutine(removeServer()); } void stopPingCoroutine() { if (_pingCoroutine != null) { runner.StopCoroutine(_pingCoroutine); _pingCoroutine = null; } } IEnumerator addServer(ServerJson server) { added = true; sending = true; currentServer = server; UnityWebRequest request = requestCreator.Post("servers", currentServer); yield return requestCreator.SendRequestEnumerator(request, onSuccess, onFail); sending = false; void onSuccess(string responseBody) { CreatedIdJson created = JsonUtility.FromJson(responseBody); serverId = created.id; // Start ping to keep server alive _pingCoroutine = runner.StartCoroutine(ping()); } void onFail(string responseBody) { added = false; } } IEnumerator updateServer(PartialServerJson server) { // wait to not be sending while (sending) { yield return new WaitForSeconds(1); } // We need to check added incase Update is called soon after Add, and add failed if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); yield break; } sending = true; UnityWebRequest request = requestCreator.Patch("servers/" + serverId, server); yield return requestCreator.SendRequestEnumerator(request, onSuccess); sending = false; void onSuccess(string responseBody) { skipNextPing = true; if (_pingCoroutine == null) { _pingCoroutine = runner.StartCoroutine(ping()); } } } /// /// Keeps server alive in database /// /// IEnumerator ping() { while (pingFails <= MaxPingFails) { yield return new WaitForSeconds(PingInterval); if (skipNextPing) { skipNextPing = false; continue; } sending = true; UnityWebRequest request = requestCreator.Patch("servers/" + serverId, new EmptyJson()); yield return requestCreator.SendRequestEnumerator(request, onSuccess, onFail); sending = false; } Logger.LogWarning("Max ping fails reached, stoping to ping server"); _pingCoroutine = null; void onSuccess(string responseBody) { pingFails = 0; } void onFail(string responseBody) { pingFails++; } } IEnumerator removeServer() { sending = true; UnityWebRequest request = requestCreator.Delete("servers/" + serverId); yield return requestCreator.SendRequestEnumerator(request); sending = false; added = false; } void removeServerWithoutCoroutine() { if (string.IsNullOrEmpty(serverId)) { Logger.LogWarning("Can not remove server becuase serverId was empty"); return; } UnityWebRequest request = requestCreator.Delete("servers/" + serverId); UnityWebRequestAsyncOperation operation = request.SendWebRequest(); operation.completed += (op) => { Logger.LogResponse(request); }; } } }