using UnityEngine; using Unity.Netcode; using System.Net.Sockets; using System.Net; using System; using System.Threading; namespace Northbound { /// /// Continuous port monitor - keeps checking if port is actually open /// Helps diagnose why Unity Netcode doesn't keep port open /// public class ContinuousPortMonitor : MonoBehaviour { [Header("Monitoring Settings")] [SerializeField] private ushort targetPort = 40445; [SerializeField] private bool startMonitoringOnStart = false; [SerializeField] private float checkInterval = 1f; [SerializeField] private int maxFailedChecksBeforeWarning = 5; [Header("Actions")] [SerializeField] private bool autoRestartBinding = true; [SerializeField] private bool keepTestListenerAlive = false; [Header("Debug")] [SerializeField] private bool verboseLogging = true; private NetworkManager _networkManager; private TcpListener _testListener; private Thread _listenerThread; private volatile bool _listenerRunning = false; private float _lastCheckTime; private int _failedCheckCount = 0; private bool _wasListeningPreviously = false; private void Start() { StartCoroutine(InitializeDelayed()); } private System.Collections.IEnumerator InitializeDelayed() { Debug.Log("[ContinuousPortMonitor] Waiting for NetworkManager..."); int attempts = 0; while (_networkManager == null && attempts < 50) { _networkManager = NetworkManager.Singleton; if (_networkManager == null) { yield return new WaitForSeconds(0.1f); attempts++; } } if (_networkManager == null) { Debug.LogError("[ContinuousPortMonitor] NetworkManager not found!"); yield break; } Debug.Log("[ContinuousPortMonitor] NetworkManager found!"); if (startMonitoringOnStart) { StartMonitoring(); } } [ContextMenu("Start Port Monitoring")] public void StartMonitoring() { Debug.Log("[ContinuousPortMonitor] Starting port monitoring for " + targetPort + ""); if (keepTestListenerAlive) { StartTestListener(); } Debug.Log("[ContinuousPortMonitor] Monitoring started - check interval: " + checkInterval + "s"); Debug.Log("[ContinuousPortMonitor] Will check if port remains accessible"); } [ContextMenu("Stop Port Monitoring")] public void StopMonitoring() { Debug.Log("[ContinuousPortMonitor] Stopping monitoring..."); StopTestListener(); enabled = false; } private void Update() { if (!enabled) return; if (Time.time - _lastCheckTime >= checkInterval) { _lastCheckTime = Time.time; CheckPortAccessibility(); } } private void CheckPortAccessibility() { bool isUnityServerRunning = _networkManager != null && _networkManager.IsServer; bool isCurrentlyListening = _listenerRunning || isUnityServerRunning; if (!verboseLogging) { // Only log when status changes if (isCurrentlyListening != _wasListeningPreviously) { _wasListeningPreviously = isCurrentlyListening; if (isCurrentlyListening) { Debug.Log("[ContinuousPortMonitor] ✓ Port " + targetPort + " is NOW ACCESSIBLE"); } else { Debug.LogWarning("[ContinuousPortMonitor] ⚠ Port " + targetPort + " became INACCESSIBLE"); } } return; } // Verbose logging if (isUnityServerRunning) { Debug.Log("[ContinuousPortMonitor] Unity Server: RUNNING"); } if (_listenerRunning) { Debug.Log("[ContinuousPortMonitor] Test Listener: RUNNING"); } bool portAccessible = TestPortConnection(); if (portAccessible) { _failedCheckCount = 0; if (Time.frameCount % 60 == 0) // Every second at 60fps { Debug.Log("[ContinuousPortMonitor] ✓ Port " + targetPort + " is accessible"); } } else { _failedCheckCount++; if (_failedCheckCount == 1) { Debug.LogWarning("[ContinuousPortMonitor] ⚠ Port " + targetPort + " became inaccessible"); } else if (_failedCheckCount % 10 == 0) { Debug.LogWarning("[ContinuousPortMonitor] ⚠ Port still inaccessible (check #" + _failedCheckCount + ")"); } if (_failedCheckCount >= maxFailedChecksBeforeWarning) { Debug.LogError("[ContinuousPortMonitor] ✗ Port has been inaccessible for " + _failedCheckCount + " checks!"); Debug.LogError("[ContinuousPortMonitor] This indicates a problem with port binding"); Debug.LogError("[ContinuousPortMonitor] Possible causes:"); Debug.LogError("1. Unity Netcode is not actually listening"); Debug.LogError("2. Another process is interfering"); Debug.LogError("3. NetworkManager has crashed/stopped"); if (autoRestartBinding) { Debug.Log("[ContinuousPortMonitor] Attempting to restore binding..."); TryRestoreBinding(); } } } } private bool TestPortConnection() { try { using (TcpClient client = new TcpClient("127.0.0.1", targetPort)) { return true; } } catch { return false; } } private void StartTestListener() { if (_listenerRunning) { Debug.LogWarning("[ContinuousPortMonitor] Test listener already running"); return; } _listenerRunning = true; _listenerThread = new Thread(new ThreadStart(ListenerThread)); _listenerThread.IsBackground = true; _listenerThread.Start(); Debug.Log("[ContinuousPortMonitor] Test listener started on port " + targetPort); } private void StopTestListener() { _listenerRunning = false; if (_testListener != null) { _testListener.Stop(); _testListener = null; } if (_listenerThread != null && _listenerThread.IsAlive) { _listenerThread.Join(1000); } Debug.Log("[ContinuousPortMonitor] Test listener stopped"); } private void ListenerThread() { try { _testListener = new TcpListener(IPAddress.Any, targetPort); _testListener.Start(); Debug.Log("[ContinuousPortMonitor] Test listener successfully bound to 0.0.0.0:" + targetPort); Debug.Log("[ContinuousPortMonitor] Port should now be accessible on yougetsignal"); while (_listenerRunning) { if (_testListener.Pending()) { try { TcpClient client = _testListener.AcceptTcpClient(); IPEndPoint endPoint = (IPEndPoint)client.Client.RemoteEndPoint; Debug.Log("[ContinuousPortMonitor] ✓ Connection received from " + endPoint.Address + ":" + endPoint.Port + ""); Debug.Log("[ContinuousPortMonitor] This proves port forwarding is working!"); Thread.Sleep(100); client.Close(); } catch (Exception e) { Debug.LogWarning("[ContinuousPortMonitor] Error accepting connection: " + e.Message); } } else { Thread.Sleep(100); } } Debug.Log("[ContinuousPortMonitor] Listener thread exiting"); } catch (Exception e) { _listenerRunning = false; Debug.LogError("[ContinuousPortMonitor] Listener error: " + e.Message + ""); } } private void TryRestoreBinding() { Debug.Log("[ContinuousPortMonitor] Attempting to restore port binding..."); // This is a placeholder - in reality, we'd need to restart Unity Netcode // But we can't do that safely from this script Debug.LogWarning("[ContinuousPortMonitor] Can't automatically restart Unity Netcode"); Debug.LogWarning("[ContinuousPortMonitor] Manual intervention required:"); Debug.LogWarning("1. Stop Host/Server"); Debug.LogWarning("2. Use ForceTransportBinding → 'Force Then Start Host'"); Debug.LogWarning("3. Check if port becomes accessible"); } [ContextMenu("Check Current Status")] public void CheckCurrentStatus() { Debug.Log("=== PORT MONITOR STATUS ==="); bool isUnityServerRunning = _networkManager != null && _networkManager.IsServer; bool isTestListenerRunning = _listenerRunning; bool portAccessible = TestPortConnection(); Debug.Log("Unity Server Running: " + isUnityServerRunning); Debug.Log("Test Listener Running: " + isTestListenerRunning); Debug.Log("Port Accessible: " + portAccessible); if (portAccessible) { Debug.Log("✓ Port " + targetPort + " is accessible"); } else { Debug.LogError("✗ Port " + targetPort + " is NOT accessible"); Debug.LogError("Check:"); Debug.LogError("1. Is Unity Netcode actually running?"); Debug.LogError("2. Is there a firewall blocking after some time?"); Debug.LogError("3. Is router restarting port forwarding?"); } Debug.Log("============================"); } [ContextMenu("Generate Diagnosis Report")] public void GenerateDiagnosisReport() { Debug.Log("=== PORT MONITOR DIAGNOSIS ==="); Debug.Log(""); Debug.Log("PROBLEM:"); Debug.Log("- PortListenerTest: WORKS (port accessible)"); Debug.Log("- After test ends: PORT INACCESSIBLE"); Debug.Log("- Unity Netcode: PORT INACCESSIBLE"); Debug.Log(""); Debug.Log("ANALYSIS:"); Debug.Log("1. Port forwarding: WORKING (proven by test)"); Debug.Log("2. Firewall: ALLOWING (proven by test)"); Debug.Log("3. Unity Netcode: NOT BINDING OR CRASHING"); Debug.Log(""); Debug.Log("POSSIBLE CAUSES:"); Debug.Log("1. Unity NetworkManager is not actually starting server"); Debug.Log("2. Player Prefab not assigned (server doesn't start)"); Debug.Log("3. Connection Approval rejecting all connections"); Debug.Log("4. NetworkConnectionHandler has error and stops server"); Debug.Log("5. Unity Netcode version bug"); Debug.Log(""); Debug.Log("CHECKLIST:"); Debug.Log("☐ NetworkManager → Player Prefab: ASSIGNED?"); Debug.Log("☐ NetworkManager → Connection Approval: CHECKED?"); Debug.Log("☐ NetworkConnectionHandler: IN SCENE?"); Debug.Log("☐ AutoHost: DISABLED or configured correctly?"); Debug.Log("☐ ForceTransportBinding: APPLIED?"); Debug.Log(""); Debug.Log("NEXT STEPS:"); Debug.Log("1. Add ForceTransportBinding to scene"); Debug.Log("2. Right-click → 'Force Then Start Host'"); Debug.Log("3. Watch Console for '✓ Server STARTED'"); Debug.Log("4. Immediately test on yougetsignal"); Debug.Log("5. If still closed: Check NetworkManager config"); Debug.Log("================================"); } private void OnDestroy() { StopTestListener(); } private void OnDisable() { StopMonitoring(); } } }