using System; using Unity.Collections; using Unity.Netcode; using Unity.Netcode.Transports.UTP; using UnityEngine; using UnityEngine.SceneManagement; namespace Colosseum.Network { /// /// 로비 상태 관리. NetworkBehaviour로 플레이어 목록을 모든 클라이언트에 동기화. /// NetworkManager가 있는 오브젝트와 별개로 배치하거나 NetworkObject 컴포넌트 필요. /// public class LobbyManager : NetworkBehaviour { public static LobbyManager Instance { get; private set; } [Header("Game Scene")] [SerializeField] private string gameSceneName = "Test"; // 모든 클라이언트에 동기화되는 플레이어 목록 private NetworkList _players; public event Action OnPlayersChanged; // ─── 초기화 ─────────────────────────────────────────────── private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; _players = new NetworkList(); } public override void OnNetworkSpawn() { _players.OnListChanged += _ => OnPlayersChanged?.Invoke(); if (IsServer) { NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected; NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnected; } } public override void OnNetworkDespawn() { if (IsServer) { NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected; NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnected; } } // ─── 연결 제어 (클라이언트에서 호출) ───────────────────── /// 호스트 시작 public void StartHost(string ip, ushort port) { SetTransport(ip, port); NetworkManager.Singleton.StartHost(); } /// 클라이언트로 접속 public void StartClient(string ip, ushort port) { SetTransport(ip, port); NetworkManager.Singleton.StartClient(); } public void Disconnect() { NetworkManager.Singleton?.Shutdown(); } // ─── 플레이어 목록 ──────────────────────────────────────── public int PlayerCount => _players.Count; public LobbyPlayerData GetPlayer(int index) => _players[index]; private void OnClientConnected(ulong clientId) { AddPlayer(clientId); } private void OnClientDisconnected(ulong clientId) { for (int i = 0; i < _players.Count; i++) { if (_players[i].ClientId == clientId) { _players.RemoveAt(i); return; } } } private void AddPlayer(ulong clientId) { _players.Add(new LobbyPlayerData { ClientId = clientId, PlayerName = new FixedString32Bytes($"Player {clientId}"), IsReady = false }); } // ─── 준비 상태 ──────────────────────────────────────────── [Rpc(SendTo.Server)] public void SetReadyRpc(bool isReady, RpcParams rpcParams = default) { ulong clientId = rpcParams.Receive.SenderClientId; for (int i = 0; i < _players.Count; i++) { if (_players[i].ClientId == clientId) { var data = _players[i]; data.IsReady = isReady; _players[i] = data; return; } } } // ─── 게임 시작 ──────────────────────────────────────────── /// 호스트만 호출 가능. 모든 플레이어가 준비되어야 활성화 권장. public void StartGame() { if (!IsHost) return; NetworkManager.Singleton.SceneManager.LoadScene(gameSceneName, LoadSceneMode.Single); } // ─── 유틸 ───────────────────────────────────────────────── private void SetTransport(string ip, ushort port) { var transport = NetworkManager.Singleton?.GetComponent(); if (transport != null) transport.SetConnectionData(ip, port); } } }