reconnect, 30% fixes from test feedback
This commit is contained in:
@@ -81,10 +81,12 @@ public class GameCanvas : MonoBehaviour
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
redName.text = GameManager.RedPlayer.Name;
|
||||
blueName.text = GameManager.BluePlayer.Name;
|
||||
|
||||
}catch{
|
||||
Logger.Log("Failed to fetch red and blue names, isServer?");
|
||||
}
|
||||
}
|
||||
|
||||
void OnEmoteTextPressed(string txtName){
|
||||
@@ -164,7 +166,10 @@ public class GameCanvas : MonoBehaviour
|
||||
LoginManager.ClearMatchYourTeam();
|
||||
|
||||
if (NetworkManager.singleton != null && NetworkClient.active)
|
||||
{
|
||||
NetManager.MarkIntentionalClientDisconnect();
|
||||
NetworkManager.singleton.StopClient();
|
||||
}
|
||||
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
}
|
||||
|
||||
@@ -106,6 +106,12 @@ public class GameManager : NetworkBehaviour
|
||||
public float puckDragClampMax = 5f;
|
||||
public float puckDragMinClamp = 1f;
|
||||
|
||||
[Header("Field bounds")]
|
||||
[Tooltip("Pitch width (X). Length (Y) is fieldSize × 2. Origin-centered; used for boundary-based camera zoom while dragging.")]
|
||||
public float fieldSize = 10f;
|
||||
[Tooltip("Exponent on distance-to-boundary (0–1). >1 = subtle at center, ramps up mostly near the boundary; 1 = linear.")]
|
||||
[Min(0.01f)] public float cameraStretchBoundaryExponent = 2.5f;
|
||||
|
||||
[SyncVar(hook = nameof(OnScoreChanged))]
|
||||
public int redScore=0;
|
||||
[SyncVar(hook = nameof(OnScoreChanged))]
|
||||
@@ -161,6 +167,50 @@ public class GameManager : NetworkBehaviour
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blends from <paramref name="centerMultiplier"/> at the pitch center to <paramref name="boundaryMultiplier"/>
|
||||
/// at the boundary (and beyond), using the max normalized axis distance inside the field rectangle.
|
||||
/// </summary>
|
||||
public float GetCameraStretchDistanceMultiplier(Vector3 puckWorldPosition, float centerMultiplier = 0.3f, float boundaryMultiplier = 1f)
|
||||
{
|
||||
if (fieldSize <= Mathf.Epsilon)
|
||||
return boundaryMultiplier;
|
||||
|
||||
float halfWidth = fieldSize * 0.5f;
|
||||
float halfHeight = fieldSize;
|
||||
|
||||
float nx = Mathf.Abs(puckWorldPosition.x) / halfWidth;
|
||||
float ny = Mathf.Abs(puckWorldPosition.y) / halfHeight;
|
||||
float t = Mathf.Clamp01(Mathf.Max(nx, ny));
|
||||
float shaped = Mathf.Pow(t, cameraStretchBoundaryExponent);
|
||||
return Mathf.Lerp(centerMultiplier, boundaryMultiplier, shaped);
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (fieldSize <= Mathf.Epsilon)
|
||||
return;
|
||||
|
||||
float halfWidth = fieldSize * 0.5f;
|
||||
float halfHeight = fieldSize;
|
||||
Vector3 c = Vector3.zero;
|
||||
Vector3 right = new Vector3(halfWidth, 0f, 0f);
|
||||
Vector3 up = new Vector3(0f, halfHeight, 0f);
|
||||
|
||||
Vector3 a = c - right - up;
|
||||
Vector3 b = c + right - up;
|
||||
Vector3 d = c + right + up;
|
||||
Vector3 e = c - right + up;
|
||||
|
||||
Color prev = Gizmos.color;
|
||||
Gizmos.color = new Color(1f, 0.92f, 0.016f, 0.85f);
|
||||
Gizmos.DrawLine(a, b);
|
||||
Gizmos.DrawLine(b, d);
|
||||
Gizmos.DrawLine(d, e);
|
||||
Gizmos.DrawLine(e, a);
|
||||
Gizmos.color = prev;
|
||||
}
|
||||
|
||||
/// <summary>Server-only: called from <see cref="NetPlayer.CmdSetTeam"/> after <c>myTeam</c> is set.</summary>
|
||||
public void OnMatchPlayerTeamAssigned(Team team)
|
||||
{
|
||||
@@ -226,6 +276,9 @@ public class GameManager : NetworkBehaviour
|
||||
yield return DedicatedMatchPatchWinner(DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, winner);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
GameEvents.OnSelectedPuckChanged?.Invoke(null);
|
||||
@@ -547,10 +600,12 @@ public class GameManager : NetworkBehaviour
|
||||
blueScore++;
|
||||
blueScoreText.text = blueScore.ToString();
|
||||
PlayGoalEffects(Team.Blue);
|
||||
Logger.Log($"Blue goal scored, blue score is now {blueScore}");
|
||||
}else{
|
||||
redScore++;
|
||||
redScoreText.text = redScore.ToString();
|
||||
PlayGoalEffects(Team.Red);
|
||||
Logger.Log($"Red goal scored, red score is now {redScore}");
|
||||
}
|
||||
|
||||
SetKickoffTeam(concedingTeam);
|
||||
@@ -632,6 +687,7 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
|
||||
public void Leave(){
|
||||
NetManager.MarkIntentionalClientDisconnect();
|
||||
StopClient();
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public class MainMenuManager : MonoBehaviour
|
||||
public Button btnPaste;
|
||||
public TMP_InputField inputCryptoAddress;
|
||||
public TMP_Text txtWithdrawStatus;
|
||||
private bool isCoinBuyInProgress;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
@@ -146,14 +147,33 @@ public class MainMenuManager : MonoBehaviour
|
||||
}
|
||||
|
||||
void OnBuy(string packId){
|
||||
if (isCoinBuyInProgress)
|
||||
return;
|
||||
|
||||
isCoinBuyInProgress = true;
|
||||
SetCoinBuyButtonsInteractable(false);
|
||||
|
||||
LoginManager.instance.PurchaseRcPack(packId, (success, error) => {
|
||||
if(success){
|
||||
OnUserUpdated(LoginManager.CurrentUser);
|
||||
AudioManager.instance.PlayCoinsSfx();
|
||||
}
|
||||
|
||||
isCoinBuyInProgress = false;
|
||||
SetCoinBuyButtonsInteractable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void SetCoinBuyButtonsInteractable(bool interactable)
|
||||
{
|
||||
if (btnBuyUsd5 != null)
|
||||
btnBuyUsd5.interactable = interactable;
|
||||
if (btnBuyUsd20 != null)
|
||||
btnBuyUsd20.interactable = interactable;
|
||||
if (btnBuyUsd50 != null)
|
||||
btnBuyUsd50.interactable = interactable;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
LoginManager.OnUserDataUpdated -= OnUserUpdated;
|
||||
|
||||
+146
-21
@@ -1,11 +1,32 @@
|
||||
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()
|
||||
{
|
||||
@@ -13,37 +34,103 @@ public class NetManager : NetworkManager
|
||||
base.OnStopServer();
|
||||
}
|
||||
|
||||
public override void OnStopClient()
|
||||
{
|
||||
base.OnStopClient();
|
||||
TryStartReconnectLoop();
|
||||
}
|
||||
|
||||
public override void OnClientConnect()
|
||||
{
|
||||
base.OnClientConnect();
|
||||
Logger.Log("Client connected");
|
||||
reopenRequestedThisDisconnect = false;
|
||||
reopenRequestInFlight = false;
|
||||
StopReconnectLoop();
|
||||
}
|
||||
|
||||
void TryStartReconnectLoop()
|
||||
public override void OnClientDisconnect()
|
||||
{
|
||||
if (!ShouldReconnect() || reconnectCoroutine != null)
|
||||
return;
|
||||
base.OnClientDisconnect();
|
||||
Logger.Log("Client disconnected");
|
||||
if (ShouldReconnect())
|
||||
{
|
||||
if (reconnectCoroutine == null)
|
||||
reconnectCoroutine = StartCoroutine(ReconnectLoopCoroutine());
|
||||
else
|
||||
SetReconnectCanvasVisible(true);
|
||||
}
|
||||
else
|
||||
SetReconnectCanvasVisible(false);
|
||||
}
|
||||
|
||||
reconnectCoroutine = StartCoroutine(CoroutineReconnectLoop());
|
||||
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)
|
||||
@@ -54,20 +141,58 @@ public class NetManager : NetworkManager
|
||||
return true;
|
||||
}
|
||||
|
||||
IEnumerator CoroutineReconnectLoop()
|
||||
IEnumerator CoRequestReopenForCurrentPort()
|
||||
{
|
||||
while (ShouldReconnect())
|
||||
{
|
||||
if (!NetworkClient.active)
|
||||
{
|
||||
Debug.Log("Client disconnected. Reconnecting...");
|
||||
StartClient();
|
||||
yield return new WaitForSeconds(reconnectIntervalSeconds);
|
||||
}
|
||||
reopenRequestInFlight = true;
|
||||
|
||||
yield return new WaitForSeconds(1);
|
||||
int port = Cupid.RoomPort;
|
||||
if (port <= 0)
|
||||
{
|
||||
Logger.Log("Reconnect: skipping /reopen because room port is invalid");
|
||||
reopenRequestInFlight = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
reconnectCoroutine = null;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class NetPlayer : NetworkBehaviour
|
||||
[Command]
|
||||
void CmdSetTeam(Team team){
|
||||
setMyTeam(team);
|
||||
|
||||
Logger.Log($"Client {netId} set team to {team}");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +69,7 @@ public class NetPlayer : NetworkBehaviour
|
||||
void CmdSendTextEmote(string txtName){
|
||||
RpcSendTextEmote(txtName);
|
||||
ShowTextEmote(txtName);
|
||||
Logger.Log($"Client {netId} sent text emote {txtName}");
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
@@ -92,6 +95,8 @@ public class NetPlayer : NetworkBehaviour
|
||||
void CmdSendEmojiEmote(int id){
|
||||
RpcSendEmojiEmote(id);
|
||||
ShowEmojiEmote(id);
|
||||
|
||||
Logger.Log($"Client {netId} sent emoji emote {id}");
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
|
||||
@@ -69,7 +69,9 @@ public class Puck : NetworkBehaviour
|
||||
&& team == NetPlayer.localPlayer.myTeam
|
||||
&& GameManager.instance.SelectedTeam == team)
|
||||
{
|
||||
CameraEffects.instance.SetStretchFactor(lineEnd.magnitude / clamp);
|
||||
float baseStretch = lineEnd.magnitude / clamp;
|
||||
float distanceMultiplier = GameManager.instance.GetCameraStretchDistanceMultiplier(transform.position);
|
||||
CameraEffects.instance.SetStretchFactor(baseStretch * distanceMultiplier);
|
||||
}
|
||||
|
||||
// Only two points for the line
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
public class ServerAutoClose : MonoBehaviour
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
|
||||
void Start()
|
||||
{
|
||||
Logger.Log("Starting auto close watchdog");
|
||||
}
|
||||
|
||||
int lastObservedPlayerCount = -1;
|
||||
bool hasPlayerEverJoined = false;
|
||||
float noPlayersTimer = 0f;
|
||||
int lastCountdownLoggedSecond = -1;
|
||||
const float NoPlayersTimeoutSeconds = 65f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
int activePlayers = 0;
|
||||
try
|
||||
{
|
||||
activePlayers = CupidConnector.GetActivePlayerConnectionCount();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log("Error getting active player connection count: " + e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activePlayers != lastObservedPlayerCount)
|
||||
{
|
||||
Logger.Log("Active player connections: " + activePlayers);
|
||||
lastObservedPlayerCount = activePlayers;
|
||||
}
|
||||
|
||||
if (activePlayers > 0)
|
||||
{
|
||||
hasPlayerEverJoined = true;
|
||||
noPlayersTimer = 0f;
|
||||
lastCountdownLoggedSecond = -1;
|
||||
}
|
||||
|
||||
noPlayersTimer += Time.deltaTime;
|
||||
int secondsRemaining = Mathf.CeilToInt(NoPlayersTimeoutSeconds - noPlayersTimer);
|
||||
if (secondsRemaining > 0 && secondsRemaining % 10 == 0 && secondsRemaining != lastCountdownLoggedSecond)
|
||||
{
|
||||
lastCountdownLoggedSecond = secondsRemaining;
|
||||
Logger.Log("Server will be closed due to no players in, " + secondsRemaining);
|
||||
}
|
||||
|
||||
if (noPlayersTimer >= NoPlayersTimeoutSeconds)
|
||||
{
|
||||
if (hasPlayerEverJoined)
|
||||
Logger.Log("All players left, exiting");
|
||||
else
|
||||
Logger.Log("No players joined, exiting");
|
||||
GameManager.ReportDedicatedMatchRoomClosed();
|
||||
Application.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c10a35ed198fa2941b2b28a03c558897
|
||||
@@ -0,0 +1,29 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(TMP_Text))]
|
||||
public class LoadingTextTMP : MonoBehaviour
|
||||
{
|
||||
public string baseText = "Loading";
|
||||
public char dotChar = '.';
|
||||
public int dotCount =3;
|
||||
public float interval = 1f;
|
||||
TMP_Text txt;
|
||||
void Start()
|
||||
{
|
||||
txt = GetComponent<TMP_Text>();
|
||||
}
|
||||
|
||||
|
||||
float timer = 0;
|
||||
void Update(){
|
||||
timer += Time.deltaTime;
|
||||
if(timer > interval * dotCount){
|
||||
timer =0;
|
||||
}
|
||||
|
||||
int dots = (int)(timer / interval);
|
||||
|
||||
txt.text = baseText + new string(dotChar, dots);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 093b12f4aa5fb0446a9c1aa544025970
|
||||
Reference in New Issue
Block a user