Files
bansonic_beta_main/Assets/scripts/UI/Panel/dontdestroyonload/btmandtopController.cs
T

1398 lines
45 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using UnityEngine.Audio;
using Bansonic;
using Steamworks;
using GameServer.Client;
public class btmandtopController : MonoBehaviour, ICancelHandler
{
public static event System.Action<bool> GlobalSettingsVisibilityChanged;
public static event System.Action<bool> GlobalOverlayPanelVisibilityChanged;
public static bool CurrentSettingsVisible { get; private set; }
public static bool CurrentOverlayPanelsVisible { get; private set; }
public event System.Action<bool> SettingsVisibilityChanged;
[Header("player unique so")]
public Player_SO player_SO;
public Text playerCoins_legacy;
public Text player_mmrFragment;
public Text player_rks;
[Header("put prefabs here")]
public GameObject putPrefabsHere;
[Header("son buttons")]
public Button settings_launch;
public Button userInfo_launch;
public Button store_launch;
public Button showLevel_display;
public Button email_display;
public Button notice_display;
public Button market_launch;
public Button button_userBag;
[Header("User Guide")]
[SerializeField] private Button userGuideButton;
[SerializeField] private Image guideDisplayImage;
[SerializeField] private Button preIMGb;
[SerializeField] private Button aftIMGb;
[SerializeField] private Button closeGuideButton;
[SerializeField] private Text guideIndexLegacyText;
[SerializeField] private List<GuideMapping> guideMappings;
[System.Serializable]
public struct GuideMapping
{
public string sceneName;
public List<Sprite> guideSprites;
}
public Button button_Music;
[Header("MusicPic")]
public RectTransform musicPicRoot;
public AudioMixerGroup bgmMixerGroup;
public bool showMusicPicInUI = false;
public string uiSceneName = "UI_UI";
public float musicPicFadeTime = 0.25f;
[Header("sig prefabs")]
public GameObject showLevel_prefab;
public GameObject store_prefab;
public GameObject settings_prefab;
public GameObject userInfo_prefab;
public GameObject email_prefab;
public GameObject notice_prefab;
public GameObject userBag_prefab;
[Header("mail red pot")]
public Image mailRedPot;
[Header("New Back Buttons")]
[SerializeField] private Button back_navButton;
[SerializeField] private Button home_navButton;
[SerializeField] private Button settings_navButton;
[SerializeField] private string homeSceneName = "UI_UI";
[SerializeField] private string backFallbackSceneName = "Main_main";
[Header("Scene Navigation Rules")]
[Tooltip("Define explicit back-navigation targets for specific scenes. This overrides the history-based navigation.")]
[SerializeField] private List<SceneNavigationRule> navigationRules;
[System.Serializable]
public struct SceneNavigationRule
{
public string sceneName;
[Tooltip("The scene to return to. If empty, falls back to history.")]
public string backTargetScene;
[Tooltip("Optional: Visual depth indicator (0=Root, 1=Chapter, etc)")]
public int depth;
}
[Header("Steam Integration")]
public Material steamMaterial;
public Text steamUserNameText;
public Text steamUserID64Text;
public Text steamStatusText;
public Image steamUserAvatarImage;
private UnityAction instantiateSettings;
private UnityAction instantiateUserInfo;
private UnityAction instantiateStore;
private UnityAction instantiateShowLevel;
private UnityAction instantiateEmail;
private UnityAction instantiateNotice;
private UnityAction navBackAction;
private UnityAction navHomeAction;
private UnityAction navSettingsAction;
private UnityAction navGuideAction;
private UnityAction instantiateMarket;
private UnityAction instantiateUserBag;
// cached reference to the settings instance to ensure only one exists
private GameObject settingsInstance;
private GameObject userInfoInstance;
private GameObject storeInstance;
private GameObject showLevelInstance;
private GameObject emailInstance;
private GameObject noticeInstance;
private GameObject userBagInstance;
private CanvasGroup musicPicGroup;
private Coroutine musicPicFade;
private bool musicPicVisible = true;
private bool navSceneLoading = false;
private bool lastSettingsVisibilityState;
private bool lastOverlayPanelsVisibilityState;
private readonly Dictionary<string, int> guideIndexByScene = new Dictionary<string, int>();
private string currentGuideScene = string.Empty;
private static btmandtopController activeInstance;
private static readonly List<string> sceneHistory = new List<string>();
private static bool sceneHistoryHooked = false;
private static string trackedCurrentScene = string.Empty;
void Awake()
{
activeInstance = this;
EnsureMusicPicRoot();
InitializeSceneHistoryIfNeeded();
}
void Start()
{
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(player_SO);
PlayerEconomyLedger.EnsureInstance().OnCoinsChanged += HandleCoinsChanged;
PlayerEconomyLedger.EnsureInstance().OnMaterialChanged += HandleMaterialChanged;
PlayerRksService.EnsureLoaded(player_SO);
PlayerRksService.OnRksChanged += HandleRksChanged;
UpdatePlayerCoinsLegacyText(PlayerEconomyLedger.EnsureInstance().GetCoins());
UpdatePlayerMmrFragmentText(PlayerEconomyLedger.EnsureInstance().GetMaterial());
UpdatePlayerRksText(PlayerRksService.GetBestOverallRks(player_SO));
if (button_Music == null)
{
var btn = transform.Find("Button_Music") as RectTransform;
if (btn != null)
button_Music = btn.GetComponent<Button>();
if (button_Music == null)
{
var any = FindByName("Button_Music");
if (any != null) button_Music = any.GetComponent<Button>();
}
}
instantiateSettings = () => ToggleSettingsPrefab();
instantiateUserInfo = () => ToggleUserInfoPrefab();
instantiateStore = () => { };
instantiateShowLevel = () => { gNotice.error.display("功能即将下线,禁止访问"); };
// instantiateShowLevel = () => ShowLevelPrefab();
instantiateEmail = () => ShowEmailPrefab();
instantiateNotice = () => { gNotice.warning.display("姝ょ増鏈鍔熻兘鏆備笉鍙敤"); };
// instantiateNotice = () => ShowNoticePrefab();
navGuideAction = () => ToggleGuideDisplay();
instantiateMarket = () => ShowStorePrefab();
instantiateUserBag = () => ShowUserBagPrefab();
if (settings_launch != null)
settings_launch.onClick.AddListener(instantiateSettings);
if (userInfo_launch != null)
userInfo_launch.onClick.AddListener(instantiateUserInfo);
if (store_launch != null)
store_launch.onClick.AddListener(instantiateStore);
if (showLevel_display != null)
showLevel_display.onClick.AddListener(instantiateShowLevel);
if (email_display != null)
email_display.onClick.AddListener(instantiateEmail);
if (notice_display != null)
notice_display.onClick.AddListener(instantiateNotice);
if (market_launch != null)
market_launch.onClick.AddListener(instantiateMarket);
if (button_userBag != null)
button_userBag.onClick.AddListener(instantiateUserBag);
if (userGuideButton != null)
userGuideButton.onClick.AddListener(navGuideAction);
if (preIMGb != null)
preIMGb.onClick.AddListener(ShowPreviousGuideImage);
if (aftIMGb != null)
aftIMGb.onClick.AddListener(ShowNextGuideImage);
if (closeGuideButton != null)
closeGuideButton.onClick.AddListener(CloseGuideDisplay);
BindNewBackButtons();
EnsureMusicPicRoot();
SetupMusicPicDefault();
if (button_Music != null)
button_Music.onClick.AddListener(ToggleMusicPicLocal);
UpdateSteamUserInfo();
InitializeMailRedPot();
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (binder != null && musicPicRoot != null)
{
binder.SetMusicRoot(musicPicRoot);
}
// Pre-instantiate settings prefab and keep it inactive, ensuring only one exists
if (settings_prefab != null && putPrefabsHere != null)
{
// Try to find existing one in scene first
if (settingsInstance == null)
{
var existing = GameObject.Find(settings_prefab.name + "(Clone)");
if (existing != null)
{
settingsInstance = existing;
}
}
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
EnsureSettingsEnterAnimator(settingsInstance);
EnsureSettingsLastSibling();
settingsInstance.SetActive(false);
// try to set canvas camera now as in previous behavior
try
{
Canvas c = settingsInstance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
}
cams = null;
c = null;
}
}
catch { }
}
else
{
// ensure it's parented correctly under putPrefabsHere
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
EnsureSettingsLastSibling();
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.SetActive(false);
}
}
if (userInfo_prefab != null && putPrefabsHere != null)
{
if (userInfoInstance == null)
{
var existing = GameObject.Find(userInfo_prefab.name + "(Clone)");
if (existing != null)
{
userInfoInstance = existing;
}
}
if (userInfoInstance == null)
{
userInfoInstance = Instantiate(userInfo_prefab, putPrefabsHere.transform);
TryAssignCanvasCamera(userInfoInstance);
PlacePanelBelowSettings(userInfoInstance);
userInfoInstance.SetActive(false);
}
else
{
userInfoInstance.transform.SetParent(putPrefabsHere.transform, false);
PlacePanelBelowSettings(userInfoInstance);
userInfoInstance.SetActive(false);
}
}
lastSettingsVisibilityState = IsSettingsPanelVisible;
lastOverlayPanelsVisibilityState = AreOverlayPanelsVisible();
CurrentOverlayPanelsVisible = lastOverlayPanelsVisibilityState;
}
private void FixedUpdate()
{
if(Input.GetKeyDown(KeyCode.Escape))
{
//ToggleSettingsPrefab();
}
}
private void Update()
{
if (!IsUiUiSceneActive())
{
if (CurrentSettingsVisible)
{
BroadcastSettingsVisibility(false);
}
if (CurrentOverlayPanelsVisible)
{
lastOverlayPanelsVisibilityState = false;
CurrentOverlayPanelsVisible = false;
GlobalOverlayPanelVisibilityChanged?.Invoke(false);
}
return;
}
bool visible = IsSettingsPanelVisible;
if (visible != lastSettingsVisibilityState)
{
BroadcastSettingsVisibility(visible);
}
bool overlayVisible = AreOverlayPanelsVisible();
if (overlayVisible != lastOverlayPanelsVisibilityState)
{
lastOverlayPanelsVisibilityState = overlayVisible;
CurrentOverlayPanelsVisible = overlayVisible;
GlobalOverlayPanelVisibilityChanged?.Invoke(overlayVisible);
}
}
private void ToggleMusicPic()
{
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (binder != null)
{
binder.ToggleMusicPic();
var spectrum = binder.GetSpectrumRoot();
if (spectrum != null && binder.transform != null)
{
spectrum.localRotation = binder.transform.localRotation;
}
}
}
private void EnsureMusicPicRoot()
{
if (musicPicRoot != null)
return;
var child = transform.Find("MusicPic");
if (child != null)
{
musicPicRoot = child as RectTransform;
return;
}
var sceneMusic = GameObject.Find("MusicPic");
if (sceneMusic != null)
{
musicPicRoot = sceneMusic.GetComponent<RectTransform>();
if (musicPicRoot != null)
{
musicPicRoot.SetParent(transform, false);
}
}
}
private void SetupMusicPicDefault()
{
if (musicPicRoot == null)
return;
EnsureMusicPicGroup();
SetMusicPicVisible(false, true);
}
private void EnsureMusicPicGroup()
{
if (musicPicRoot == null)
return;
if (musicPicGroup == null)
musicPicGroup = musicPicRoot.GetComponent<CanvasGroup>();
if (musicPicGroup == null)
musicPicGroup = musicPicRoot.gameObject.AddComponent<CanvasGroup>();
}
private void ToggleMusicPicLocal()
{
EnsureMusicPicRoot();
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (musicPicRoot == null)
{
if (binder != null)
binder.ToggleMusicPic();
return;
}
SetMusicPicVisible(!musicPicVisible, false);
}
private void SetMusicPicVisible(bool visible, bool instant)
{
if (musicPicRoot == null)
return;
EnsureMusicPicGroup();
musicPicVisible = visible;
if (musicPicFade != null)
{
StopCoroutine(musicPicFade);
musicPicFade = null;
}
if (instant)
{
musicPicGroup.alpha = visible ? 1f : 0f;
musicPicGroup.interactable = visible;
musicPicGroup.blocksRaycasts = visible;
musicPicRoot.gameObject.SetActive(visible);
return;
}
musicPicRoot.gameObject.SetActive(true);
musicPicFade = StartCoroutine(FadeMusicPic(visible));
}
private System.Collections.IEnumerator FadeMusicPic(bool visibleAtEnd)
{
EnsureMusicPicGroup();
if (musicPicGroup == null)
yield break;
float start = musicPicGroup != null ? musicPicGroup.alpha : 0f;
float target = visibleAtEnd ? 1f : 0f;
float t = 0f;
while (t < 1f)
{
if (musicPicGroup == null || musicPicRoot == null)
yield break;
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, musicPicFadeTime);
float eased = Mathf.SmoothStep(0f, 1f, t);
musicPicGroup.alpha = Mathf.LerpUnclamped(start, target, eased);
yield return null;
}
if (musicPicGroup != null)
{
musicPicGroup.alpha = target;
musicPicGroup.interactable = visibleAtEnd;
musicPicGroup.blocksRaycasts = visibleAtEnd;
}
if (!visibleAtEnd && musicPicRoot != null)
{
musicPicRoot.gameObject.SetActive(false);
}
}
GameObject FindByName(string name)
{
var all = Resources.FindObjectsOfTypeAll<Transform>();
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded) continue;
if (t.name == name) return t.gameObject;
}
return null;
}
void OnDestroy()
{
if (musicPicFade != null)
{
StopCoroutine(musicPicFade);
musicPicFade = null;
}
musicPicGroup = null;
if (settings_launch != null)
settings_launch.onClick.RemoveListener(instantiateSettings);
if (userInfo_launch != null)
userInfo_launch.onClick.RemoveListener(instantiateUserInfo);
if (store_launch != null)
store_launch.onClick.RemoveListener(instantiateStore);
if (showLevel_display != null)
showLevel_display.onClick.RemoveListener(instantiateShowLevel);
if (email_display != null)
email_display.onClick.RemoveListener(instantiateEmail);
if (notice_display != null)
notice_display.onClick.RemoveListener(instantiateNotice);
if (market_launch != null)
market_launch.onClick.RemoveListener(instantiateMarket);
if (button_userBag != null)
button_userBag.onClick.RemoveListener(instantiateUserBag);
if (userGuideButton != null)
userGuideButton.onClick.RemoveListener(navGuideAction);
if (preIMGb != null)
preIMGb.onClick.RemoveListener(ShowPreviousGuideImage);
if (aftIMGb != null)
aftIMGb.onClick.RemoveListener(ShowNextGuideImage);
if (closeGuideButton != null)
closeGuideButton.onClick.RemoveListener(CloseGuideDisplay);
if (button_Music != null)
button_Music.onClick.RemoveListener(ToggleMusicPicLocal);
if (back_navButton != null && navBackAction != null)
back_navButton.onClick.RemoveListener(navBackAction);
if (home_navButton != null && navHomeAction != null)
home_navButton.onClick.RemoveListener(navHomeAction);
if (settings_navButton != null && navSettingsAction != null)
settings_navButton.onClick.RemoveListener(navSettingsAction);
if (PlayerEconomyLedger.Instance != null)
{
PlayerEconomyLedger.Instance.OnCoinsChanged -= HandleCoinsChanged;
PlayerEconomyLedger.Instance.OnMaterialChanged -= HandleMaterialChanged;
}
PlayerRksService.OnRksChanged -= HandleRksChanged;
UI_Panel_Mail.OnUnreadStateChanged -= HandleMailUnreadStateChanged;
if (MailHttpService.Instance != null)
{
MailHttpService.Instance.OnMailListChanged -= HandleMailListChanged;
}
if (ReferenceEquals(activeInstance, this))
{
activeInstance = null;
}
}
private void HandleCoinsChanged(int coinAmount)
{
UpdatePlayerCoinsLegacyText(coinAmount);
}
private void HandleMaterialChanged(int materialAmount)
{
UpdatePlayerMmrFragmentText(materialAmount);
}
private void HandleRksChanged(float rksAmount)
{
UpdatePlayerRksText(rksAmount);
}
private void InitializeMailRedPot()
{
if (mailRedPot == null)
{
return;
}
bool useServerMail = false;
if (email_prefab != null)
{
UI_Panel_Mail mailPanel = email_prefab.GetComponent<UI_Panel_Mail>();
if (mailPanel != null)
{
useServerMail = mailPanel.UsesServerMail;
}
}
if (useServerMail && MailHttpService.Instance != null)
{
MailHttpService.Instance.SetServerModeEnabled(true);
MailHttpService.Instance.OnMailListChanged -= HandleMailListChanged;
MailHttpService.Instance.OnMailListChanged += HandleMailListChanged;
}
UI_Panel_Mail.OnUnreadStateChanged -= HandleMailUnreadStateChanged;
UI_Panel_Mail.OnUnreadStateChanged += HandleMailUnreadStateChanged;
UpdateMailRedPot();
}
private void HandleMailUnreadStateChanged()
{
UpdateMailRedPot();
}
private void HandleMailListChanged(IReadOnlyList<MailApiEntry> _)
{
UpdateMailRedPot();
}
private void UpdateMailRedPot()
{
if (mailRedPot == null)
{
return;
}
bool useServerMail = false;
if (email_prefab != null)
{
UI_Panel_Mail mailPanel = email_prefab.GetComponent<UI_Panel_Mail>();
if (mailPanel != null)
{
useServerMail = mailPanel.UsesServerMail;
}
}
mailRedPot.enabled = UI_Panel_Mail.HasUnreadMails(useServerMail);
}
private void UpdatePlayerCoinsLegacyText(int coinAmount)
{
if (playerCoins_legacy != null)
{
playerCoins_legacy.text = coinAmount.ToString();
}
}
private void UpdatePlayerMmrFragmentText(int fragmentAmount)
{
if (player_mmrFragment != null)
{
player_mmrFragment.text = fragmentAmount.ToString();
}
}
private void UpdatePlayerRksText(float rksAmount)
{
if (player_rks == null)
{
player_rks = FindLegacyTextByLiteral("player_rks");
}
if (player_rks != null)
{
player_rks.text = rksAmount.ToString("F2");
}
}
private Text FindLegacyTextByLiteral(string literal)
{
if (string.IsNullOrEmpty(literal))
{
return null;
}
Text[] texts = GetComponentsInChildren<Text>(true);
for (int i = 0; i < texts.Length; i++)
{
if (texts[i] != null && texts[i].text == literal)
{
return texts[i];
}
}
return null;
}
private void ToggleGuideDisplay()
{
if (guideDisplayImage == null)
{
return;
}
if (guideDisplayImage.gameObject.activeSelf)
{
CloseGuideDisplay();
}
else
{
string currentScene = SceneManager.GetActiveScene().name;
ShowGuideForScene(currentScene, true);
}
}
private void CloseGuideDisplay()
{
if (guideDisplayImage == null) return;
guideDisplayImage.gameObject.SetActive(false);
UpdateGuideIndexText(-1, 0);
SetGuideButtonsInteractable(false);
}
public void OnCancel(BaseEventData eventData)
{
if (guideDisplayImage != null && guideDisplayImage.gameObject.activeSelf)
CloseGuideDisplay();
}
private void ShowGuideForScene(string sceneName, bool allowStoredIndex)
{
if (!TryGetGuideMapping(sceneName, out var mapping))
{
gNotice.warning.display("未找到指引信息");
return;
}
int count = GetGuideSpriteCount(mapping);
if (count <= 0)
{
gNotice.warning.display("未找到指引信息");
return;
}
int index = 0;
if (allowStoredIndex && guideIndexByScene.TryGetValue(sceneName, out var storedIndex))
index = storedIndex;
index = Mathf.Clamp(index, 0, count - 1);
ApplyGuideSprite(sceneName, mapping, index, count);
}
private void ShowPreviousGuideImage()
{
if (guideDisplayImage == null || !guideDisplayImage.gameObject.activeSelf) return;
if (string.IsNullOrEmpty(currentGuideScene))
currentGuideScene = SceneManager.GetActiveScene().name;
if (!TryGetGuideMapping(currentGuideScene, out var mapping)) return;
int count = GetGuideSpriteCount(mapping);
if (count <= 0) return;
int index = 0;
guideIndexByScene.TryGetValue(currentGuideScene, out index);
index = Mathf.Clamp(index - 1, 0, count - 1);
ApplyGuideSprite(currentGuideScene, mapping, index, count);
}
private void ShowNextGuideImage()
{
if (guideDisplayImage == null || !guideDisplayImage.gameObject.activeSelf) return;
if (string.IsNullOrEmpty(currentGuideScene))
currentGuideScene = SceneManager.GetActiveScene().name;
if (!TryGetGuideMapping(currentGuideScene, out var mapping)) return;
int count = GetGuideSpriteCount(mapping);
if (count <= 0) return;
int index = 0;
guideIndexByScene.TryGetValue(currentGuideScene, out index);
index = Mathf.Clamp(index + 1, 0, count - 1);
ApplyGuideSprite(currentGuideScene, mapping, index, count);
}
private void ApplyGuideSprite(string sceneName, GuideMapping mapping, int index, int count)
{
Sprite targetSprite = GetGuideSpriteAt(mapping, index);
if (targetSprite == null)
{
gNotice.warning.display("未找到指引信息");
return;
}
guideDisplayImage.sprite = targetSprite;
guideDisplayImage.gameObject.SetActive(true);
currentGuideScene = sceneName;
guideIndexByScene[sceneName] = index;
UpdateGuideIndexText(index, count);
SetGuideButtonsInteractable(count > 1);
}
private void UpdateGuideIndexText(int index, int count)
{
string text = count > 0 && index >= 0 ? $"{index + 1}/{count}" : string.Empty;
if (guideIndexLegacyText != null) guideIndexLegacyText.text = text;
}
private void SetGuideButtonsInteractable(bool enabled)
{
if (preIMGb != null) preIMGb.interactable = enabled;
if (aftIMGb != null) aftIMGb.interactable = enabled;
}
private bool TryGetGuideMapping(string sceneName, out GuideMapping mapping)
{
mapping = default;
if (guideMappings == null) return false;
for (int i = 0; i < guideMappings.Count; i++)
{
if (guideMappings[i].sceneName == sceneName)
{
mapping = guideMappings[i];
return true;
}
}
return false;
}
private int GetGuideSpriteCount(GuideMapping mapping)
{
if (mapping.guideSprites != null) return mapping.guideSprites.Count;
return 0;
}
private Sprite GetGuideSpriteAt(GuideMapping mapping, int index)
{
if (mapping.guideSprites == null || mapping.guideSprites.Count == 0) return null;
return mapping.guideSprites[Mathf.Clamp(index, 0, mapping.guideSprites.Count - 1)];
}
private void ToggleSettingsPrefab()
{
if (settings_prefab == null || putPrefabsHere == null) return;
// If we don't have an instance (it may have been destroyed), instantiate one
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
EnsureSettingsEnterAnimator(settingsInstance);
EnsureSettingsLastSibling();
// attempt to set canvas camera
try
{
Canvas c = settingsInstance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
}
cams = null;
c = null;
}
}
catch { }
settingsInstance.SetActive(true);
EnsureSettingsLastSibling();
BroadcastSettingsVisibility(true);
BroadcastOverlayPanelsVisibility();
return;
}
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
EnsureSettingsLastSibling();
// Toggle active state
bool active = settingsInstance.activeSelf;
settingsInstance.SetActive(!active);
if (settingsInstance.activeSelf)
{
EnsureSettingsLastSibling();
}
BroadcastSettingsVisibility(settingsInstance.activeSelf);
BroadcastOverlayPanelsVisibility();
}
public bool IsSettingsPanelVisible
{
get { return settingsInstance != null && settingsInstance.activeInHierarchy; }
}
private void ToggleUserInfoPrefab()
{
if (userInfo_prefab == null || putPrefabsHere == null) return;
if (userInfoInstance == null)
{
userInfoInstance = Instantiate(userInfo_prefab, putPrefabsHere.transform);
TryAssignCanvasCamera(userInfoInstance);
PlacePanelBelowSettings(userInfoInstance);
userInfoInstance.SetActive(true);
BroadcastOverlayPanelsVisibility();
return;
}
userInfoInstance.transform.SetParent(putPrefabsHere.transform, false);
userInfoInstance.SetActive(!userInfoInstance.activeSelf);
if (userInfoInstance.activeSelf)
{
PlacePanelBelowSettings(userInfoInstance);
}
BroadcastOverlayPanelsVisibility();
}
private void BroadcastSettingsVisibility(bool visible)
{
lastSettingsVisibilityState = visible;
if (CurrentSettingsVisible == visible)
{
SettingsVisibilityChanged?.Invoke(visible);
return;
}
CurrentSettingsVisible = visible;
SettingsVisibilityChanged?.Invoke(visible);
GlobalSettingsVisibilityChanged?.Invoke(visible);
}
private bool IsUiUiSceneActive()
{
string sceneName = SceneManager.GetActiveScene().name;
string targetScene = string.IsNullOrWhiteSpace(uiSceneName) ? "UI_UI" : uiSceneName;
return string.Equals(sceneName, targetScene, System.StringComparison.OrdinalIgnoreCase);
}
private bool AreOverlayPanelsVisible()
{
return (settingsInstance != null && settingsInstance.activeInHierarchy)
|| (storeInstance != null && storeInstance.activeInHierarchy)
|| (showLevelInstance != null && showLevelInstance.activeInHierarchy)
|| (emailInstance != null && emailInstance.activeInHierarchy)
|| (noticeInstance != null && noticeInstance.activeInHierarchy)
|| (userBagInstance != null && userBagInstance.activeInHierarchy);
}
private void BroadcastOverlayPanelsVisibility()
{
bool visible = AreOverlayPanelsVisible();
lastOverlayPanelsVisibilityState = visible;
CurrentOverlayPanelsVisible = visible;
GlobalOverlayPanelVisibilityChanged?.Invoke(visible);
}
private void ShowLevelPrefab()
{
if (ToggleIfAlreadyOpen(ref showLevelInstance))
{
return;
}
if (OpenPrefab(showLevel_prefab, ref showLevelInstance))
{
CloseInfoPanels(showLevelInstance);
}
}
private void ShowStorePrefab()
{
if (ToggleIfAlreadyOpen(ref storeInstance))
{
return;
}
if (OpenPrefab(store_prefab, ref storeInstance))
{
CloseInfoPanels(storeInstance);
}
}
private void ShowEmailPrefab()
{
if (ToggleIfAlreadyOpen(ref emailInstance))
{
return;
}
if (OpenPrefab(email_prefab, ref emailInstance))
{
CloseInfoPanels(emailInstance);
}
}
private void ShowNoticePrefab()
{
if (ToggleIfAlreadyOpen(ref noticeInstance))
{
return;
}
if (OpenPrefab(notice_prefab, ref noticeInstance))
{
CloseInfoPanels(noticeInstance);
}
}
private void ShowUserBagPrefab()
{
if (ToggleIfAlreadyOpen(ref userBagInstance))
{
return;
}
if (OpenPrefab(userBag_prefab, ref userBagInstance))
{
CloseInfoPanels(userBagInstance);
}
}
private bool ToggleIfAlreadyOpen(ref GameObject instance)
{
if (instance == null)
{
return false;
}
if (!instance.activeInHierarchy)
{
return false;
}
instance.SetActive(false);
BroadcastOverlayPanelsVisibility();
return true;
}
private bool OpenPrefab(GameObject prefab, ref GameObject instance)
{
if (prefab == null || putPrefabsHere == null) return false;
if (instance == null)
{
instance = FindExistingInstance(prefab);
if (instance == null)
{
instance = Instantiate(prefab, putPrefabsHere.transform);
TryAssignCanvasCamera(instance);
}
else
{
instance.transform.SetParent(putPrefabsHere.transform, false);
}
}
if (instance == null)
{
return false;
}
if (!instance.activeSelf)
{
instance.SetActive(true);
}
PlacePanelBelowSettings(instance);
BroadcastOverlayPanelsVisibility();
return true;
}
private void EnsureSettingsLastSibling()
{
if (settingsInstance == null || putPrefabsHere == null)
{
return;
}
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
settingsInstance.transform.SetAsLastSibling();
}
private void PlacePanelBelowSettings(GameObject instance)
{
if (instance == null || putPrefabsHere == null)
{
return;
}
instance.transform.SetParent(putPrefabsHere.transform, false);
if (settingsInstance == null || instance == settingsInstance)
{
instance.transform.SetAsLastSibling();
return;
}
EnsureSettingsLastSibling();
int settingsIndex = settingsInstance.transform.GetSiblingIndex();
int targetIndex = Mathf.Clamp(settingsIndex, 0, putPrefabsHere.transform.childCount - 1);
instance.transform.SetSiblingIndex(targetIndex);
EnsureSettingsLastSibling();
}
private void CloseInfoPanels(GameObject keep)
{
CloseInstance(ref storeInstance, keep);
CloseInstance(ref showLevelInstance, keep);
CloseInstance(ref emailInstance, keep);
CloseInstance(ref noticeInstance, keep);
CloseInstance(ref userBagInstance, keep);
}
private void CloseInstance(ref GameObject instance, GameObject keep)
{
if (instance == null || instance == keep) return;
instance.SetActive(false);
BroadcastOverlayPanelsVisibility();
}
private GameObject FindExistingInstance(GameObject prefab)
{
if (prefab == null || putPrefabsHere == null) return null;
Transform parent = putPrefabsHere.transform;
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child == null) continue;
if (child.name == prefab.name || child.name == prefab.name + "(Clone)")
{
return child.gameObject;
}
}
GameObject existing = GameObject.Find(prefab.name + "(Clone)");
return existing;
}
private void TryAssignCanvasCamera(GameObject instance)
{
if (instance == null) return;
try
{
Canvas c = instance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
}
}
}
catch { }
}
public static void RefreshOverlayVisibilityState()
{
if (activeInstance != null)
{
activeInstance.BroadcastOverlayPanelsVisibility();
return;
}
CurrentOverlayPanelsVisible = false;
GlobalOverlayPanelVisibilityChanged?.Invoke(false);
}
private void InstantiatePrefab(GameObject prefab)
{
if (prefab != null && putPrefabsHere != null)
{
GameObject instance = Instantiate(prefab, putPrefabsHere.transform);
instance = null;
}
}
private void EnsureSettingsEnterAnimator(GameObject instance)
{
if (instance == null) return;
UI_SettingsPanelEnterAnim anim = instance.GetComponent<UI_SettingsPanelEnterAnim>();
if (anim == null)
anim = instance.AddComponent<UI_SettingsPanelEnterAnim>();
anim.enabled = true;
}
private void BindNewBackButtons()
{
ResolveNewBackButtons();
navBackAction = OnBackNavClicked;
navHomeAction = OnHomeNavClicked;
navSettingsAction = OnSettingsNavClicked;
if (back_navButton != null)
{
back_navButton.onClick.RemoveListener(navBackAction);
back_navButton.onClick.AddListener(navBackAction);
}
if (home_navButton != null)
{
home_navButton.onClick.RemoveListener(navHomeAction);
home_navButton.onClick.AddListener(navHomeAction);
}
if (settings_navButton != null)
{
settings_navButton.onClick.RemoveListener(navSettingsAction);
settings_navButton.onClick.AddListener(navSettingsAction);
}
}
private void ResolveNewBackButtons()
{
Transform navRoot = FindChildRecursive(transform, "New back");
if (navRoot == null)
{
GameObject sceneRoot = FindByName("New back");
if (sceneRoot != null)
navRoot = sceneRoot.transform;
}
if (back_navButton == null)
back_navButton = FindButtonByName(navRoot, "back");
if (home_navButton == null)
home_navButton = FindButtonByName(navRoot, "home");
if (settings_navButton == null)
settings_navButton = FindButtonByName(navRoot, "settings");
}
private static Transform FindChildRecursive(Transform root, string childName)
{
if (root == null || string.IsNullOrEmpty(childName)) return null;
if (root.name == childName) return root;
for (int i = 0; i < root.childCount; i++)
{
Transform child = root.GetChild(i);
Transform found = FindChildRecursive(child, childName);
if (found != null) return found;
}
return null;
}
private static Button FindButtonByName(Transform root, string name)
{
if (string.IsNullOrEmpty(name)) return null;
if (root != null)
{
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button btn = buttons[i];
if (btn != null && string.Equals(btn.gameObject.name, name, System.StringComparison.OrdinalIgnoreCase))
return btn;
}
}
return null;
}
private static void InitializeSceneHistoryIfNeeded()
{
if (sceneHistoryHooked) return;
sceneHistoryHooked = true;
trackedCurrentScene = SceneManager.GetActiveScene().name ?? string.Empty;
SceneManager.sceneLoaded += OnSceneLoadedTrackHistory;
}
private static void OnSceneLoadedTrackHistory(Scene scene, LoadSceneMode mode)
{
string incoming = scene.name ?? string.Empty;
if (!string.IsNullOrEmpty(trackedCurrentScene) &&
!string.Equals(trackedCurrentScene, incoming, System.StringComparison.OrdinalIgnoreCase))
{
if (sceneHistory.Count == 0 ||
!string.Equals(sceneHistory[sceneHistory.Count - 1], trackedCurrentScene, System.StringComparison.OrdinalIgnoreCase))
{
sceneHistory.Add(trackedCurrentScene);
if (sceneHistory.Count > 24) sceneHistory.RemoveAt(0);
}
}
trackedCurrentScene = incoming;
}
private static string PopPreviousSceneName(string currentScene)
{
for (int i = sceneHistory.Count - 1; i >= 0; i--)
{
string candidate = sceneHistory[i];
sceneHistory.RemoveAt(i);
if (string.IsNullOrEmpty(candidate)) continue;
if (string.Equals(candidate, currentScene, System.StringComparison.OrdinalIgnoreCase)) continue;
return candidate;
}
return null;
}
private void OnBackNavClicked()
{
if (navSceneLoading) return;
InitializeSceneHistoryIfNeeded();
string current = SceneManager.GetActiveScene().name ?? string.Empty;
string target = null;
if (navigationRules != null)
{
foreach (var rule in navigationRules)
{
if (string.Equals(rule.sceneName, current, System.StringComparison.OrdinalIgnoreCase))
{
if (!string.IsNullOrEmpty(rule.backTargetScene))
{
target = rule.backTargetScene;
}
break;
}
}
}
if (string.IsNullOrEmpty(target))
{
target = PopPreviousSceneName(current);
}
if (string.IsNullOrEmpty(target))
{
target = string.IsNullOrEmpty(backFallbackSceneName) ? "Main_main" : backFallbackSceneName;
}
if (!string.IsNullOrEmpty(target) &&
!string.Equals(target, current, System.StringComparison.OrdinalIgnoreCase))
{
StartCoroutine(LoadNavSceneAsync(target));
}
}
private void OnHomeNavClicked()
{
if (navSceneLoading) return;
string target = string.IsNullOrEmpty(homeSceneName) ? "UI_UI" : homeSceneName;
StartCoroutine(LoadNavSceneAsync(target));
}
private void OnSettingsNavClicked()
{
ToggleSettingsPrefab();
}
private System.Collections.IEnumerator LoadNavSceneAsync(string sceneName)
{
if (string.IsNullOrEmpty(sceneName)) yield break;
if (navSceneLoading) yield break;
navSceneLoading = true;
Time.timeScale = 1f;
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
while (op != null && !op.isDone)
{
yield return null;
}
navSceneLoading = false;
}
public void UpdateSteamUserInfo()
{
if (!SteamManager.Initialized)
{
Debug.LogWarning("[Steam] SteamManager not initialized.");
if (steamStatusText != null)
steamStatusText.text = "Unknown Server";
return;
}
try
{
CSteamID steamID = SteamUser.GetSteamID();
if (steamUserNameText != null)
steamUserNameText.text = SteamFriends.GetPersonaName();
if (steamUserID64Text != null)
steamUserID64Text.text = "Uid : " + steamID.m_SteamID.ToString();
// Online status check
EPersonaState state = SteamFriends.GetPersonaState();
bool isOffline = (state == EPersonaState.k_EPersonaStateOffline);
if (steamStatusText != null)
{
steamStatusText.text = isOffline ? "Steam Offline" : "Steam Online";
}
if (steamUserAvatarImage != null)
{
// Assign material if offline, otherwise set to null (default)
steamUserAvatarImage.material = isOffline ? steamMaterial : null;
int iImage = SteamFriends.GetMediumFriendAvatar(steamID);
if (iImage != -1)
{
uint width, height;
if (SteamUtils.GetImageSize(iImage, out width, out height))
{
byte[] imageBuffer = new byte[width * height * 4];
if (SteamUtils.GetImageRGBA(iImage, imageBuffer, (int)(width * height * 4)))
{
Texture2D texture = new Texture2D((int)width, (int)height, TextureFormat.RGBA32, false);
texture.LoadRawTextureData(imageBuffer);
texture.Apply();
// Flip the texture vertically because Steam returns it upside down
Texture2D flipped = new Texture2D((int)width, (int)height, TextureFormat.RGBA32, false);
for (int y = 0; y < (int)height; y++)
{
Color[] pixels = texture.GetPixels(0, y, (int)width, 1);
flipped.SetPixels(0, (int)height - 1 - y, (int)width, 1, pixels);
}
flipped.Apply();
steamUserAvatarImage.sprite = Sprite.Create(flipped, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f));
}
}
}
}
}
catch (System.Exception e)
{
Debug.LogError("[Steam] Error updating steam info: " + e);
if (steamStatusText != null)
steamStatusText.text = "Unknown Server";
}
}
}