using System.Collections.Generic; using System.Linq; using Unity.Netcode; using UnityEngine; namespace Northbound { /// /// 네트워크 연결 및 스폰 관리 /// public class NetworkConnectionHandler : MonoBehaviour { [Header("Spawn Settings")] public List spawnPoints = new List(); public bool useRandomSpawn = false; public bool findSpawnPointsAutomatically = true; private Dictionary _clientSpawnIndices = new Dictionary(); private int _nextSpawnIndex = 0; // ⭐ Awake에서 스폰 포인트 먼저 찾고, 콜백 등록 private void Awake() { // 1️⃣ 먼저 스폰 포인트 찾기 if (findSpawnPointsAutomatically) { FindSpawnPoints(); } // 2️⃣ 그 다음 콜백 등록 if (NetworkManager.Singleton != null) { NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck; NetworkManager.Singleton.OnServerStarted += OnServerStarted; NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected; Debug.Log("[Connection] ConnectionApprovalCallback 등록됨"); } else { Debug.LogError("[Connection] NetworkManager.Singleton이 null입니다!"); } } private void FindSpawnPoints() { PlayerSpawnPoint[] points = FindObjectsByType(FindObjectsSortMode.None); // spawnIndex로 정렬 var sortedPoints = points.OrderBy(p => p.spawnIndex == -1 ? int.MaxValue : p.spawnIndex); spawnPoints.Clear(); foreach (var point in sortedPoints) { if (point != null && point.transform != null && point.isAvailable) { spawnPoints.Add(point.transform); } } Debug.Log($"[Connection] {spawnPoints.Count}개의 스폰 포인트를 찾았습니다."); } private void OnServerStarted() { Debug.Log("[Connection] 서버 시작됨"); if (ServerResourceManager.Instance == null) { GameObject resourceManagerObj = new GameObject("ServerResourceManager"); ServerResourceManager manager = resourceManagerObj.AddComponent(); NetworkObject networkObject = resourceManagerObj.GetComponent(); if (networkObject == null) { networkObject = resourceManagerObj.AddComponent(); } networkObject.Spawn(); Debug.Log("[Connection] ServerResourceManager spawned."); } if (NetworkManager.Singleton.IsHost) { SpawnPlayer(NetworkManager.Singleton.LocalClientId); } } private void OnClientConnected(ulong clientId) { if (!NetworkManager.Singleton.IsServer) return; if (clientId == NetworkManager.Singleton.LocalClientId) return; Debug.Log($"[Connection] 클라이언트 {clientId} 연결됨"); if (!NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var client) || client.PlayerObject != null) { Debug.Log($"[Connection] 클라이언트 {clientId}의 플레이어가 이미 존재합니다."); return; } SpawnPlayer(clientId); } private void SpawnPlayer(ulong clientId) { Vector3 spawnPosition = GetSpawnPosition(clientId); Quaternion spawnRotation = GetSpawnRotation(clientId); GameObject playerPrefab = NetworkManager.Singleton.NetworkConfig.PlayerPrefab; if (playerPrefab == null) { Debug.LogError("[Connection] PlayerPrefab이 null입니다!"); return; } GameObject playerObject = Instantiate(playerPrefab, spawnPosition, spawnRotation); NetworkObject networkObject = playerObject.GetComponent(); if (networkObject == null) { Debug.LogError("[Connection] PlayerPrefab에 NetworkObject가 없습니다!"); return; } networkObject.SpawnAsPlayerObject(clientId); Debug.Log($"[Connection] 플레이어 {clientId} 스폰됨: {spawnPosition}"); } private void ApprovalCheck( NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) { spawnPoints.RemoveAll(p => p == null); if (spawnPoints.Count == 0) { Debug.LogError($"[Connection] 스폰 포인트가 없습니다! 씬에 PlayerSpawnPoint가 있는지 확인하세요."); } response.Approved = true; response.CreatePlayerObject = false; response.Position = Vector3.zero; response.Rotation = Quaternion.identity; Debug.Log($"[Connection] 클라이언트 {request.ClientNetworkId} 승인됨. 수동 스폰으로 대기."); } private Vector3 GetSpawnPosition(ulong clientId) { spawnPoints.RemoveAll(p => p == null); if (spawnPoints.Count == 0) { Debug.LogWarning("[Connection] 스폰 포인트가 없습니다. 기본 위치 반환."); return Vector3.zero; } int spawnIndex; if (useRandomSpawn) { spawnIndex = Random.Range(0, spawnPoints.Count); } else { if (!_clientSpawnIndices.ContainsKey(clientId)) { _clientSpawnIndices[clientId] = _nextSpawnIndex; _nextSpawnIndex = (_nextSpawnIndex + 1) % spawnPoints.Count; } spawnIndex = _clientSpawnIndices[clientId]; if (spawnIndex >= spawnPoints.Count) { Debug.LogWarning($"[Connection] 스폰 인덱스 {spawnIndex}가 범위를 벗어났습니다. 기본값으로 조정."); spawnIndex = spawnIndex % spawnPoints.Count; } } Debug.Log($"[Connection] 클라이언트 {clientId}에게 스폰 인덱스 {spawnIndex} 할당"); return spawnPoints[spawnIndex].position; } private Quaternion GetSpawnRotation(ulong clientId) { spawnPoints.RemoveAll(p => p == null); if (spawnPoints.Count == 0) return Quaternion.identity; int spawnIndex = _clientSpawnIndices.ContainsKey(clientId) ? _clientSpawnIndices[clientId] : 0; if (spawnIndex >= spawnPoints.Count) { spawnIndex = spawnIndex % spawnPoints.Count; } return spawnPoints[spawnIndex].rotation; } private void OnDestroy() { if (NetworkManager.Singleton != null) { NetworkManager.Singleton.ConnectionApprovalCallback = null; NetworkManager.Singleton.OnServerStarted -= OnServerStarted; NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected; } } } }