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);
}
}
}