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; } else { } } 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); } } } private void OnServerStarted() { 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(); } if (NetworkManager.Singleton.IsHost) { SpawnPlayer(NetworkManager.Singleton.LocalClientId); } } private void OnClientConnected(ulong clientId) { if (!NetworkManager.Singleton.IsServer) return; if (clientId == NetworkManager.Singleton.LocalClientId) return; if (!NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var client) || client.PlayerObject != null) { 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) { return; } GameObject playerObject = Instantiate(playerPrefab, spawnPosition, spawnRotation); NetworkObject networkObject = playerObject.GetComponent(); if (networkObject == null) { return; } // 서버 소유권으로 스폰 networkObject.SpawnWithOwnership(NetworkManager.ServerClientId); // 플레이어 컨트롤러 초기화 var playerController = playerObject.GetComponent(); if (playerController != null) { playerController.Initialize(clientId); } } private void ApprovalCheck( NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) { spawnPoints.RemoveAll(p => p == null); if (spawnPoints.Count == 0) { } response.Approved = true; response.CreatePlayerObject = false; response.Position = Vector3.zero; response.Rotation = Quaternion.identity; } private Vector3 GetSpawnPosition(ulong clientId) { spawnPoints.RemoveAll(p => p == null); if (spawnPoints.Count == 0) { 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) { spawnIndex = spawnIndex % spawnPoints.Count; } } 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; } } } }