- OnNetworkSpawn에서 호스트 수동 AddPlayer 호출 제거 - OnClientConnectedCallback이 호스트 접속 시에도 발동되므로 수동 추가 시 중복 등록되는 문제 해결 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
145 lines
5.1 KiB
C#
145 lines
5.1 KiB
C#
using System;
|
|
using Unity.Collections;
|
|
using Unity.Netcode;
|
|
using Unity.Netcode.Transports.UTP;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace Colosseum.Network
|
|
{
|
|
/// <summary>
|
|
/// 로비 상태 관리. NetworkBehaviour로 플레이어 목록을 모든 클라이언트에 동기화.
|
|
/// NetworkManager가 있는 오브젝트와 별개로 배치하거나 NetworkObject 컴포넌트 필요.
|
|
/// </summary>
|
|
public class LobbyManager : NetworkBehaviour
|
|
{
|
|
public static LobbyManager Instance { get; private set; }
|
|
|
|
[Header("Game Scene")]
|
|
[SerializeField] private string gameSceneName = "Test";
|
|
|
|
// 모든 클라이언트에 동기화되는 플레이어 목록
|
|
private NetworkList<LobbyPlayerData> _players;
|
|
|
|
public event Action OnPlayersChanged;
|
|
|
|
// ─── 초기화 ───────────────────────────────────────────────
|
|
private void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
Instance = this;
|
|
|
|
_players = new NetworkList<LobbyPlayerData>();
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// ─── 연결 제어 (클라이언트에서 호출) ─────────────────────
|
|
/// <summary>호스트 시작</summary>
|
|
public void StartHost(string ip, ushort port)
|
|
{
|
|
SetTransport(ip, port);
|
|
NetworkManager.Singleton.StartHost();
|
|
}
|
|
|
|
/// <summary>클라이언트로 접속</summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── 게임 시작 ────────────────────────────────────────────
|
|
/// <summary>호스트만 호출 가능. 모든 플레이어가 준비되어야 활성화 권장.</summary>
|
|
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<UnityTransport>();
|
|
if (transport != null)
|
|
transport.SetConnectionData(ip, port);
|
|
}
|
|
}
|
|
}
|