Files
Northbound/Assets/Scripts/NetworkConnectionHandler.cs
dal4segno 4ffbbb0aff 모든 네트워크 오브젝트의 소유권을 서버가 갖도록 함
Distributable -> None
관련 사이드 이펙트로 인한 버그 수정
2026-02-18 02:18:42 +09:00

203 lines
6.6 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Linq;
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 네트워크 연결 및 스폰 관리
/// </summary>
public class NetworkConnectionHandler : MonoBehaviour
{
[Header("Spawn Settings")]
public List<Transform> spawnPoints = new List<Transform>();
public bool useRandomSpawn = false;
public bool findSpawnPointsAutomatically = true;
private Dictionary<ulong, int> _clientSpawnIndices = new Dictionary<ulong, int>();
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<PlayerSpawnPoint>(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<ServerResourceManager>();
NetworkObject networkObject = resourceManagerObj.GetComponent<NetworkObject>();
if (networkObject == null)
{
networkObject = resourceManagerObj.AddComponent<NetworkObject>();
}
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<NetworkObject>();
if (networkObject == null)
{
return;
}
// 서버 소유권으로 스폰
networkObject.SpawnWithOwnership(NetworkManager.ServerClientId);
// 플레이어 컨트롤러 초기화
var playerController = playerObject.GetComponent<NetworkPlayerController>();
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;
}
}
}
}