199 lines
6.0 KiB
C#
199 lines
6.0 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using Mirror;
|
|
using UnityEngine.Networking;
|
|
|
|
public class NetManager : NetworkManager
|
|
{
|
|
const float InitialReconnectDelaySeconds = 2f;
|
|
const float ReopenTriggerDelaySeconds = 15f;
|
|
[SerializeField] float reconnectIntervalSeconds = 15f;
|
|
Coroutine reconnectCoroutine;
|
|
bool reopenRequestedThisDisconnect;
|
|
bool reopenRequestInFlight;
|
|
|
|
[SerializeField] private CanvasGroup reconnectCanvasGroup;
|
|
|
|
static bool s_IntentionalClientDisconnect;
|
|
|
|
public static void MarkIntentionalClientDisconnect()
|
|
{
|
|
s_IntentionalClientDisconnect = true;
|
|
}
|
|
|
|
public override void OnApplicationQuit()
|
|
{
|
|
MarkIntentionalClientDisconnect();
|
|
StopReconnectLoop();
|
|
base.OnApplicationQuit();
|
|
}
|
|
|
|
public override void OnStopServer()
|
|
{
|
|
GameManager.ReportDedicatedMatchRoomClosed();
|
|
base.OnStopServer();
|
|
}
|
|
|
|
public override void OnClientConnect()
|
|
{
|
|
base.OnClientConnect();
|
|
Logger.Log("Client connected");
|
|
reopenRequestedThisDisconnect = false;
|
|
reopenRequestInFlight = false;
|
|
StopReconnectLoop();
|
|
}
|
|
|
|
public override void OnClientDisconnect()
|
|
{
|
|
base.OnClientDisconnect();
|
|
Logger.Log("Client disconnected");
|
|
if (ShouldReconnect())
|
|
{
|
|
if (reconnectCoroutine == null)
|
|
reconnectCoroutine = StartCoroutine(ReconnectLoopCoroutine());
|
|
else
|
|
SetReconnectCanvasVisible(true);
|
|
}
|
|
else
|
|
SetReconnectCanvasVisible(false);
|
|
}
|
|
|
|
public override void OnStopClient()
|
|
{
|
|
s_IntentionalClientDisconnect = false;
|
|
base.OnStopClient();
|
|
}
|
|
|
|
void StopReconnectLoop()
|
|
{
|
|
if (reconnectCoroutine == null)
|
|
{
|
|
SetReconnectCanvasVisible(false);
|
|
return;
|
|
}
|
|
|
|
StopCoroutine(reconnectCoroutine);
|
|
reconnectCoroutine = null;
|
|
SetReconnectCanvasVisible(false);
|
|
}
|
|
|
|
void SetReconnectCanvasVisible(bool visible)
|
|
{
|
|
if (reconnectCanvasGroup == null)
|
|
return;
|
|
reconnectCanvasGroup.alpha = visible ? 1f : 0f;
|
|
reconnectCanvasGroup.interactable = visible;
|
|
reconnectCanvasGroup.blocksRaycasts = visible;
|
|
}
|
|
|
|
IEnumerator ReconnectLoopCoroutine()
|
|
{
|
|
SetReconnectCanvasVisible(true);
|
|
reopenRequestedThisDisconnect = false;
|
|
reopenRequestInFlight = false;
|
|
float reconnectStartedAt = Time.realtimeSinceStartup;
|
|
float initialWaitEnd = Time.realtimeSinceStartup + InitialReconnectDelaySeconds;
|
|
while (ShouldReconnect() && Time.realtimeSinceStartup < initialWaitEnd)
|
|
yield return null;
|
|
|
|
while (ShouldReconnect())
|
|
{
|
|
if (!reopenRequestedThisDisconnect && !reopenRequestInFlight
|
|
&& Time.realtimeSinceStartup - reconnectStartedAt >= ReopenTriggerDelaySeconds)
|
|
{
|
|
reopenRequestedThisDisconnect = true;
|
|
StartCoroutine(CoRequestReopenForCurrentPort());
|
|
}
|
|
|
|
if (NetworkClient.active && !NetworkClient.isConnected)
|
|
{
|
|
StopClient();
|
|
yield return null;
|
|
continue;
|
|
}
|
|
|
|
if (!NetworkClient.active)
|
|
{
|
|
Logger.Log("Reconnect: attempting StartClient");
|
|
StartClient();
|
|
}
|
|
|
|
float waitEnd = Time.realtimeSinceStartup + reconnectIntervalSeconds;
|
|
while (ShouldReconnect() && Time.realtimeSinceStartup < waitEnd)
|
|
yield return null;
|
|
}
|
|
|
|
reconnectCoroutine = null;
|
|
SetReconnectCanvasVisible(false);
|
|
}
|
|
|
|
bool ShouldReconnect()
|
|
{
|
|
if (s_IntentionalClientDisconnect)
|
|
return false;
|
|
if (NetworkServer.active)
|
|
return false;
|
|
if (NetworkClient.isConnected)
|
|
return false;
|
|
if (GameManager.instance != null && GameManager.instance.isGameEnded)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
IEnumerator CoRequestReopenForCurrentPort()
|
|
{
|
|
reopenRequestInFlight = true;
|
|
|
|
int port = Cupid.RoomPort;
|
|
if (port <= 0)
|
|
{
|
|
Logger.Log("Reconnect: skipping /reopen because room port is invalid");
|
|
reopenRequestInFlight = false;
|
|
yield break;
|
|
}
|
|
|
|
string baseUri = Cupid.CupidURI;
|
|
string password = Cupid.SettingsPassword;
|
|
if (string.IsNullOrWhiteSpace(baseUri) || string.IsNullOrEmpty(password))
|
|
{
|
|
Logger.Log("Reconnect: skipping /reopen because Cupid URI/password is not available");
|
|
reopenRequestInFlight = false;
|
|
yield break;
|
|
}
|
|
|
|
string query = "?password=" + UnityWebRequest.EscapeURL(password) + "&port=" + port;
|
|
string[] endpointCandidates =
|
|
{
|
|
baseUri.TrimEnd('/') + "/internal/admin/reopen" + query,
|
|
baseUri.TrimEnd('/') + "/reopen" + query
|
|
};
|
|
|
|
bool success = false;
|
|
for (int i = 0; i < endpointCandidates.Length; i++)
|
|
{
|
|
string url = endpointCandidates[i];
|
|
using (UnityWebRequest req = UnityWebRequest.Get(url))
|
|
{
|
|
req.downloadHandler = new DownloadHandlerBuffer();
|
|
yield return req.SendWebRequest();
|
|
string body = req.downloadHandler != null ? req.downloadHandler.text : "";
|
|
|
|
if (req.result == UnityWebRequest.Result.Success && req.responseCode >= 200 && req.responseCode < 300)
|
|
{
|
|
Logger.Log("Reconnect: /reopen success on port " + port + ". Response: " + body);
|
|
success = true;
|
|
break;
|
|
}
|
|
|
|
Logger.Log("Reconnect: /reopen failed at " + url + " status " + req.responseCode + " error: " + req.error + " body: " + body);
|
|
}
|
|
}
|
|
|
|
if (!success)
|
|
Logger.Log("Reconnect: all /reopen endpoint attempts failed.");
|
|
|
|
reopenRequestInFlight = false;
|
|
}
|
|
}
|