Files
Colosseum/Assets/_Game/Scripts/Network/LobbyManager.cs
dal4segno f73a2ca9d7 fix: 로비에서 호스트 Player 1 중복 표시 버그 수정
- OnNetworkSpawn에서 호스트 수동 AddPlayer 호출 제거
- OnClientConnectedCallback이 호스트 접속 시에도 발동되므로
  수동 추가 시 중복 등록되는 문제 해결

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:01:49 +09:00

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