Files
2026-07-20 22:19:25 +08:00

1906 lines
60 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using UnityEngine.Audio;
using DG.Tweening;
using Bansonic;
#if UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX
using Steamworks;
#endif
using GameServer.Client;
public class btmandtopController : MonoBehaviour, ICancelHandler
{
private const string MusicLockedMessage = "暂无可选择的音乐";
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;
public Image rksProgressImage;
[Header("currency hover")]
public Button mmrFragmentHoverButton;
public Button coinsHoverButton;
public CanvasGroup mmrFragmentHoverCanvasGroup;
public CanvasGroup coinsHoverCanvasGroup;
[Min(0.01f)] public float currencyHoverFadeDuration = 0.25f;
[Header("put prefabs here")]
public GameObject putPrefabsHere;
public GameObject putSettingsPrefabHere;
[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")]
[Tooltip("是否启用指引 sprite 展示。true:点击指引按钮时按场景展示 guideMappings 的 spritefalse:点击无反应,不展示任何指引。")]
[SerializeField] private bool enableGuideDisplay = true;
[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 Coroutine deferredUiRefreshRoutine;
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 RectTransform topNavigationRoot;
private bool topNavigationGeometryDirty = true;
private int lastTopNavigationParentChildCount = -1;
private Tween mmrFragmentHoverTween;
private Tween coinsHoverTween;
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());
float currentRks = PlayerRksService.GetBestOverallRks(player_SO);
UpdatePlayerRksText(currentRks);
UpdateRksProgressImage(currentRks);
SetupCurrencyHoverIndicators();
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 = SceneObjectLookupCache.Find("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();
EnsureTopNavigationFront();
ScheduleDeferredUiRefresh();
EnsureMusicPicRoot();
SetupMusicPicDefault();
if (button_Music != null)
button_Music.onClick.AddListener(HandleMusicButtonLockedClick);
UpdateSteamUserInfo();
InitializeMailRedPot();
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : SceneObjectLookupCache.FindAny<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 && GetSettingsParentTransform() != null)
{
// Try to find existing one in scene first
if (settingsInstance == null)
{
var existing = SceneObjectLookupCache.Find(settings_prefab.name + "(Clone)");
if (existing != null)
{
settingsInstance = existing;
}
}
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, GetSettingsParentTransform());
AttachManagedPanelVisibilityRelay(settingsInstance, true);
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 beside putPrefabsHere
settingsInstance.transform.SetParent(GetSettingsParentTransform(), false);
AttachManagedPanelVisibilityRelay(settingsInstance, true);
EnsureSettingsLastSibling();
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.SetActive(false);
}
}
if (userInfo_prefab != null && putPrefabsHere != null)
{
if (userInfoInstance == null)
{
var existing = SceneObjectLookupCache.Find(userInfo_prefab.name + "(Clone)");
if (existing != null)
{
userInfoInstance = existing;
}
}
if (userInfoInstance == null)
{
userInfoInstance = Instantiate(userInfo_prefab, putPrefabsHere.transform);
AttachManagedPanelVisibilityRelay(userInfoInstance, false);
userInfoInstance.SetActive(false);
}
else
{
userInfoInstance.transform.SetParent(putPrefabsHere.transform, false);
AttachManagedPanelVisibilityRelay(userInfoInstance, false);
userInfoInstance.SetActive(false);
}
}
SyncManagedPanelVisibilityState(true);
}
private void OnTransformChildrenChanged()
{
if (!IsUiUiSceneActive())
{
return;
}
topNavigationGeometryDirty = true;
EnsureTopNavigationFront();
}
internal void NotifyManagedPanelVisibilityChanged(bool includesSettingsPanel)
{
if (!ReferenceEquals(activeInstance, this))
{
return;
}
if (!IsUiUiSceneActive())
{
SetSettingsVisibilityState(false);
SetOverlayPanelsVisibilityState(false);
return;
}
if (includesSettingsPanel)
{
SetSettingsVisibilityState(IsSettingsPanelVisible);
}
SetOverlayPanelsVisibilityState(AreOverlayPanelsVisible());
}
private void SyncManagedPanelVisibilityState(bool forceNotify)
{
if (!IsUiUiSceneActive())
{
SetSettingsVisibilityState(false, forceNotify);
SetOverlayPanelsVisibilityState(false, forceNotify);
return;
}
SetSettingsVisibilityState(IsSettingsPanelVisible, forceNotify);
SetOverlayPanelsVisibilityState(AreOverlayPanelsVisible(), forceNotify);
}
private void AttachManagedPanelVisibilityRelay(GameObject panel, bool includesSettingsPanel)
{
if (panel == null)
{
return;
}
btmandtopPanelVisibilityRelay relay = panel.GetComponent<btmandtopPanelVisibilityRelay>();
if (relay == null)
{
relay = panel.AddComponent<btmandtopPanelVisibilityRelay>();
}
relay.Initialize(this, includesSettingsPanel);
}
private void SetSettingsVisibilityState(bool visible, bool forceNotify = false)
{
lastSettingsVisibilityState = visible;
if (!forceNotify && CurrentSettingsVisible == visible)
{
return;
}
CurrentSettingsVisible = visible;
SettingsVisibilityChanged?.Invoke(visible);
GlobalSettingsVisibilityChanged?.Invoke(visible);
}
private void SetOverlayPanelsVisibilityState(bool visible, bool forceNotify = false)
{
lastOverlayPanelsVisibilityState = visible;
if (!forceNotify && CurrentOverlayPanelsVisible == visible)
{
return;
}
CurrentOverlayPanelsVisible = visible;
GlobalOverlayPanelVisibilityChanged?.Invoke(visible);
topNavigationGeometryDirty = true;
EnsureTopNavigationFront();
}
private void ToggleMusicPic()
{
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : SceneObjectLookupCache.FindAny<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 = SceneObjectLookupCache.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 : SceneObjectLookupCache.FindAny<BgmUiBinder>();
if (musicPicRoot == null)
{
if (binder != null)
binder.ToggleMusicPic();
return;
}
SetMusicPicVisible(!musicPicVisible, false);
}
private void HandleMusicButtonLockedClick()
{
gNotice.error.display(MusicLockedMessage);
}
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 cached = SceneObjectLookupCache.Find(name);
if (cached != null) return cached;
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;
}
KillCurrencyHoverTweens();
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(HandleMusicButtonLockedClick);
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 SetupCurrencyHoverIndicators()
{
InitializeCurrencyHoverCanvasGroup(mmrFragmentHoverCanvasGroup);
InitializeCurrencyHoverCanvasGroup(coinsHoverCanvasGroup);
AttachCurrencyHoverListener(mmrFragmentHoverButton, true);
AttachCurrencyHoverListener(coinsHoverButton, false);
}
private void InitializeCurrencyHoverCanvasGroup(CanvasGroup targetGroup)
{
if (targetGroup == null)
{
return;
}
targetGroup.DOKill();
targetGroup.alpha = 0f;
targetGroup.interactable = false;
targetGroup.blocksRaycasts = false;
}
private void AttachCurrencyHoverListener(Button targetButton, bool isFragmentButton)
{
if (targetButton == null)
{
return;
}
btmandtopCurrencyHoverRelay relay = targetButton.GetComponent<btmandtopCurrencyHoverRelay>();
if (relay == null)
{
relay = targetButton.gameObject.AddComponent<btmandtopCurrencyHoverRelay>();
}
relay.Initialize(this, isFragmentButton);
}
internal void SetCurrencyHoverVisible(bool isFragmentGroup, bool visible)
{
CanvasGroup targetGroup = isFragmentGroup ? mmrFragmentHoverCanvasGroup : coinsHoverCanvasGroup;
if (targetGroup == null)
{
return;
}
Tween currentTween = isFragmentGroup ? mmrFragmentHoverTween : coinsHoverTween;
if (currentTween != null && currentTween.IsActive())
{
currentTween.Kill();
}
float duration = Mathf.Max(0.01f, currencyHoverFadeDuration);
targetGroup.interactable = false;
targetGroup.blocksRaycasts = false;
Tween nextTween = targetGroup
.DOFade(visible ? 1f : 0f, duration)
.SetEase(Ease.Linear)
.SetUpdate(true)
.SetLink(targetGroup.gameObject)
.OnComplete(() =>
{
targetGroup.alpha = visible ? 1f : 0f;
targetGroup.interactable = false;
targetGroup.blocksRaycasts = false;
});
if (isFragmentGroup)
{
mmrFragmentHoverTween = nextTween;
}
else
{
coinsHoverTween = nextTween;
}
}
private void KillCurrencyHoverTweens()
{
if (mmrFragmentHoverTween != null && mmrFragmentHoverTween.IsActive())
{
mmrFragmentHoverTween.Kill();
}
if (coinsHoverTween != null && coinsHoverTween.IsActive())
{
coinsHoverTween.Kill();
}
if (mmrFragmentHoverCanvasGroup != null)
{
mmrFragmentHoverCanvasGroup.DOKill();
}
if (coinsHoverCanvasGroup != null)
{
coinsHoverCanvasGroup.DOKill();
}
}
private void HandleCoinsChanged(int coinAmount)
{
UpdatePlayerCoinsLegacyText(coinAmount);
}
private void HandleMaterialChanged(int materialAmount)
{
UpdatePlayerMmrFragmentText(materialAmount);
}
private void HandleRksChanged(float rksAmount)
{
UpdatePlayerRksText(rksAmount);
UpdateRksProgressImage(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 void UpdateRksProgressImage(float rksAmount)
{
if (rksProgressImage == null)
{
return;
}
rksProgressImage.fillAmount = Mathf.Clamp01(Mathf.InverseLerp(0f, 100f, rksAmount));
}
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 (!enableGuideDisplay)
{
if (guideDisplayImage != null && guideDisplayImage.gameObject.activeSelf)
{
CloseGuideDisplay();
}
return;
}
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 || GetSettingsParentTransform() == null) return;
// If we don't have an instance (it may have been destroyed), instantiate one
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, GetSettingsParentTransform());
AttachManagedPanelVisibilityRelay(settingsInstance, true);
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();
RegisterManagedPanel(settingsInstance, CloseSettingsWithExitAnim);
NotifyManagedPanelVisibilityChanged(true);
return;
}
AttachManagedPanelVisibilityRelay(settingsInstance, true);
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.transform.SetParent(GetSettingsParentTransform(), false);
EnsureSettingsLastSibling();
bool active = settingsInstance.activeSelf;
if (active)
{
CloseSettingsWithExitAnim();
return;
}
settingsInstance.SetActive(true);
if (settingsInstance.activeSelf)
{
EnsureSettingsLastSibling();
RegisterManagedPanel(settingsInstance, CloseSettingsWithExitAnim);
}
NotifyManagedPanelVisibilityChanged(true);
}
private void CloseSettingsWithExitAnim()
{
if (settingsInstance == null)
{
NotifyManagedPanelVisibilityChanged(true);
return;
}
UI_PanelExitUtility.PlayExitThen(settingsInstance, () =>
{
if (settingsInstance != null)
{
settingsInstance.SetActive(false);
}
NotifyManagedPanelVisibilityChanged(true);
});
}
public bool IsSettingsPanelVisible
{
get { return settingsInstance != null && settingsInstance.activeInHierarchy; }
}
private void ToggleUserInfoPrefab()
{
if (ToggleIfAlreadyOpen(ref userInfoInstance))
{
return;
}
if (OpenPrefab(userInfo_prefab, ref userInfoInstance))
{
CloseInfoPanels(userInfoInstance);
RegisterManagedPanel(userInfoInstance, () => CloseManagedOverlay(userInfoInstance));
}
}
private void BroadcastSettingsVisibility(bool visible)
{
SetSettingsVisibilityState(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)
|| (userInfoInstance != null && userInfoInstance.activeInHierarchy)
|| (storeInstance != null && storeInstance.activeInHierarchy)
|| (showLevelInstance != null && showLevelInstance.activeInHierarchy)
|| (emailInstance != null && emailInstance.activeInHierarchy)
|| (noticeInstance != null && noticeInstance.activeInHierarchy)
|| (userBagInstance != null && userBagInstance.activeInHierarchy);
}
private void BroadcastOverlayPanelsVisibility()
{
SetOverlayPanelsVisibilityState(AreOverlayPanelsVisible());
}
private void RegisterManagedPanel(GameObject panel, System.Action closeAction)
{
if (panel == null)
{
return;
}
UIBackStack.RegisterOrBump(
panel,
() => panel != null && panel.activeInHierarchy,
() =>
{
closeAction?.Invoke();
return true;
});
}
private void ShowLevelPrefab()
{
if (ToggleIfAlreadyOpen(ref showLevelInstance))
{
return;
}
if (OpenPrefab(showLevel_prefab, ref showLevelInstance))
{
CloseInfoPanels(showLevelInstance);
RegisterManagedPanel(showLevelInstance, () => CloseManagedOverlay(showLevelInstance));
}
}
private void ShowStorePrefab()
{
if (ToggleIfAlreadyOpen(ref storeInstance))
{
return;
}
if (OpenPrefab(store_prefab, ref storeInstance))
{
CloseInfoPanels(storeInstance);
RegisterManagedPanel(storeInstance, () => CloseManagedOverlay(storeInstance));
}
}
private void ShowEmailPrefab()
{
if (ToggleIfAlreadyOpen(ref emailInstance))
{
return;
}
if (OpenPrefab(email_prefab, ref emailInstance))
{
CloseInfoPanels(emailInstance);
RegisterManagedPanel(emailInstance, () => CloseManagedOverlay(emailInstance));
}
}
private void ShowNoticePrefab()
{
if (ToggleIfAlreadyOpen(ref noticeInstance))
{
return;
}
if (OpenPrefab(notice_prefab, ref noticeInstance))
{
CloseInfoPanels(noticeInstance);
RegisterManagedPanel(noticeInstance, () => CloseManagedOverlay(noticeInstance));
}
}
private void ShowUserBagPrefab()
{
if (ToggleIfAlreadyOpen(ref userBagInstance))
{
return;
}
if (OpenPrefab(userBag_prefab, ref userBagInstance))
{
CloseInfoPanels(userBagInstance);
RegisterManagedPanel(userBagInstance, () => CloseManagedOverlay(userBagInstance));
}
}
private void CloseManagedOverlay(GameObject instance)
{
if (instance == null)
{
return;
}
CloseManagedOverlayWithExitAnim(instance);
}
private bool ToggleIfAlreadyOpen(ref GameObject instance)
{
if (instance == null)
{
return false;
}
if (!instance.activeInHierarchy)
{
return false;
}
CloseManagedOverlayWithExitAnim(instance);
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);
}
else
{
instance.transform.SetParent(putPrefabsHere.transform, false);
}
}
if (instance == null)
{
return false;
}
if (!instance.activeSelf)
{
instance.SetActive(true);
}
AttachManagedPanelVisibilityRelay(instance, false);
EnsurePanelPopupTween(instance);
TryAssignCanvasCamera(instance);
BroadcastOverlayPanelsVisibility();
EnsureTopNavigationFront();
return true;
}
private UI_PanelPopupTween EnsurePanelPopupTween(GameObject instance)
{
if (instance == null)
{
return null;
}
if (instance.GetComponent<UI_SettingsPanelEnterAnim>() != null)
{
return null;
}
UI_PanelPopupTween popupTween = instance.GetComponent<UI_PanelPopupTween>();
if (popupTween == null)
{
popupTween = instance.AddComponent<UI_PanelPopupTween>();
}
return popupTween;
}
private void EnsureSettingsLastSibling()
{
if (settingsInstance == null || GetSettingsParentTransform() == null)
{
return;
}
settingsInstance.transform.SetParent(GetSettingsParentTransform(), false);
settingsInstance.transform.SetAsLastSibling();
}
private Transform GetSettingsParentTransform()
{
if (putSettingsPrefabHere != null)
{
return putSettingsPrefabHere.transform;
}
if (putPrefabsHere == null)
{
return null;
}
Transform siblingParent = putPrefabsHere.transform.parent;
return siblingParent != null ? siblingParent : putPrefabsHere.transform;
}
private void CloseInfoPanels(GameObject keep)
{
CloseInstance(ref userInfoInstance, 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;
CloseManagedOverlayWithExitAnim(instance);
}
private void CloseManagedOverlayWithExitAnim(GameObject instance)
{
if (instance == null)
{
return;
}
UI_PanelExitUtility.PlayExitThen(instance, () =>
{
if (instance != null)
{
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 = SceneObjectLookupCache.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.SyncManagedPanelVisibilityState(false);
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);
}
EnsureTopNavigationFront();
}
private void ResolveNewBackButtons()
{
Transform topRoot = FindChildRecursive(transform, "TOP");
if (topRoot != null)
{
topNavigationRoot = topRoot as RectTransform;
}
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 void EnsureTopNavigationFront()
{
ResolveTopNavigationRoot();
if (topNavigationRoot == null)
{
return;
}
Transform parent = topNavigationRoot.parent;
if (parent == null)
{
return;
}
if (topNavigationRoot.GetSiblingIndex() != parent.childCount - 1)
{
topNavigationRoot.SetAsLastSibling();
topNavigationGeometryDirty = true;
}
// The parent's child count changing means a panel was shown/hidden, which can
// shift the top-bar layout. Use it as a cheap heuristic to re-settle geometry.
if (parent.childCount != lastTopNavigationParentChildCount)
{
lastTopNavigationParentChildCount = parent.childCount;
topNavigationGeometryDirty = true;
}
if (topNavigationGeometryDirty)
{
topNavigationGeometryDirty = false;
RefreshTopNavigationGeometry();
}
}
public void MarkTopNavigationGeometryDirty()
{
topNavigationGeometryDirty = true;
}
private void ResolveTopNavigationRoot()
{
if (topNavigationRoot != null)
{
return;
}
Transform topRoot = FindChildRecursive(transform, "TOP");
if (topRoot == null)
{
GameObject sceneTop = FindByName("TOP");
if (sceneTop != null)
{
topRoot = sceneTop.transform;
}
}
if (topRoot != null)
{
topNavigationRoot = topRoot as RectTransform;
}
}
private void RefreshTopNavigationGeometry()
{
if (topNavigationRoot == null)
{
return;
}
Canvas.ForceUpdateCanvases();
LayoutRebuilder.ForceRebuildLayoutImmediate(topNavigationRoot);
RectTransform navRoot = null;
if (back_navButton != null)
{
navRoot = back_navButton.transform.parent as RectTransform;
}
if (navRoot == null)
{
Transform candidate = FindChildRecursive(topNavigationRoot, "New back");
navRoot = candidate as RectTransform;
}
if (navRoot != null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(navRoot);
}
if (back_navButton != null)
{
RectTransform backRect = back_navButton.transform as RectTransform;
if (backRect != null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(backRect);
}
}
Canvas.ForceUpdateCanvases();
}
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;
if (activeInstance != null)
{
activeInstance.topNavigationGeometryDirty = true;
activeInstance.EnsureTopNavigationFront();
activeInstance.SyncManagedPanelVisibilityState(true);
activeInstance.ScheduleDeferredUiRefresh();
}
}
private void ScheduleDeferredUiRefresh()
{
if (!isActiveAndEnabled)
{
return;
}
if (deferredUiRefreshRoutine != null)
{
StopCoroutine(deferredUiRefreshRoutine);
}
deferredUiRefreshRoutine = StartCoroutine(DeferredUiRefreshRoutine());
}
private System.Collections.IEnumerator DeferredUiRefreshRoutine()
{
for (int i = 0; i < 3; i++)
{
yield return null;
topNavigationGeometryDirty = true;
EnsureTopNavigationFront();
}
deferredUiRefreshRoutine = null;
}
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();
if (UIBackStack.TryHandleTop())
{
return;
}
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;
if (gTransition.LoadScene(sceneName, LoadSceneMode.Single))
{
while (gTransition.IsBusy)
{
yield return null;
}
navSceneLoading = false;
yield break;
}
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
while (op != null && !op.isDone)
{
yield return null;
}
navSceneLoading = false;
}
public void UpdateSteamUserInfo()
{
#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
// 非 Steam 平台(如 Android):无 Steamworks,显示未知来源即可。
if (steamStatusText != null)
steamStatusText.text = LocalizationService.Get("steam.status.unknown", "Unknown Server");
return;
#else
if (!SteamManager.Initialized)
{
Debug.LogWarning("[Steam] SteamManager not initialized.");
if (steamStatusText != null)
steamStatusText.text = LocalizationService.Get("steam.status.unknown", "Unknown Server");
return;
}
try
{
CSteamID steamID = SteamUser.GetSteamID();
if (steamUserNameText != null)
steamUserNameText.text = SteamFriends.GetPersonaName();
if (steamUserID64Text != null)
steamUserID64Text.text = LocalizationService.GetFormat("steam.uid_format", steamID.m_SteamID.ToString());
// Online status check
EPersonaState state = SteamFriends.GetPersonaState();
bool isOffline = (state == EPersonaState.k_EPersonaStateOffline);
if (steamStatusText != null)
{
steamStatusText.text = isOffline
? LocalizationService.Get("steam.status.offline", "Steam Offline")
: LocalizationService.Get("steam.status.online", "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 = LocalizationService.Get("steam.status.unknown", "Unknown Server");
}
#endif
}
}
internal sealed class btmandtopPanelVisibilityRelay : MonoBehaviour
{
private btmandtopController owner;
private bool includesSettingsPanel;
public void Initialize(btmandtopController controller, bool isSettingsPanel)
{
owner = controller;
includesSettingsPanel = isSettingsPanel;
}
private void OnEnable()
{
if (owner != null)
{
owner.NotifyManagedPanelVisibilityChanged(includesSettingsPanel);
}
}
private void OnDisable()
{
if (owner != null)
{
owner.NotifyManagedPanelVisibilityChanged(includesSettingsPanel);
}
}
}
internal sealed class btmandtopCurrencyHoverRelay : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
private btmandtopController owner;
private bool isFragmentGroup;
public void Initialize(btmandtopController controller, bool fragmentGroup)
{
owner = controller;
isFragmentGroup = fragmentGroup;
}
public void OnPointerEnter(PointerEventData eventData)
{
if (owner != null)
{
owner.SetCurrencyHoverVisible(isFragmentGroup, true);
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (owner != null)
{
owner.SetCurrencyHoverVisible(isFragmentGroup, false);
}
}
public void OnPointerClick(PointerEventData eventData)
{
if (owner != null)
{
owner.SetCurrencyHoverVisible(isFragmentGroup, true);
}
}
}