using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Mirror; using UnityEngine; public class CupidConnector : MonoBehaviour { public kcp2k.KcpTransport transport; void Start() { #if UNITY_SERVER //Server code string[] args = Environment.GetCommandLineArgs(); int matchId = 0; string dedicatedSecret = null; bool dedicatedSecretFromCli = false; string internalApiBase = null; for (int i = 0; i < args.Length; i++) { if (args[i].Contains("-port") && i + 1 < args.Length) { Cupid.RoomPort = int.Parse(args[i + 1]); } if (i + 1 < args.Length) { if (string.Equals(args[i], "-matchId", StringComparison.OrdinalIgnoreCase) || string.Equals(args[i], "-matchid", StringComparison.OrdinalIgnoreCase)) int.TryParse(args[i + 1], out matchId); else if (string.Equals(args[i], "-dedicatedSecret", StringComparison.OrdinalIgnoreCase)) { dedicatedSecret = args[i + 1]; dedicatedSecretFromCli = true; } else if (string.Equals(args[i], "-internalApiBase", StringComparison.OrdinalIgnoreCase)) internalApiBase = args[i + 1]; } } if (!dedicatedSecretFromCli) { string envSecret = Environment.GetEnvironmentVariable("DEDICATED_SERVER_SECRET"); if (!string.IsNullOrEmpty(envSecret)) dedicatedSecret = envSecret; } GameManager.ConfigureDedicatedMatchReporting(matchId, dedicatedSecret, internalApiBase); #if UNITY_EDITOR Logger.Log("Editor mode, skipping arg check"); Cupid.RoomPort = 7777; matchId = 228; #else if(Cupid.RoomPort < 0){ Logger.Log("Invalid port, Did you pass the -port arguement?"); return; } if(matchId <=0){ Logger.Log("Invalid match id, Did you pass the -matchId arguement?"); return; } #endif Logger.SetFileName(matchId.ToString()); // Keep this component alive across server scene loads so timeout coroutine keeps running. DontDestroyOnLoad(gameObject); transport.Port = (ushort)Cupid.RoomPort; Logger.Log($"Starting server at port {Cupid.RoomPort}"); //StartCoroutine(PlayerTimeoutLoop()); NetworkManager.singleton.StartServer(); #else //Client code if (Cupid.RoomPort < 0) { Logger.Log("Invalid Room port"); return; } transport.Port = (ushort)Cupid.RoomPort; NetworkManager.singleton.networkAddress = Cupid.ServerAddress; Logger.Log($"Starting client at ${Cupid.ServerAddress}:{Cupid.RoomPort}"); NetworkManager.singleton.StartClient(); #endif } const float NoPlayersTimeoutSeconds = 45f; float noPlayersTimer = 0f; bool hasPlayerEverJoined = false; int lastCountdownLoggedSecond = -1; int lastObservedPlayerCount = -1; public static int GetActivePlayerConnectionCount() { if (NetworkServer.connections == null || NetworkServer.connections.Count == 0) return 0; // Mirror can keep dictionary entries around briefly; count only live/authenticated clients. return NetworkServer.connections.Values.Count(conn => conn != null && conn.isAuthenticated && conn.identity != null); } IEnumerator PlayerTimeoutLoop() { Logger.Log("Player timeout loop started"); while (true) { int activePlayers = 0; try{ activePlayers = GetActivePlayerConnectionCount(); if (activePlayers != lastObservedPlayerCount) { Logger.Log("Active player connections: " + activePlayers); lastObservedPlayerCount = activePlayers; } }catch(Exception e){ Logger.Log("Error getting active player connection count: " + e.Message); } if (activePlayers > 0) { hasPlayerEverJoined = true; noPlayersTimer = 0f; lastCountdownLoggedSecond = -1; yield return new WaitForSecondsRealtime(1f); continue; } noPlayersTimer += 1f; 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(); } yield return new WaitForSecondsRealtime(1f); } } void OnValidate() { if (GetComponent() != null) { GetComponent().headlessStartMode = HeadlessStartOptions.DoNothing; } if (transport == null) { transport = GetComponent(); } } }