This commit is contained in:
2026-05-02 00:00:31 +07:00
parent 709ed4069d
commit e66f2ec715
12 changed files with 1185 additions and 194 deletions

View File

@@ -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;