using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using Photon.Pun; using Photon.Realtime; using TMPro; using System.Collections.Generic; // หน้าหลัก คลังยาน และการโหลดข้อมูลเพื่อแสดงผล; ยังใช้ LobbyManager เดิม // Runtime view keeps existing scene button bindings and inventory intact. public partial class LobbyManager { private bool profileLoaded; private bool shipLoaded, skillLoaded, readyPending, reconnecting; private int profileGeneration; private string previousRoom; private float profileDeadline, reconnectDeadline, nextStatusRefresh; private TMP_Text lobbyMessage, browserMessage, connectionText, readyHint, emptyRoomsText; private readonly List fittedRoots = new List(); private readonly List mapCardGroups = new List(); private readonly List mapLabelGroups = new List(); private readonly string[] mapDescriptions = { "Cover and side routes.\nEnergy core: trade HP for fire rate.\nHazard: lightning strikes.", "Crystals bounce your shots.\nWarp gates link the corners.\nHazard: slowing pools.", "12 rocks / 2 turrets / 6 red cores.\nUse cover around the wreck.\nHazard: falling lava asteroids." }; private readonly string[] mapShortNames = { "JELLYFISH CORE", "PRISM PLAINS", "MECH WARZONE" }; private readonly Color panelColor = new Color(0.035f, 0.065f, 0.12f, 0.97f); private readonly Color accentColor = new Color(0.23f, 0.82f, 0.92f); private TMP_FontAsset lobbyFont; private TMP_Text homeSkillText; private TMP_Text hangarMessage; private TMP_Text hangarCoinText; private void UpdateCoinDisplay(long coins) { if (coinText != null) coinText.text = "Astronium Coins : " + coins; if (hangarCoinText != null) hangarCoinText.text = "ASTRONIUM / " + coins.ToString("N0"); } private bool hangarBusy; private Button[] hangarSkillCards; private TMP_Text[] hangarSkillStates; private TMP_Text[] hangarCardLabels; private GameObject hangarShipsPage, hangarSkillsPage; private void LoadLobbyProfile() { int generation = ++profileGeneration; profileLoaded = shipLoaded = skillLoaded = false; if (inventoryButton != null) inventoryButton.interactable = false; profileDeadline = Time.unscaledTime + 20f; EnablePlayButtons(false); UpdateStatus("Loading your ship and skill..."); if (FirebaseManager.Instance == null) { // Direct editor entry uses an explicit default loadout. equippedShipIndex = equippedSkillIndex = 0; shipLoaded = skillLoaded = true; FinishProfileLoad(); return; } if (playerNameText != null) { playerNameText.richText = false; playerNameText.text = FirebaseManager.Instance.GetUsername(); } FirebaseManager.Instance.GetPlayerStats((highScore, wins, losses) => { if (this == null || generation != profileGeneration || winsText == null) return; winsText.text = $"HIGH SCORE {highScore:N0} W {wins:N0} / L {losses:N0}"; }); FirebaseManager.Instance.GetCoinBalance(coins => { if (this == null || generation != profileGeneration) return; UpdateCoinDisplay(coins); }, error => { if (this == null || generation != profileGeneration) return; if (coinText != null) coinText.text = "Astronium Coins : unavailable"; if (hangarCoinText != null) hangarCoinText.text = "ASTRONIUM / unavailable"; UpdateStatus(error); }); FirebaseManager.Instance.GetUnlockedShips(result => { if (this == null || generation != profileGeneration) return; unlockedShips = result ?? new List { 0 }; if (!unlockedShips.Contains(0)) unlockedShips.Add(0); FirebaseManager.Instance.GetSelectedShip(index => { if (this == null || generation != profileGeneration) return; equippedShipIndex = index >= 0 && index < ships.Length && unlockedShips.Contains(index) ? index : 0; selectedShipIndex = equippedShipIndex; shipLoaded = true; FinishProfileLoad(); }); }); FirebaseManager.Instance.GetSelectedSkill(index => { if (this == null || generation != profileGeneration) return; equippedSkillIndex = Mathf.Clamp(index, 0, skills.Length - 1); selectedSkillIndex = equippedSkillIndex; skillLoaded = true; FinishProfileLoad(); }); } private void FinishProfileLoad() { profileLoaded = shipLoaded && skillLoaded; if (!profileLoaded) return; if (inventoryButton != null) inventoryButton.interactable = true; UpdateShipDisplay(equippedShipIndex); UpdateSkillDisplay(equippedSkillIndex); if (PhotonNetwork.InRoom) PublishLocalLoadout(true); EnablePlayButtons(true); RenderRoomList(); UpdateStatus(PhotonNetwork.IsConnectedAndReady ? "Loadout ready. Create or join a room." : "Loadout ready. Connecting..."); } public void RetryLobbyConnection() { if (roomRequestPending || reconnecting || PhotonNetwork.InRoom) return; if (!profileLoaded) LoadLobbyProfile(); if (!PhotonNetwork.IsConnected) { UpdateStatus("Connecting..."); PhotonNetwork.ConnectUsingSettings(); } else if (PhotonNetwork.IsConnectedAndReady && !PhotonNetwork.InLobby) PhotonNetwork.JoinLobby(); } private void RoomRequestFailed() { roomRequestPending = false; EnablePlayButtons(true); RenderRoomList(); UpdateStatus("Could not send the request. Please try again."); } public void CopyRoomCode() { if (!PhotonNetwork.InRoom) return; GUIUtility.systemCopyBuffer = PhotonNetwork.CurrentRoom.Name; UpdateStatus("Room code copied. Share it with your friend."); } private static void SetButtonLabel(Button button, string label) { TMP_Text text = button.GetComponentInChildren(true); if (text != null) text.text = label; } private RectTransform UIRect(string name, Transform parent, float x, float y, float width, float height) { var rect = parent.Find(name) as RectTransform; if (rect == null) { var go = new GameObject(name, typeof(RectTransform)); go.layer = parent.gameObject.layer; rect = go.GetComponent(); rect.SetParent(parent, false); rect.anchorMin = rect.anchorMax = new Vector2(0.5f, 0.5f); rect.sizeDelta = new Vector2(width, height); rect.anchoredPosition = new Vector2(x, y); #if UNITY_EDITOR if (!Application.isPlaying) UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Create editable lobby UI"); #endif } return rect; } private Image UIPanel(string name, Transform parent, float x, float y, float width, float height, Color color) { bool initializeStyle = parent.Find(name) == null; RectTransform rect = UIRect(name, parent, x, y, width, height); Image img = rect.GetComponent(); if (img == null) { img = rect.gameObject.AddComponent(); initializeStyle = true; } if (initializeStyle) { img.color = color; img.raycastTarget = false; } return img; } private TMP_Text UILabel(string name, Transform parent, string value, float x, float y, float w, float h, int size, Color color) { RectTransform rect = UIRect(name, parent, x, y, w, h); var text = rect.GetComponent(); bool initializeStyle = text == null; if (initializeStyle) text = rect.gameObject.AddComponent(); if (text.font == null) { if (lobbyFont != null) text.font = lobbyFont; initializeStyle = true; } text.text = value; if (initializeStyle) { text.fontSize = size; text.enableAutoSizing = true; text.fontSizeMin = Mathf.Max(12, size - 5); text.fontSizeMax = size; text.textWrappingMode = TextWrappingModes.Normal; text.color = color; text.alignment = TextAlignmentOptions.Center; text.overflowMode = TextOverflowModes.Ellipsis; text.raycastTarget = false; } return text; } private Button UIButton(string name, Transform parent, string value, float x, float y, float w, float h, UnityEngine.Events.UnityAction action) { Image image = UIPanel(name, parent, x, y, w, h, new Color(0.08f, 0.26f, 0.36f)); image.raycastTarget = true; Button button = image.GetComponent