네트워크 멀티플레이 테스트를 위한 코드 추가

This commit is contained in:
2026-02-03 13:18:50 +09:00
parent 3e874fb863
commit 775e1cffac
30 changed files with 2021 additions and 1835 deletions

View File

@@ -0,0 +1,365 @@
using UnityEngine;
using Unity.Netcode;
using System.Net.Sockets;
using System.Net;
using System;
using System.Threading;
namespace Northbound
{
/// <summary>
/// Continuous port monitor - keeps checking if port is actually open
/// Helps diagnose why Unity Netcode doesn't keep port open
/// </summary>
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("<color=cyan>[ContinuousPortMonitor] Starting port monitoring for " + targetPort + "</color>");
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("<color=green>[ContinuousPortMonitor] ✓ Port " + targetPort + " is NOW ACCESSIBLE</color>");
}
else
{
Debug.LogWarning("<color=yellow>[ContinuousPortMonitor] ⚠ Port " + targetPort + " became INACCESSIBLE</color>");
}
}
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("<color=green>[ContinuousPortMonitor] ✓ Port " + targetPort + " is accessible</color>");
}
}
else
{
_failedCheckCount++;
if (_failedCheckCount == 1)
{
Debug.LogWarning("<color=yellow>[ContinuousPortMonitor] ⚠ Port " + targetPort + " became inaccessible</color>");
}
else if (_failedCheckCount % 10 == 0)
{
Debug.LogWarning("<color=yellow>[ContinuousPortMonitor] ⚠ Port still inaccessible (check #" + _failedCheckCount + ")</color>");
}
if (_failedCheckCount >= maxFailedChecksBeforeWarning)
{
Debug.LogError("<color=red>[ContinuousPortMonitor] ✗ Port has been inaccessible for " + _failedCheckCount + " checks!</color>");
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("<color=cyan>[ContinuousPortMonitor] Attempting to restore binding...</color>");
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("<color=green>[ContinuousPortMonitor] ✓ Connection received from " + endPoint.Address + ":" + endPoint.Port + "</color>");
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("<color=red>[ContinuousPortMonitor] Listener error: " + e.Message + "</color>");
}
}
private void TryRestoreBinding()
{
Debug.Log("<color=cyan>[ContinuousPortMonitor] Attempting to restore port binding...</color>");
// 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("<color=green>✓ Port " + targetPort + " is accessible</color>");
}
else
{
Debug.LogError("<color=red>✗ Port " + targetPort + " is NOT accessible</color>");
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();
}
}
}