UPdate
This commit is contained in:
@@ -301,6 +301,17 @@ namespace Hallucinate.UI
|
||||
_spawnedCharacters.Remove(player);
|
||||
}
|
||||
|
||||
// Logic Reassign Leader (Logical)
|
||||
if (runner.IsServer && PlayerDataManager.Instance != null && PlayerDataManager.Instance.Leader == player)
|
||||
{
|
||||
var nextLeader = runner.ActivePlayers.FirstOrDefault();
|
||||
if (nextLeader != PlayerRef.None)
|
||||
{
|
||||
PlayerDataManager.Instance.Leader = nextLeader;
|
||||
Debug.Log($"[BasicSpawner] Leader left. New logical leader: {nextLeader}");
|
||||
}
|
||||
}
|
||||
|
||||
if (runner.IsServer && player == runner.LocalPlayer)
|
||||
{
|
||||
runner.Shutdown();
|
||||
@@ -319,6 +330,13 @@ namespace Hallucinate.UI
|
||||
return;
|
||||
}
|
||||
|
||||
// Nếu đang trong quá trình Host Migration, đừng quay về menu
|
||||
if (shutdownReason == ShutdownReason.HostMigration)
|
||||
{
|
||||
Debug.Log("[BasicSpawner] Shutdown due to Host Migration. Waiting for recovery...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (UIManager.Instance != null)
|
||||
{
|
||||
UIManager.Instance.OnBackToMenu();
|
||||
@@ -354,7 +372,34 @@ namespace Hallucinate.UI
|
||||
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
||||
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
|
||||
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
|
||||
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
|
||||
|
||||
public async void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken)
|
||||
{
|
||||
Debug.Log("[BasicSpawner] OnHostMigration triggered!");
|
||||
|
||||
// 1. Shutdown existing runner properly
|
||||
await runner.Shutdown(false);
|
||||
|
||||
// 2. Create new runner
|
||||
await EnsureRunnerExists();
|
||||
|
||||
// 3. Restart as new Host/Server using the migration token
|
||||
var result = await _runner.StartGame(new StartGameArgs()
|
||||
{
|
||||
HostMigrationToken = hostMigrationToken,
|
||||
SceneManager = gameObject.GetComponent<NetworkSceneManagerDefault>() ?? gameObject.AddComponent<NetworkSceneManagerDefault>()
|
||||
});
|
||||
|
||||
if (result.Ok)
|
||||
{
|
||||
Debug.Log("[BasicSpawner] Host Migration SUCCESSFUL");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[BasicSpawner] Host Migration FAILED: {result.ShutdownReason}");
|
||||
UIManager.Instance?.OnBackToMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneLoadDone(NetworkRunner runner)
|
||||
{
|
||||
|
||||
@@ -16,12 +16,19 @@ public class PlayerDataManager : NetworkBehaviour
|
||||
|
||||
[Networked]
|
||||
public NetworkDictionary<PlayerRef, _PlayerMetaData> Players => default;
|
||||
|
||||
[Networked]
|
||||
public PlayerRef Leader { get; set; }
|
||||
|
||||
public event Action<PlayerRef, string> OnChatMessageReceived;
|
||||
|
||||
public override void Spawned()
|
||||
{
|
||||
Instance = this;
|
||||
if (Object.HasStateAuthority)
|
||||
{
|
||||
Leader = Runner.LocalPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Despawned(NetworkRunner runner, bool hasState)
|
||||
@@ -29,6 +36,15 @@ public class PlayerDataManager : NetworkBehaviour
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
|
||||
public void RPC_TransferLeader(PlayerRef newLeader)
|
||||
{
|
||||
if (Players.ContainsKey(newLeader))
|
||||
{
|
||||
Leader = newLeader;
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
|
||||
public void RPC_UpdatePlayerMetaData(PlayerRef playerRef, _PlayerMetaData metaData)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,11 @@ namespace Hallucinate.UI
|
||||
private Label _guestChatMessage;
|
||||
private TextField _chatInput;
|
||||
|
||||
private VisualElement _hostAvatar, _guestAvatar;
|
||||
private VisualElement _transferHostOverlay;
|
||||
private Button _confirmTransferBtn, _closeTransferBtn;
|
||||
private PlayerRef _pendingTransferPlayer;
|
||||
|
||||
private bool _isBusy = false;
|
||||
|
||||
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
|
||||
@@ -62,6 +67,11 @@ namespace Hallucinate.UI
|
||||
_guestChatMessage = root.Q<Label>("GuestChatMessage");
|
||||
_chatInput = root.Q<TextField>("ChatInput");
|
||||
|
||||
_hostAvatar = root.Q<VisualElement>("HostAvatar");
|
||||
_guestAvatar = root.Q<VisualElement>("GuestAvatar");
|
||||
_transferHostOverlay = root.Q<VisualElement>("TransferHostOverlay");
|
||||
_confirmTransferBtn = root.Q<Button>("ConfirmTransferBtn");
|
||||
_closeTransferBtn = root.Q<Button>("CloseTransferBtn");
|
||||
|
||||
root.Q<Button>("GoToCreateBtn").clicked += ShowCreate;
|
||||
root.Q<Button>("CancelCreateBtn").clicked += ShowJoin;
|
||||
@@ -76,6 +86,12 @@ namespace Hallucinate.UI
|
||||
if (_startBtn != null) _startBtn.clicked += OnStartClicked;
|
||||
if (_passToggle != null) _passToggle.RegisterValueChangedCallback(evt => { if (_roomPassInput != null) _roomPassInput.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None; });
|
||||
if (_chatInput != null) _chatInput.RegisterCallback<KeyDownEvent>(OnChatKeyDown, TrickleDown.TrickleDown);
|
||||
|
||||
if (_hostAvatar != null) _hostAvatar.RegisterCallback<ClickEvent>(evt => OnAvatarClicked(true));
|
||||
if (_guestAvatar != null) _guestAvatar.RegisterCallback<ClickEvent>(evt => OnAvatarClicked(false));
|
||||
if (_confirmTransferBtn != null) _confirmTransferBtn.clicked += OnConfirmTransferHost;
|
||||
if (_closeTransferBtn != null) _closeTransferBtn.clicked += () => { if(_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.None; };
|
||||
|
||||
if (LocalizationManager.Instance != null) { LocalizationManager.Instance.OnLanguageChanged += ApplyLocalization; ApplyLocalization(); }
|
||||
if (BasicSpawner.Instance != null) RegisterSpawnerEvents();
|
||||
else Invoke(nameof(RegisterSpawnerEvents), 0.1f);
|
||||
@@ -97,7 +113,7 @@ namespace Hallucinate.UI
|
||||
string msg = _chatInput.value.Trim();
|
||||
if (!string.IsNullOrEmpty(msg) && PlayerDataManager.Instance != null)
|
||||
{
|
||||
var runner = Object.FindFirstObjectByType<NetworkRunner>();
|
||||
var runner = BasicSpawner.Instance.Runner;
|
||||
if (runner != null) { PlayerDataManager.Instance.RPC_SendChatMessage(runner.LocalPlayer, msg); _chatInput.value = ""; _chatInput.Focus(); }
|
||||
}
|
||||
}
|
||||
@@ -105,7 +121,7 @@ namespace Hallucinate.UI
|
||||
|
||||
private void OnChatMessageReceived(PlayerRef sender, string message)
|
||||
{
|
||||
var runner = Object.FindFirstObjectByType<NetworkRunner>();
|
||||
var runner = BasicSpawner.Instance.Runner;
|
||||
if (runner == null) return;
|
||||
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
|
||||
bool isHost = sortedPlayers.Count > 0 && sender == sortedPlayers[0];
|
||||
@@ -163,7 +179,7 @@ namespace Hallucinate.UI
|
||||
var loungeIdLabel = root.Q<Label>("LoungeID");
|
||||
if (loungeIdLabel != null) loungeIdLabel.text = GetT("LOBBY_ID_PREFIX") + spawner.Runner.SessionInfo.Name;
|
||||
}
|
||||
_playerDataManager = Object.FindFirstObjectByType<PlayerDataManager>();
|
||||
_playerDataManager = PlayerDataManager.Instance;
|
||||
if (_playerDataManager != null) _playerDataManager.OnChatMessageReceived += OnChatMessageReceived;
|
||||
}
|
||||
|
||||
@@ -270,7 +286,7 @@ namespace Hallucinate.UI
|
||||
private void OnReadyClicked()
|
||||
{
|
||||
if (_isBusy) return;
|
||||
var runner = Object.FindFirstObjectByType<NetworkRunner>();
|
||||
var runner = BasicSpawner.Instance.Runner;
|
||||
if (runner != null && _playerDataManager != null && _playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData))
|
||||
_playerDataManager.RPC_SetReady(runner.LocalPlayer, !myData.IsReady);
|
||||
}
|
||||
@@ -280,13 +296,40 @@ namespace Hallucinate.UI
|
||||
if (_isBusy) return;
|
||||
BasicSpawner.Instance?.StartGame();
|
||||
}
|
||||
|
||||
private void OnAvatarClicked(bool isHostSlot)
|
||||
{
|
||||
if (_playerDataManager == null || _playerDataManager.Leader != BasicSpawner.Instance.Runner.LocalPlayer) return;
|
||||
|
||||
var runner = BasicSpawner.Instance.Runner;
|
||||
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
|
||||
|
||||
PlayerRef clickedPlayer = PlayerRef.None;
|
||||
if (isHostSlot && sortedPlayers.Count > 0) clickedPlayer = sortedPlayers[0];
|
||||
else if (!isHostSlot && sortedPlayers.Count > 1) clickedPlayer = sortedPlayers[1];
|
||||
|
||||
if (clickedPlayer != PlayerRef.None && clickedPlayer != runner.LocalPlayer)
|
||||
{
|
||||
_pendingTransferPlayer = clickedPlayer;
|
||||
if (_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConfirmTransferHost()
|
||||
{
|
||||
if (_pendingTransferPlayer != PlayerRef.None && _playerDataManager != null)
|
||||
{
|
||||
_playerDataManager.RPC_TransferLeader(_pendingTransferPlayer);
|
||||
if (_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnLeaveLoungeClicked()
|
||||
{
|
||||
if (_isBusy) return;
|
||||
_isBusy = true;
|
||||
|
||||
var runner = Object.FindFirstObjectByType<NetworkRunner>();
|
||||
var runner = BasicSpawner.Instance.Runner;
|
||||
if (runner != null) await runner.Shutdown(false);
|
||||
if (_playerDataManager != null) _playerDataManager.OnChatMessageReceived -= OnChatMessageReceived;
|
||||
ShowJoin();
|
||||
@@ -303,14 +346,7 @@ namespace Hallucinate.UI
|
||||
var runner = spawner.Runner;
|
||||
if (runner == null) return;
|
||||
|
||||
// 1. Strict Visibility Check
|
||||
bool isHost = runner.IsServer;
|
||||
if (_startBtn != null)
|
||||
{
|
||||
_startBtn.style.display = isHost ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
// 2. PlayerDataManager Sync
|
||||
// 1. PlayerDataManager Sync
|
||||
if (_playerDataManager == null || _playerDataManager.Object == null || !_playerDataManager.Object.IsValid)
|
||||
{
|
||||
_playerDataManager = PlayerDataManager.Instance;
|
||||
@@ -321,10 +357,18 @@ namespace Hallucinate.UI
|
||||
else return; // Still waiting for synchronization
|
||||
}
|
||||
|
||||
// 3. Identify Players
|
||||
// 2. Identify Players
|
||||
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
|
||||
PlayerRef hostRef = sortedPlayers.Count > 0 ? sortedPlayers[0] : PlayerRef.None;
|
||||
PlayerRef guestRef = sortedPlayers.Count > 1 ? sortedPlayers[1] : PlayerRef.None;
|
||||
PlayerRef leaderRef = _playerDataManager.Leader;
|
||||
|
||||
// 3. Strict Visibility Check (Leader Only)
|
||||
bool isLeader = runner.LocalPlayer == leaderRef;
|
||||
if (_startBtn != null)
|
||||
{
|
||||
_startBtn.style.display = isLeader ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
if (runner.SessionInfo != null && runner.SessionInfo.Properties.TryGetValue("rn", out var rnProp)) _loungeRoomName.text = rnProp.ToString().ToUpper();
|
||||
|
||||
@@ -333,8 +377,19 @@ namespace Hallucinate.UI
|
||||
{
|
||||
_hostNameLabel.text = hostData.Name.ToString().ToUpper();
|
||||
string readyStatus = hostData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
|
||||
_hostStatusLabel.text = $"{GetT("LOBBY_HOST_LABEL")} - {readyStatus}";
|
||||
string roleLabel = (hostRef == leaderRef) ? GetT("LOBBY_HOST_LABEL") : GetT("LOBBY_PLAYER_LABEL");
|
||||
_hostStatusLabel.text = $"{roleLabel} - {readyStatus}";
|
||||
_hostStatusLabel.style.color = hostData.IsReady ? Color.green : Color.red;
|
||||
|
||||
// Highlight leader avatar
|
||||
if (_hostAvatar != null)
|
||||
{
|
||||
float width = (hostRef == leaderRef) ? 2f : 0f;
|
||||
_hostAvatar.style.borderTopWidth = width;
|
||||
_hostAvatar.style.borderBottomWidth = width;
|
||||
_hostAvatar.style.borderLeftWidth = width;
|
||||
_hostAvatar.style.borderRightWidth = width;
|
||||
}
|
||||
}
|
||||
else { _hostNameLabel.text = GetT("LOBBY_SYNCING"); _hostStatusLabel.text = "-"; }
|
||||
|
||||
@@ -342,14 +397,42 @@ namespace Hallucinate.UI
|
||||
if (guestRef != PlayerRef.None && _playerDataManager.TryGetPlayerMetaData(guestRef, out var guestData))
|
||||
{
|
||||
_guestNameLabel.text = guestData.Name.ToString().ToUpper();
|
||||
_guestStatusLabel.text = guestData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
|
||||
string readyStatus = guestData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
|
||||
string roleLabel = (guestRef == leaderRef) ? GetT("LOBBY_HOST_LABEL") : GetT("LOBBY_PLAYER_LABEL");
|
||||
_guestStatusLabel.text = $"{roleLabel} - {readyStatus}";
|
||||
_guestStatusLabel.style.color = guestData.IsReady ? Color.green : Color.red;
|
||||
|
||||
// Highlight leader avatar
|
||||
if (_guestAvatar != null)
|
||||
{
|
||||
float width = (guestRef == leaderRef) ? 2f : 0f;
|
||||
_guestAvatar.style.borderTopWidth = width;
|
||||
_guestAvatar.style.borderBottomWidth = width;
|
||||
_guestAvatar.style.borderLeftWidth = width;
|
||||
_guestAvatar.style.borderRightWidth = width;
|
||||
_guestAvatar.style.borderTopColor = Color.white;
|
||||
_guestAvatar.style.borderBottomColor = Color.white;
|
||||
_guestAvatar.style.borderLeftColor = Color.white;
|
||||
_guestAvatar.style.borderRightColor = Color.white;
|
||||
}
|
||||
}
|
||||
else if (runner.ActivePlayers.Count() >= 2) { _guestNameLabel.text = GetT("LOBBY_SYNCING"); _guestStatusLabel.text = "-"; }
|
||||
else { _guestNameLabel.text = GetT("LOBBY_WAITING_LABEL"); _guestStatusLabel.text = "-"; _guestStatusLabel.style.color = Color.gray; }
|
||||
else
|
||||
{
|
||||
_guestNameLabel.text = GetT("LOBBY_WAITING_LABEL");
|
||||
_guestStatusLabel.text = "-";
|
||||
_guestStatusLabel.style.color = Color.gray;
|
||||
if (_guestAvatar != null)
|
||||
{
|
||||
_guestAvatar.style.borderTopWidth = 0;
|
||||
_guestAvatar.style.borderBottomWidth = 0;
|
||||
_guestAvatar.style.borderLeftWidth = 0;
|
||||
_guestAvatar.style.borderRightWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Start Button Logic (Host Only)
|
||||
if (_startBtn != null && isHost)
|
||||
// 4. Start Button Logic (Leader Only)
|
||||
if (_startBtn != null && isLeader)
|
||||
{
|
||||
bool allReady = true;
|
||||
int playerCount = 0;
|
||||
|
||||
Reference in New Issue
Block a user