This commit is contained in:
2026-04-30 15:08:19 +07:00
parent 2c0ec5ab1c
commit c2b0e96570
8 changed files with 416 additions and 117 deletions

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -19,6 +19,10 @@ namespace Hallucinate.UI
public event Action OnJoinStartedEvent;
public event Action OnJoinFailedEvent;
[Header(""Prefabs"")]
[SerializeField] private NetworkPrefabRef _playerPrefab;
[SerializeField] private NetworkPrefabRef _playerDataManagerPrefab;
private void Awake()
{
if (Instance != null && Instance != this)
@@ -62,22 +66,23 @@ namespace Hallucinate.UI
{
await EnsureRunnerExists();
if (_runner.SessionInfo.IsValid) return;
var result = await _runner.JoinSessionLobby(SessionLobby.ClientServer);
if (!result.Ok)
{
Debug.LogError($"Failed to join lobby: {result.ShutdownReason}. Check AppID type or Network/Firewall.");
Debug.LogWarning($""Join lobby result: {result.ShutdownReason}. This is often normal on first run if already connecting."");
}
}
public async Task<bool> StartHost(string sessionName, string password = null)
public async Task<bool> StartHost(string sessionName, string displayName, string password = null)
{
OnJoinStartedEvent?.Invoke();
// 1. Kiểm tra Build Settings
bool sceneExists = false;
for (int i = 0; i < UnityEngine.SceneManagement.SceneManager.sceneCountInBuildSettings; i++)
{
if (UnityEngine.SceneManagement.SceneUtility.GetScenePathByBuildIndex(i).Contains("Main Scene"))
if (UnityEngine.SceneManagement.SceneUtility.GetScenePathByBuildIndex(i).Contains(""Main Scene""))
{
sceneExists = true;
break;
@@ -86,18 +91,18 @@ namespace Hallucinate.UI
if (!sceneExists)
{
Debug.LogError("CRITICAL: 'Main Scene' is NOT in Build Settings!");
Debug.LogError(""CRITICAL: 'Main Scene' is NOT in Build Settings!"");
return false;
}
// 2. Khởi tạo Runner mới sạch sẽ
await EnsureRunnerExists();
var customProps = new Dictionary<string, SessionProperty>();
if (!string.IsNullOrEmpty(password))
{
customProps.Add("pw", password);
customProps.Add(""pw"", password);
}
customProps.Add(""rn"", displayName);
var result = await _runner.StartGame(new StartGameArgs()
{
@@ -105,18 +110,23 @@ namespace Hallucinate.UI
SessionName = sessionName,
SessionProperties = customProps,
PlayerCount = 2,
// Thêm fixed region để tránh timeout khi tìm server
// SceneManager sẽ tự động add nếu thiếu
SceneManager = gameObject.GetComponent<NetworkSceneManagerDefault>() ?? gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (result.Ok)
{
if (_runner.IsServer && _playerDataManagerPrefab.IsValid)
{
if (FindFirstObjectByType<PlayerDataManager>() == null)
{
_runner.Spawn(_playerDataManagerPrefab, Vector3.zero, Quaternion.identity, null);
}
}
return true;
}
else
{
Debug.LogError($"Fusion StartHost Failed: {result.ShutdownReason}.");
Debug.LogError($""Fusion StartHost Failed: {result.ShutdownReason}."");
OnJoinFailedEvent?.Invoke();
return false;
}
@@ -140,39 +150,54 @@ namespace Hallucinate.UI
}
else
{
Debug.LogError($"Fusion StartClient Failed: {result.ShutdownReason}");
Debug.LogError($""Fusion StartClient Failed: {result.ShutdownReason}"");
OnJoinFailedEvent?.Invoke();
return false;
}
}
// --- Các phương thức Callbacks ---
[SerializeField] private NetworkPrefabRef _playerPrefab;
private Dictionary<PlayerRef, NetworkObject> _spawnedCharacters = new Dictionary<PlayerRef, NetworkObject>();
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
if (player == runner.LocalPlayer)
{
var pdm = FindFirstObjectByType<PlayerDataManager>();
if (pdm != null)
SendLocalMetaData(player);
}
}
private async void SendLocalMetaData(PlayerRef player)
{
PlayerDataManager pdm = null;
int retries = 0;
while (pdm == null && retries < 20)
{
pdm = FindFirstObjectByType<PlayerDataManager>();
if (pdm != null) break;
await Task.Delay(500);
retries++;
}
if (pdm != null)
{
string playerName = LocalPlayerProfile != null ? LocalPlayerProfile.Name : ""Player "" + player.PlayerId;
// Thêm hậu tố (HOST) nếu là server để dễ phân biệt
if (_runner.IsServer) playerName += "" (HOST)"";
_Role playerRole = _Role.Seeker;
var metaData = new _PlayerMetaData()
{
string playerName = "Player";
_Role playerRole = _Role.Seeker;
if (LocalPlayerProfile != null)
{
playerName = LocalPlayerProfile.Name;
}
var metaData = new _PlayerMetaData()
{
Name = playerName,
Role = playerRole,
IsReady = false
};
pdm.RPC_UpdatePlayerMetaData(player, metaData);
}
Name = playerName,
Role = playerRole,
IsReady = false
};
pdm.RPC_UpdatePlayerMetaData(player, metaData);
}
else
{
Debug.LogError(""[BasicSpawner] Could not find PlayerDataManager after retries. Data will not sync."");
}
}
@@ -180,7 +205,7 @@ namespace Hallucinate.UI
{
if (_runner != null && _runner.IsServer)
{
_runner.LoadScene("Main Scene");
_runner.LoadScene(""Main Scene"");
}
}
@@ -190,18 +215,23 @@ namespace Hallucinate.UI
{
runner.Despawn(networkObject);
_spawnedCharacters.Remove(player);
// Chỉ Shutdown nếu người thoát chính là Server (Host)
if (runner.IsServer && player == runner.LocalPlayer)
{
runner.Shutdown();
}
}
if (runner.IsServer && player == runner.LocalPlayer)
{
runner.Shutdown();
}
}
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason)
{
Debug.LogWarning($"[Fusion] Shutdown occurred. Reason: {shutdownReason}");
Debug.LogWarning($""[Fusion] Shutdown occurred. Reason: {shutdownReason}"");
OnShutdownEvent?.Invoke(shutdownReason.ToString());
if (UIManager.Instance != null)
{
UIManager.Instance.OnBackToMenu();
}
}
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
@@ -238,7 +268,7 @@ namespace Hallucinate.UI
public void OnSceneLoadDone(NetworkRunner runner)
{
string currentSceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
if (runner.IsServer && currentSceneName == "Main Scene")
if (runner.IsServer && currentSceneName == ""Main Scene"")
{
foreach (var player in runner.ActivePlayers)
{
@@ -247,9 +277,9 @@ namespace Hallucinate.UI
_spawnedCharacters.Add(player, networkPlayerObject);
}
}
if (currentSceneName == "Main Scene")
if (currentSceneName == ""Main Scene"")
UIManager.Instance?.OnGameStarted();
else if (currentSceneName == "Lobby" || currentSceneName == "Menu")
else if (currentSceneName == ""Lobby"" || currentSceneName == ""Menu"")
UIManager.Instance?.OnBackToMenu();
}