Animace + Menu
This commit is contained in:
939
UI/Scripts/MultiplayerLobbyController.cs
Normal file
939
UI/Scripts/MultiplayerLobbyController.cs
Normal file
@@ -0,0 +1,939 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MegaKoop.Steam;
|
||||
|
||||
namespace MegaKoop.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Professional Multiplayer Lobby Controller with Steam API Integration
|
||||
/// Senior-level implementation with proper state management
|
||||
/// </summary>
|
||||
public class MultiplayerLobbyController : MonoBehaviour
|
||||
{
|
||||
[Header("UI Document")]
|
||||
[SerializeField] private UIDocument uiDocument;
|
||||
|
||||
[Header("Lobby Settings")]
|
||||
[SerializeField] private int maxPlayers = 4;
|
||||
[SerializeField] private string[] maxPlayersOptions = { "2", "3", "4", "8" };
|
||||
|
||||
// Root element
|
||||
private VisualElement root;
|
||||
|
||||
// Panel
|
||||
private VisualElement multiplayerPanel;
|
||||
|
||||
// Header Elements
|
||||
private Label lobbyStatusLabel;
|
||||
private VisualElement statusIndicator;
|
||||
|
||||
// Lobby Code Section
|
||||
private VisualElement lobbyCodeSection;
|
||||
private Label lobbyCodeDisplay;
|
||||
private Button copyCodeButton;
|
||||
|
||||
// Connection Section
|
||||
private VisualElement lobbyConnectionSection;
|
||||
private Button hostLobbyButton;
|
||||
private Button joinLobbyButton;
|
||||
private VisualElement joinLobbyContent;
|
||||
private VisualElement hostLobbyContent;
|
||||
private TextField lobbyCodeInput;
|
||||
private Button connectButton;
|
||||
private Button createLobbyButton;
|
||||
private DropdownField maxPlayersDropdown;
|
||||
private Toggle publicLobbyToggle;
|
||||
|
||||
// Players Section
|
||||
private VisualElement playersSection;
|
||||
private Label playerCountLabel;
|
||||
private ScrollView playersListScrollView;
|
||||
private VisualElement playersList;
|
||||
private VisualElement emptyPlayersState;
|
||||
|
||||
// Host Controls
|
||||
private VisualElement hostControlsSection;
|
||||
private Button inviteFriendsButton;
|
||||
private Button kickPlayerButton;
|
||||
|
||||
// Player Ready Section
|
||||
private VisualElement playerReadySection;
|
||||
private Button toggleReadyButton;
|
||||
private Label readyIcon;
|
||||
private Label readyText;
|
||||
|
||||
// Footer
|
||||
private Button startGameButton;
|
||||
private Button leaveLobbyButton;
|
||||
private Button backFromMultiplayerButton;
|
||||
|
||||
// Lobby State
|
||||
private bool isHost = false;
|
||||
private bool isInLobby = false;
|
||||
private bool isPlayerReady = false;
|
||||
private List<PlayerInfo> connectedPlayers = new List<PlayerInfo>();
|
||||
private string currentLobbyCode = "";
|
||||
private string selectedPlayerSteamId = "";
|
||||
|
||||
// Steam Integration
|
||||
private SteamLobbyService steam;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (uiDocument == null)
|
||||
uiDocument = GetComponent<UIDocument>();
|
||||
|
||||
if (uiDocument != null)
|
||||
{
|
||||
root = uiDocument.rootVisualElement;
|
||||
InitializeElements();
|
||||
RegisterEvents();
|
||||
EnsureSteamServices();
|
||||
RegisterSteamEvents();
|
||||
SetupInitialState();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("UIDocument not found on MultiplayerLobbyController!");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnregisterEvents();
|
||||
UnregisterSteamEvents();
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
|
||||
private void InitializeElements()
|
||||
{
|
||||
// Panel
|
||||
multiplayerPanel = root.Q<VisualElement>("MultiplayerPanel");
|
||||
|
||||
// Header
|
||||
lobbyStatusLabel = root.Q<Label>("LobbyStatusLabel");
|
||||
statusIndicator = root.Q<VisualElement>("StatusIndicator");
|
||||
|
||||
// Lobby Code Section
|
||||
lobbyCodeSection = root.Q<VisualElement>("LobbyCodeSection");
|
||||
lobbyCodeDisplay = root.Q<Label>("LobbyCodeDisplay");
|
||||
copyCodeButton = root.Q<Button>("CopyCodeButton");
|
||||
|
||||
// Connection Section
|
||||
lobbyConnectionSection = root.Q<VisualElement>("LobbyConnectionSection");
|
||||
hostLobbyButton = root.Q<Button>("HostLobbyButton");
|
||||
joinLobbyButton = root.Q<Button>("JoinLobbyButton");
|
||||
joinLobbyContent = root.Q<VisualElement>("JoinLobbyContent");
|
||||
hostLobbyContent = root.Q<VisualElement>("HostLobbyContent");
|
||||
lobbyCodeInput = root.Q<TextField>("LobbyCodeInput");
|
||||
connectButton = root.Q<Button>("ConnectButton");
|
||||
createLobbyButton = root.Q<Button>("CreateLobbyButton");
|
||||
maxPlayersDropdown = root.Q<DropdownField>("MaxPlayersDropdown");
|
||||
publicLobbyToggle = root.Q<Toggle>("PublicLobbyToggle");
|
||||
|
||||
// Players Section
|
||||
playersSection = root.Q<VisualElement>("PlayersSection");
|
||||
playerCountLabel = root.Q<Label>("PlayerCountLabel");
|
||||
playersListScrollView = root.Q<ScrollView>("PlayersListScrollView");
|
||||
playersList = root.Q<VisualElement>("PlayersList");
|
||||
emptyPlayersState = root.Q<VisualElement>("EmptyPlayersState");
|
||||
|
||||
// Host Controls
|
||||
hostControlsSection = root.Q<VisualElement>("HostControlsSection");
|
||||
inviteFriendsButton = root.Q<Button>("InviteFriendsButton");
|
||||
kickPlayerButton = root.Q<Button>("KickPlayerButton");
|
||||
|
||||
// Player Ready Section
|
||||
playerReadySection = root.Q<VisualElement>("PlayerReadySection");
|
||||
toggleReadyButton = root.Q<Button>("ToggleReadyButton");
|
||||
readyIcon = root.Q<Label>("ReadyIcon");
|
||||
readyText = root.Q<Label>("ReadyText");
|
||||
|
||||
// Footer
|
||||
startGameButton = root.Q<Button>("StartGameButton");
|
||||
leaveLobbyButton = root.Q<Button>("LeaveLobbyButton");
|
||||
backFromMultiplayerButton = root.Q<Button>("BackFromMultiplayerButton");
|
||||
|
||||
// Setup dropdowns
|
||||
if (maxPlayersDropdown != null)
|
||||
{
|
||||
maxPlayersDropdown.choices = maxPlayersOptions.ToList();
|
||||
maxPlayersDropdown.value = maxPlayers.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupInitialState()
|
||||
{
|
||||
// Show host content by default
|
||||
ShowHostContent();
|
||||
// Hide sections that require lobby
|
||||
HideLobbyDependentSections();
|
||||
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Steam Integration
|
||||
private void EnsureSteamServices()
|
||||
{
|
||||
if (steam == null)
|
||||
{
|
||||
steam = GetComponent<SteamLobbyService>();
|
||||
if (steam == null)
|
||||
{
|
||||
var go = GameObject.Find("SteamServices") ?? new GameObject("SteamServices");
|
||||
if (go.GetComponent<SteamManager>() == null) go.AddComponent<SteamManager>();
|
||||
steam = go.GetComponent<SteamLobbyService>() ?? go.AddComponent<SteamLobbyService>();
|
||||
DontDestroyOnLoad(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterSteamEvents()
|
||||
{
|
||||
if (steam == null) return;
|
||||
steam.OnLobbyCreated += OnSteamLobbyCreated;
|
||||
steam.OnLobbyEntered += OnSteamLobbyEntered;
|
||||
steam.OnLobbyLeft += OnSteamLobbyLeft;
|
||||
steam.OnMembersChanged += OnSteamMembersChanged;
|
||||
steam.OnLobbyDataUpdated += OnSteamLobbyDataUpdated;
|
||||
steam.OnJoinFailed += OnSteamJoinFailed;
|
||||
}
|
||||
|
||||
private void UnregisterSteamEvents()
|
||||
{
|
||||
if (steam == null) return;
|
||||
steam.OnLobbyCreated -= OnSteamLobbyCreated;
|
||||
steam.OnLobbyEntered -= OnSteamLobbyEntered;
|
||||
steam.OnLobbyLeft -= OnSteamLobbyLeft;
|
||||
steam.OnMembersChanged -= OnSteamMembersChanged;
|
||||
steam.OnLobbyDataUpdated -= OnSteamLobbyDataUpdated;
|
||||
steam.OnJoinFailed -= OnSteamJoinFailed;
|
||||
}
|
||||
|
||||
private void OnSteamLobbyCreated()
|
||||
{
|
||||
if (steam == null) return;
|
||||
isHost = steam.IsHost;
|
||||
isInLobby = true;
|
||||
currentLobbyCode = steam.LobbyCode;
|
||||
RebuildPlayersFromSteam();
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void OnSteamLobbyEntered()
|
||||
{
|
||||
if (steam == null) return;
|
||||
isHost = steam.IsHost;
|
||||
isInLobby = true;
|
||||
currentLobbyCode = steam.LobbyCode;
|
||||
RebuildPlayersFromSteam();
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void OnSteamLobbyLeft()
|
||||
{
|
||||
isHost = false;
|
||||
isInLobby = false;
|
||||
isPlayerReady = false;
|
||||
currentLobbyCode = string.Empty;
|
||||
selectedPlayerSteamId = string.Empty;
|
||||
connectedPlayers.Clear();
|
||||
SetupInitialState();
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void OnSteamMembersChanged()
|
||||
{
|
||||
RebuildPlayersFromSteam();
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void OnSteamLobbyDataUpdated()
|
||||
{
|
||||
if (steam == null) return;
|
||||
currentLobbyCode = steam.LobbyCode;
|
||||
RebuildPlayersFromSteam();
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void OnSteamJoinFailed(string reason)
|
||||
{
|
||||
Debug.LogWarning($"Join failed: {reason}");
|
||||
}
|
||||
|
||||
private void RebuildPlayersFromSteam()
|
||||
{
|
||||
if (steam == null || !steam.IsInLobby) return;
|
||||
connectedPlayers.Clear();
|
||||
var members = steam.GetMembers();
|
||||
foreach (var m in members)
|
||||
{
|
||||
connectedPlayers.Add(new PlayerInfo
|
||||
{
|
||||
steamId = m.steamId,
|
||||
playerName = string.IsNullOrEmpty(m.name) ? "Player" : m.name,
|
||||
isHost = m.isHost,
|
||||
isReady = m.isReady
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event Registration
|
||||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
if (hostLobbyButton != null)
|
||||
hostLobbyButton.clicked += OnHostTabClicked;
|
||||
|
||||
if (joinLobbyButton != null)
|
||||
joinLobbyButton.clicked += OnJoinTabClicked;
|
||||
|
||||
if (createLobbyButton != null)
|
||||
createLobbyButton.clicked += OnCreateLobbyClicked;
|
||||
|
||||
if (connectButton != null)
|
||||
connectButton.clicked += OnConnectClicked;
|
||||
|
||||
if (copyCodeButton != null)
|
||||
copyCodeButton.clicked += OnCopyCodeClicked;
|
||||
|
||||
if (inviteFriendsButton != null)
|
||||
inviteFriendsButton.clicked += OnInviteFriendsClicked;
|
||||
|
||||
if (kickPlayerButton != null)
|
||||
kickPlayerButton.clicked += OnKickPlayerClicked;
|
||||
|
||||
if (toggleReadyButton != null)
|
||||
toggleReadyButton.clicked += OnToggleReadyClicked;
|
||||
|
||||
if (startGameButton != null)
|
||||
startGameButton.clicked += OnStartGameClicked;
|
||||
|
||||
if (leaveLobbyButton != null)
|
||||
leaveLobbyButton.clicked += OnLeaveLobbyClicked;
|
||||
|
||||
if (backFromMultiplayerButton != null)
|
||||
backFromMultiplayerButton.clicked += OnBackClicked;
|
||||
}
|
||||
|
||||
private void UnregisterEvents()
|
||||
{
|
||||
if (hostLobbyButton != null)
|
||||
hostLobbyButton.clicked -= OnHostTabClicked;
|
||||
|
||||
if (joinLobbyButton != null)
|
||||
joinLobbyButton.clicked -= OnJoinTabClicked;
|
||||
|
||||
if (createLobbyButton != null)
|
||||
createLobbyButton.clicked -= OnCreateLobbyClicked;
|
||||
|
||||
if (connectButton != null)
|
||||
connectButton.clicked -= OnConnectClicked;
|
||||
|
||||
if (copyCodeButton != null)
|
||||
copyCodeButton.clicked -= OnCopyCodeClicked;
|
||||
|
||||
if (inviteFriendsButton != null)
|
||||
inviteFriendsButton.clicked -= OnInviteFriendsClicked;
|
||||
|
||||
if (kickPlayerButton != null)
|
||||
kickPlayerButton.clicked -= OnKickPlayerClicked;
|
||||
|
||||
if (toggleReadyButton != null)
|
||||
toggleReadyButton.clicked -= OnToggleReadyClicked;
|
||||
|
||||
if (startGameButton != null)
|
||||
startGameButton.clicked -= OnStartGameClicked;
|
||||
|
||||
if (leaveLobbyButton != null)
|
||||
leaveLobbyButton.clicked -= OnLeaveLobbyClicked;
|
||||
|
||||
if (backFromMultiplayerButton != null)
|
||||
backFromMultiplayerButton.clicked -= OnBackClicked;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Button Callbacks
|
||||
|
||||
private void OnHostTabClicked()
|
||||
{
|
||||
ShowHostContent();
|
||||
}
|
||||
|
||||
private void OnJoinTabClicked()
|
||||
{
|
||||
ShowJoinContent();
|
||||
}
|
||||
|
||||
private void OnCreateLobbyClicked()
|
||||
{
|
||||
CreateLobby();
|
||||
}
|
||||
|
||||
private void OnConnectClicked()
|
||||
{
|
||||
string code = lobbyCodeInput?.value ?? "";
|
||||
if (!string.IsNullOrEmpty(code) && code.Length == 6)
|
||||
{
|
||||
JoinLobby(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Invalid lobby code! Must be 6 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCopyCodeClicked()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(currentLobbyCode))
|
||||
{
|
||||
GUIUtility.systemCopyBuffer = currentLobbyCode;
|
||||
Debug.Log($"Lobby code copied: {currentLobbyCode}");
|
||||
|
||||
// Visual feedback
|
||||
if (copyCodeButton != null)
|
||||
{
|
||||
string originalText = copyCodeButton.text;
|
||||
copyCodeButton.text = "COPIED!";
|
||||
copyCodeButton.schedule.Execute(() => copyCodeButton.text = originalText).StartingIn(1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInviteFriendsClicked()
|
||||
{
|
||||
if (steam != null && isInLobby)
|
||||
{
|
||||
steam.InviteFriends();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("Invite: not in lobby or steam service missing");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKickPlayerClicked()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(selectedPlayerSteamId) && isHost)
|
||||
{
|
||||
KickPlayer(selectedPlayerSteamId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("No player selected to kick!");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnToggleReadyClicked()
|
||||
{
|
||||
TogglePlayerReady();
|
||||
}
|
||||
|
||||
private void OnStartGameClicked()
|
||||
{
|
||||
if (isHost && isInLobby)
|
||||
{
|
||||
StartGame();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLeaveLobbyClicked()
|
||||
{
|
||||
LeaveLobby();
|
||||
}
|
||||
|
||||
private void OnBackClicked()
|
||||
{
|
||||
HideMultiplayerPanel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lobby Management
|
||||
|
||||
public void ShowMultiplayerPanel()
|
||||
{
|
||||
multiplayerPanel?.RemoveFromClassList("hidden");
|
||||
}
|
||||
|
||||
public void HideMultiplayerPanel()
|
||||
{
|
||||
multiplayerPanel?.AddToClassList("hidden");
|
||||
}
|
||||
|
||||
private void CreateLobby()
|
||||
{
|
||||
// Parse max players
|
||||
if (maxPlayersDropdown != null && int.TryParse(maxPlayersDropdown.value, out int maxP))
|
||||
maxPlayers = maxP;
|
||||
|
||||
if (steam != null)
|
||||
{
|
||||
bool isPublic = publicLobbyToggle == null || publicLobbyToggle.value;
|
||||
steam.CreateLobby(maxPlayers, isPublic);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback mock
|
||||
isHost = true; isInLobby = true; currentLobbyCode = GenerateLobbyCode();
|
||||
connectedPlayers.Clear();
|
||||
connectedPlayers.Add(new PlayerInfo { steamId = "HOST_ID", playerName = "Host Player", isHost = true, isReady = true });
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void JoinLobby(string lobbyCode)
|
||||
{
|
||||
if (steam != null)
|
||||
{
|
||||
steam.JoinLobbyByCode(lobbyCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback mock
|
||||
isHost = false; isInLobby = true; isPlayerReady = false; currentLobbyCode = lobbyCode;
|
||||
connectedPlayers.Clear();
|
||||
connectedPlayers.Add(new PlayerInfo { steamId = "HOST_ID", playerName = "Host Player", isHost = true, isReady = true });
|
||||
connectedPlayers.Add(new PlayerInfo { steamId = "MY_ID", playerName = "My Player", isHost = false, isReady = false });
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void LeaveLobby()
|
||||
{
|
||||
if (steam != null && steam.IsInLobby)
|
||||
{
|
||||
steam.LeaveLobby();
|
||||
}
|
||||
else
|
||||
{
|
||||
isHost = false; isInLobby = false; isPlayerReady = false; currentLobbyCode = ""; selectedPlayerSteamId = ""; connectedPlayers.Clear();
|
||||
SetupInitialState(); UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartGame()
|
||||
{
|
||||
if (!isHost)
|
||||
{
|
||||
Debug.LogWarning("Only host can start the game!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if all players are ready
|
||||
bool allReady = connectedPlayers.All(p => p.isReady);
|
||||
if (!allReady)
|
||||
{
|
||||
Debug.LogWarning("Not all players are ready!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal via Steam lobby data (host)
|
||||
if (steam != null && steam.IsInLobby)
|
||||
{
|
||||
steam.StartGameSignal();
|
||||
}
|
||||
Debug.Log("Starting game...");
|
||||
|
||||
// Load game scene
|
||||
// UnityEngine.SceneManagement.SceneManager.LoadScene("GameScene");
|
||||
}
|
||||
|
||||
private void TogglePlayerReady()
|
||||
{
|
||||
if (isHost) return; // Host is always ready
|
||||
|
||||
isPlayerReady = !isPlayerReady;
|
||||
// Steam ready flag
|
||||
if (steam != null && steam.IsInLobby)
|
||||
{
|
||||
steam.SetReady(isPlayerReady);
|
||||
}
|
||||
// Update local player ready state
|
||||
var myPlayer = connectedPlayers.Find(p => p.steamId == "MY_ID");
|
||||
if (myPlayer != null)
|
||||
{
|
||||
myPlayer.isReady = isPlayerReady;
|
||||
}
|
||||
|
||||
Debug.Log($"Player ready status: {isPlayerReady}");
|
||||
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
private void KickPlayer(string steamId)
|
||||
{
|
||||
if (!isHost || steamId == "HOST_ID") return;
|
||||
|
||||
if (steam != null && steam.IsInLobby)
|
||||
{
|
||||
steam.Kick(steamId);
|
||||
}
|
||||
connectedPlayers.RemoveAll(p => p.steamId == steamId);
|
||||
selectedPlayerSteamId = "";
|
||||
|
||||
Debug.Log($"Kicked player: {steamId}");
|
||||
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Updates
|
||||
|
||||
private void UpdateUI()
|
||||
{
|
||||
UpdateStatusBadge();
|
||||
UpdateLobbyCodeSection();
|
||||
UpdateConnectionSection();
|
||||
UpdatePlayersList();
|
||||
UpdateHostControls();
|
||||
UpdatePlayerReadySection();
|
||||
UpdateFooterButtons();
|
||||
}
|
||||
|
||||
private void UpdateStatusBadge()
|
||||
{
|
||||
if (lobbyStatusLabel != null)
|
||||
{
|
||||
if (isInLobby)
|
||||
{
|
||||
lobbyStatusLabel.text = isHost ? "HOSTING" : "CONNECTED";
|
||||
lobbyStatusLabel.AddToClassList("connected");
|
||||
statusIndicator?.AddToClassList("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
lobbyStatusLabel.text = "OFFLINE";
|
||||
lobbyStatusLabel.RemoveFromClassList("connected");
|
||||
statusIndicator?.RemoveFromClassList("connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLobbyCodeSection()
|
||||
{
|
||||
if (lobbyCodeSection != null)
|
||||
{
|
||||
if (isInLobby && !string.IsNullOrEmpty(currentLobbyCode))
|
||||
{
|
||||
lobbyCodeSection.RemoveFromClassList("hidden");
|
||||
if (lobbyCodeDisplay != null)
|
||||
lobbyCodeDisplay.text = currentLobbyCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
lobbyCodeSection.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateConnectionSection()
|
||||
{
|
||||
if (lobbyConnectionSection != null)
|
||||
{
|
||||
if (isInLobby)
|
||||
{
|
||||
lobbyConnectionSection.AddToClassList("hidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
lobbyConnectionSection.RemoveFromClassList("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayersList()
|
||||
{
|
||||
if (playersList == null) return;
|
||||
|
||||
// Update count
|
||||
if (playerCountLabel != null)
|
||||
{
|
||||
playerCountLabel.text = $"{connectedPlayers.Count}/{maxPlayers}";
|
||||
}
|
||||
|
||||
// Clear list
|
||||
playersList.Clear();
|
||||
|
||||
// Show/hide empty state
|
||||
if (emptyPlayersState != null)
|
||||
{
|
||||
if (connectedPlayers.Count == 0)
|
||||
{
|
||||
emptyPlayersState.RemoveFromClassList("hidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
emptyPlayersState.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Add players
|
||||
foreach (var player in connectedPlayers)
|
||||
{
|
||||
var playerItem = CreatePlayerItem(player);
|
||||
playersList.Add(playerItem);
|
||||
}
|
||||
}
|
||||
|
||||
private VisualElement CreatePlayerItem(PlayerInfo player)
|
||||
{
|
||||
var item = new VisualElement();
|
||||
item.AddToClassList("player-item");
|
||||
|
||||
if (player.isHost)
|
||||
item.AddToClassList("host");
|
||||
|
||||
if (player.steamId == selectedPlayerSteamId)
|
||||
item.AddToClassList("selected");
|
||||
|
||||
// Player info container
|
||||
var playerInfo = new VisualElement();
|
||||
playerInfo.AddToClassList("player-info");
|
||||
|
||||
// Avatar
|
||||
var avatar = new VisualElement();
|
||||
avatar.AddToClassList("player-avatar");
|
||||
playerInfo.Add(avatar);
|
||||
|
||||
// Name and badge
|
||||
var nameContainer = new VisualElement();
|
||||
nameContainer.style.flexDirection = FlexDirection.Row;
|
||||
nameContainer.style.alignItems = Align.Center;
|
||||
|
||||
var nameLabel = new Label(player.playerName);
|
||||
nameLabel.AddToClassList("player-name");
|
||||
nameContainer.Add(nameLabel);
|
||||
|
||||
if (player.isHost)
|
||||
{
|
||||
var hostBadge = new Label("HOST");
|
||||
hostBadge.AddToClassList("player-host-badge");
|
||||
nameContainer.Add(hostBadge);
|
||||
}
|
||||
|
||||
playerInfo.Add(nameContainer);
|
||||
item.Add(playerInfo);
|
||||
|
||||
// Status container
|
||||
var statusContainer = new VisualElement();
|
||||
statusContainer.AddToClassList("player-status");
|
||||
|
||||
var readyIndicator = new VisualElement();
|
||||
readyIndicator.AddToClassList("player-ready-indicator");
|
||||
if (player.isReady)
|
||||
readyIndicator.AddToClassList("ready");
|
||||
statusContainer.Add(readyIndicator);
|
||||
|
||||
var readyLabel = new Label(player.isReady ? "READY" : "NOT READY");
|
||||
readyLabel.AddToClassList("player-ready-text");
|
||||
if (player.isReady)
|
||||
readyLabel.AddToClassList("ready");
|
||||
statusContainer.Add(readyLabel);
|
||||
|
||||
item.Add(statusContainer);
|
||||
|
||||
// Click event for selection (host only)
|
||||
if (isHost && !player.isHost)
|
||||
{
|
||||
item.RegisterCallback<ClickEvent>(evt =>
|
||||
{
|
||||
selectedPlayerSteamId = player.steamId;
|
||||
UpdatePlayersList();
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void UpdateHostControls()
|
||||
{
|
||||
if (hostControlsSection != null)
|
||||
{
|
||||
if (isHost && isInLobby)
|
||||
{
|
||||
hostControlsSection.RemoveFromClassList("hidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
hostControlsSection.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Enable/disable kick button
|
||||
if (kickPlayerButton != null)
|
||||
{
|
||||
kickPlayerButton.SetEnabled(!string.IsNullOrEmpty(selectedPlayerSteamId));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerReadySection()
|
||||
{
|
||||
if (playerReadySection != null)
|
||||
{
|
||||
if (!isHost && isInLobby)
|
||||
{
|
||||
playerReadySection.RemoveFromClassList("hidden");
|
||||
|
||||
// Update ready button appearance
|
||||
if (toggleReadyButton != null)
|
||||
{
|
||||
if (isPlayerReady)
|
||||
{
|
||||
toggleReadyButton.AddToClassList("ready");
|
||||
if (readyText != null) readyText.text = "READY";
|
||||
}
|
||||
else
|
||||
{
|
||||
toggleReadyButton.RemoveFromClassList("ready");
|
||||
if (readyText != null) readyText.text = "NOT READY";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
playerReadySection.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFooterButtons()
|
||||
{
|
||||
// Start game button (host only, in lobby)
|
||||
if (startGameButton != null)
|
||||
{
|
||||
if (isHost && isInLobby)
|
||||
{
|
||||
startGameButton.RemoveFromClassList("hidden");
|
||||
|
||||
// Enable only if all players ready
|
||||
bool allReady = connectedPlayers.All(p => p.isReady);
|
||||
startGameButton.SetEnabled(allReady && connectedPlayers.Count >= 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
startGameButton.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Leave lobby button
|
||||
if (leaveLobbyButton != null)
|
||||
{
|
||||
if (isInLobby)
|
||||
{
|
||||
leaveLobbyButton.RemoveFromClassList("hidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
leaveLobbyButton.AddToClassList("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI State Management
|
||||
|
||||
private void ShowHostContent()
|
||||
{
|
||||
hostLobbyButton?.AddToClassList("primary-button");
|
||||
joinLobbyButton?.RemoveFromClassList("primary-button");
|
||||
|
||||
hostLobbyContent?.RemoveFromClassList("hidden");
|
||||
joinLobbyContent?.AddToClassList("hidden");
|
||||
}
|
||||
|
||||
private void ShowJoinContent()
|
||||
{
|
||||
joinLobbyButton?.AddToClassList("primary-button");
|
||||
hostLobbyButton?.RemoveFromClassList("primary-button");
|
||||
|
||||
joinLobbyContent?.RemoveFromClassList("hidden");
|
||||
hostLobbyContent?.AddToClassList("hidden");
|
||||
}
|
||||
|
||||
private void HideLobbyDependentSections()
|
||||
{
|
||||
lobbyCodeSection?.AddToClassList("hidden");
|
||||
hostControlsSection?.AddToClassList("hidden");
|
||||
playerReadySection?.AddToClassList("hidden");
|
||||
startGameButton?.AddToClassList("hidden");
|
||||
leaveLobbyButton?.AddToClassList("hidden");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
private string GenerateLobbyCode()
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
var code = "";
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
code += chars[Random.Range(0, chars.Length)];
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
// Public methods for Steam API callbacks
|
||||
public void OnPlayerJoinedLobby(string steamId, string playerName)
|
||||
{
|
||||
var player = new PlayerInfo
|
||||
{
|
||||
steamId = steamId,
|
||||
playerName = playerName,
|
||||
isHost = false,
|
||||
isReady = false
|
||||
};
|
||||
|
||||
connectedPlayers.Add(player);
|
||||
UpdateUI();
|
||||
|
||||
Debug.Log($"Player joined: {playerName}");
|
||||
}
|
||||
|
||||
public void OnPlayerLeftLobby(string steamId)
|
||||
{
|
||||
connectedPlayers.RemoveAll(p => p.steamId == steamId);
|
||||
if (selectedPlayerSteamId == steamId)
|
||||
selectedPlayerSteamId = "";
|
||||
|
||||
UpdateUI();
|
||||
|
||||
Debug.Log($"Player left: {steamId}");
|
||||
}
|
||||
|
||||
public void OnPlayerReadyChanged(string steamId, bool isReady)
|
||||
{
|
||||
var player = connectedPlayers.Find(p => p.steamId == steamId);
|
||||
if (player != null)
|
||||
{
|
||||
player.isReady = isReady;
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Player information in lobby
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class PlayerInfo
|
||||
{
|
||||
public string steamId;
|
||||
public string playerName;
|
||||
public bool isHost;
|
||||
public bool isReady;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user