using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using MegaKoop.Steam; using MegaKoop.Networking; using MegaKoop.Game.Networking; using TMPro; namespace MegaKoop.UI { /// /// UGUI Multiplayer Lobby Controller integrated with SteamLobbyService. /// Builds players list dynamically, handles host/join/invite/kick/ready/start. /// public class UGUIMultiplayerLobbyController : MonoBehaviour { // Panels [Header("Optional Root Ref (assigned by builder)")] [SerializeField] private GameObject panelLobbyRef; private GameObject panelLobby; private GameObject groupJoin; private GameObject groupHost; [Header("Manual Wiring - Header & Code")] [SerializeField] private TMP_Text textStatus; [SerializeField] private TMP_Text textLobbyCodeValue; [SerializeField] private Button btnCopyCode; [Header("Manual Wiring - Tabs")] [SerializeField] private Button btnHostTab; [SerializeField] private Button btnJoinTab; [Header("Manual Wiring - Join Section")] [SerializeField] private TMP_InputField inputLobbyCode; [SerializeField] private Button btnConnect; [Header("Manual Wiring - Host Section")] [SerializeField] private TMP_Dropdown ddMaxPlayers; [SerializeField] private Toggle tgPublicLobby; [SerializeField] private Button btnCreateLobby; [Header("Manual Wiring - Players List")] [SerializeField] private TMP_Text textPlayerCount; [SerializeField] private ScrollRect scrollPlayers; [SerializeField] private Transform contentPlayers; [SerializeField] private GameObject playerItemTemplate; [SerializeField] private GameObject emptyPlayers; [Header("Manual Wiring - Friends Picker")] [SerializeField] private GameObject panelFriends; [SerializeField] private Transform contentFriends; [SerializeField] private GameObject emptyFriends; [SerializeField] private Button btnBackFromFriends; [SerializeField] private Button btnCloseFriendsOverlay; [Header("Manual Wiring - Host Controls")] [SerializeField] private Button btnInviteFriends; [SerializeField] private Button btnKickSelected; [Header("Manual Wiring - Footer")] [SerializeField] private Button btnToggleReady; [SerializeField] private Button btnStartGame; [SerializeField] private Button btnLeaveLobby; [SerializeField] private Button btnBackFromLobby; [Header("Player Ready Styling")] [SerializeField] private Color readyBorderColor = new Color(0.2f, 0.82f, 0.35f, 1f); [SerializeField] private Color notReadyBorderColor = new Color(0.85f, 0.25f, 0.25f, 1f); [SerializeField] private float avatarBorderThickness = 12f; // Selection private string selectedPlayerSteamId = string.Empty; // Cached readiness state per member private readonly Dictionary memberReadyCache = new Dictionary(); // Steam service private SteamLobbyService steam; private LobbyGameSceneCoordinator lobbyGameCoordinator; private SteamCoopNetworkManager coopNetworkManager; // Local state cache private bool IsInLobby => steam != null && steam.IsInLobby; private bool IsHost => steam != null && steam.IsHost; private string LobbyCode => steam != null ? steam.LobbyCode : string.Empty; private bool clientStartedFromSignal = false; private bool leftDueToKick = false; private bool inviteOverlayRequested = false; private void Awake() { // Find UI (including inactive) panelLobby = EnsureGO(panelLobby, "Panel_Lobby"); groupJoin = EnsureGO(groupJoin, "Group_Join"); groupHost = EnsureGO(groupHost, "Group_Host"); textStatus = EnsureText(textStatus, "Text_Status"); textLobbyCodeValue = EnsureText(textLobbyCodeValue, "Text_LobbyCodeValue"); btnCopyCode = EnsureButton(btnCopyCode, "Button_CopyCode"); btnHostTab = EnsureButton(btnHostTab, "Button_HostTab"); btnJoinTab = EnsureButton(btnJoinTab, "Button_JoinTab"); inputLobbyCode = EnsureInput(inputLobbyCode, "Input_LobbyCode"); btnConnect = EnsureButton(btnConnect, "Button_Connect"); ddMaxPlayers = EnsureDropdown(ddMaxPlayers, "Dropdown_MaxPlayers"); tgPublicLobby = EnsureToggle(tgPublicLobby, "Toggle_PublicLobby"); btnCreateLobby = EnsureButton(btnCreateLobby, "Button_CreateLobby"); textPlayerCount = EnsureText(textPlayerCount, "Text_PlayerCount"); scrollPlayers = EnsureScroll(scrollPlayers, "Scroll_Players"); contentPlayers = EnsureTransform(contentPlayers, "Content_PlayersList"); emptyPlayers = EnsureGO(emptyPlayers, "Empty_Players"); playerItemTemplate = EnsureGO(playerItemTemplate, "PlayerItemTemplate"); btnInviteFriends = EnsureButton(btnInviteFriends, "Button_InviteFriends"); btnKickSelected = EnsureButton(btnKickSelected, "Button_KickSelected"); btnToggleReady = EnsureButton(btnToggleReady, "Button_ToggleReady"); btnStartGame = EnsureButton(btnStartGame, "Button_StartGame"); btnLeaveLobby = EnsureButton(btnLeaveLobby, "Button_LeaveLobby"); btnBackFromLobby = EnsureButton(btnBackFromLobby, "Button_BackFromLobby"); // Friends picker panelFriends = EnsureGO(panelFriends, "Panel_Friends"); contentFriends = EnsureTransform(contentFriends, "Content_FriendsList"); emptyFriends = EnsureGO(emptyFriends, "Empty_Friends"); btnBackFromFriends = EnsureButton(btnBackFromFriends, "Button_BackFromFriends"); btnCloseFriendsOverlay = EnsureButton(btnCloseFriendsOverlay, "Button_CloseFriendsOverlay"); EnsureSteamServices(); RegisterSteamEvents(); WireButtonEvents(); ValidateUI(); // Initial view: Host tab ShowHostTab(); UpdateUI(); } private void ShowFriendsPanel() { if (panelFriends) panelFriends.SetActive(true); EnsureFriendsGridSetup(); RebuildFriendsList(); } private void HideFriendsPanel() { if (panelFriends) panelFriends.SetActive(false); } private void RebuildFriendsList() { if (contentFriends == null || steam == null) return; // Clear existing var toDestroy = new List(); foreach (Transform child in contentFriends) toDestroy.Add(child.gameObject); foreach (var go in toDestroy) DestroyImmediate(go); var friends = steam.GetFriends(); if (friends.Count == 0) { if (emptyFriends) emptyFriends.SetActive(true); return; } if (emptyFriends) emptyFriends.SetActive(false); foreach (var f in friends) { // Icon button cell only var cell = new GameObject($"Friend_{f.steamId}", typeof(RectTransform), typeof(Image), typeof(Button)); cell.transform.SetParent(contentFriends, false); var img = cell.GetComponent(); if (steam.TryGetAvatarSprite(f.steamId, out var spr, false)) { img.sprite = spr; img.color = Color.white; img.preserveAspect = true; } else { img.sprite = null; img.color = new Color(0.3f,0.6f,0.3f,1f); } var rt = (RectTransform)cell.transform; rt.sizeDelta = new Vector2(72,72); var btn = cell.GetComponent