Decompiled source of RoguelikeSkillTreeVisualizer v0.3.5
plugins/RoguelikeSkillTreeVisualizer/RoguelikeSkillTreeVisualizer.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Burst2Flame; using Burst2Flame.Observable; using Gumatos.RealmApi; using Gumatos.RealmApi.UI; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("RoguelikeSkillTreeVisualizer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Adds a 'Skills' button (run HUD bottom bar, Remove Skill Trees modal and the level-up window) that opens the game's native skill tree read-only for the character in view, plus the shortcut F10. No skill point is spent; no gameplay change.")] [assembly: AssemblyFileVersion("0.3.5.0")] [assembly: AssemblyInformationalVersion("0.3.5")] [assembly: AssemblyProduct("RoguelikeSkillTreeVisualizer")] [assembly: AssemblyTitle("RoguelikeSkillTreeVisualizer")] [assembly: AssemblyVersion("0.3.5.0")] namespace RoguelikeSkillTreeVisualizer; internal static class LevelUpWindowButton { internal const string ButtonName = "RstvLevelUpSkillsButton"; internal const string Label = "Skills"; internal const string LabelChildName = "RstvLevelUpLabel"; internal const float Lado = 44f; private const float Margem = 8f; private static GameObject _janela; private static GameObject _button; private static string _reasonLogged; internal static void Ensure(RoguelikeManager rok) { try { EnsureInternal(rok); Refresh(); } catch (Exception ex) { Fail("excecao durante a injecao (" + ex.GetType().Name + "): " + ex.Message, aviso: true); Plugin.Log.LogError((object)("RSTV: falha ao injetar o botao da janela do level-up: " + ex)); } } private static void EnsureInternal(RoguelikeManager rok) { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown if ((Object)(object)rok == (Object)null) { Fail("a instancia do RoguelikeManager chegou nula", aviso: false); return; } if (!Plugin.RunBotaoLigado) { Fail(Plugin.MotivoDoBotaoDaRunDesligado, aviso: false); return; } GameObject skillSelectWindow = rok.SkillSelectWindow; if ((Object)(object)skillSelectWindow == (Object)null) { Fail("RoguelikeManager.SkillSelectWindow esta nulo (o campo do prefab nao carregou)", aviso: true); } else if (!skillSelectWindow.activeSelf) { Fail("a janela do level-up (" + ((Object)skillSelectWindow).name + ") NAO esta ativa — nao injetar fora de hora", aviso: false); } else { if ((Object)(object)_janela == (Object)(object)skillSelectWindow && (Object)(object)_button != (Object)null) { return; } if ((Object)(object)_button != (Object)null && (Object)(object)_janela != (Object)(object)skillSelectWindow) { Object.Destroy((Object)(object)_button); _button = null; } Button acceptButton = rok.AcceptButton; if ((Object)(object)acceptButton == (Object)null) { Fail("RoguelikeManager.AcceptButton esta nulo — sem molde nao ha clone", aviso: true); return; } if ((Object)(object)((Component)acceptButton).transform == (Object)null) { Fail("o 'Accept Btn' molde esta sem Transform", aviso: true); return; } RectTransform component = skillSelectWindow.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { Fail("o SkillSelectWindow esta sem RectTransform (nao da para ancorar o botao)", aviso: true); return; } Transform parent = ((Component)acceptButton).transform.parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { Fail("o pai do 'Accept Btn' (o painel Content) nao e RectTransform — sem ele nao sei onde fica o canto do painel", aviso: true); return; } Transform val2 = skillSelectWindow.transform.Find("RstvLevelUpSkillsButton"); GameObject val3; if ((Object)(object)val2 != (Object)null) { val3 = ((Component)val2).gameObject; } else { val3 = Object.Instantiate<GameObject>(((Component)acceptButton).gameObject, skillSelectWindow.transform); ((Object)val3).name = "RstvLevelUpSkillsButton"; } RectTransform component2 = val3.GetComponent<RectTransform>(); if ((Object)(object)component2 == (Object)null) { Fail("o clone do 'Accept Btn' ficou sem RectTransform", aviso: true); return; } NativeUiHelpers.DisableLocalizers(val3); EnsureLabel(val3); AnchorToContentCorner(component2, component, val); Button component3 = val3.GetComponent<Button>(); if ((Object)(object)component3 == (Object)null) { Fail("o clone do 'Accept Btn' ficou sem componente Button", aviso: true); return; } NativeUiHelpers.ClearClickListeners(component3); ((UnityEvent)component3.onClick).AddListener(new UnityAction(RunButton.OpenForTarget)); ((Selectable)component3).interactable = true; _janela = skillSelectWindow; _button = val3; _reasonLogged = null; Plugin.Log.LogInfo((object)("RSTV-11b: botao 'Skills' injetado DENTRO da janela do level-up (" + ((Object)skillSelectWindow).name + "), filho direto (fora do Content, sem reflow); " + 44f.ToString("0.#") + "x" + 44f.ToString("0.#") + " px no canto superior direito do painel Content; onClick limpo -> RunButton.OpenForTarget().")); } } internal static void Refresh() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 try { GameObject button = _button; GameObject janela = _janela; if ((Object)(object)button == (Object)null || (Object)(object)janela == (Object)null) { return; } RoguelikeManager instance = RoguelikeManager.Instance; bool flag = (Object)(object)instance != (Object)null && (Object)(object)instance.SkillSelectWindow == (Object)(object)janela && janela.activeSelf && (int)instance.CurLevelUpStage == 0; if (button.activeSelf == flag) { return; } button.SetActive(flag); if (flag) { RectTransform component = button.GetComponent<RectTransform>(); RectTransform component2 = janela.GetComponent<RectTransform>(); Button val = (((Object)(object)instance != (Object)null) ? instance.AcceptButton : null); RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && (Object)(object)val2 != (Object)null) { AnchorToContentCorner(component, component2, val2); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV: falha ao sincronizar o botao da janela do level-up (" + ex.GetType().Name + "): " + ex.Message)); } } private static void EnsureLabel(GameObject clone) { TextMeshProUGUI componentInChildren = clone.GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren == (Object)null) { Fail("o clone do 'Accept Btn' ficou SEM TextMeshProUGUI — botao sem rotulo", aviso: true); } else { ((TMP_Text)componentInChildren).text = OptionsManager.Localize("Skills", (LanguageGender)0, (Gender)2); } } internal static void AnchorToContentCorner(RectTransform rt, RectTransform janela, RectTransform content) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Canvas.ForceUpdateCanvases(); Vector3[] array = (Vector3[])(object)new Vector3[4]; content.GetWorldCorners(array); Vector3 val = ((Transform)janela).InverseTransformPoint(array[2]); Rect rect = janela.rect; float num = (0f - ((Rect)(ref rect)).width) * janela.pivot.x; rect = janela.rect; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(num, (0f - ((Rect)(ref rect)).height) * janela.pivot.y); rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.zero; rt.pivot = new Vector2(1f, 1f); ((Transform)rt).localScale = Vector3.one; ((Transform)rt).localRotation = Quaternion.identity; rt.sizeDelta = new Vector2(44f, 44f); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(val.x - 8f, val.y - 8f); rt.anchoredPosition = val3 - val2; ((Transform)rt).SetAsLastSibling(); } private static void Fail(string motivo, bool aviso) { if (!(_reasonLogged == motivo)) { _reasonLogged = motivo; string text = "RSTV DIAG: botao 'Skills' da janela do level-up NAO injetado — " + motivo + "."; if (aviso) { Plugin.Log.LogWarning((object)text); } else { Plugin.Log.LogInfo((object)text); } } } } internal static class NativeUiHelpers { internal static string DescribeGroup(Transform parent) { if ((Object)(object)parent == (Object)null) { return "nenhum"; } LayoutGroup component = ((Component)parent).GetComponent<LayoutGroup>(); if (!((Object)(object)component == (Object)null)) { return ((object)component).GetType().Name; } return "nenhum"; } internal static void DisableLocalizers(GameObject root) { Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; if (name.IndexOf("Localiz", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Localize", StringComparison.OrdinalIgnoreCase) >= 0) { Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null); if ((Object)(object)val2 != (Object)null) { val2.enabled = false; Plugin.Log.LogInfo((object)("RSTV: localizador '" + name + "' desativado no botao clonado.")); } } } } internal static void ClearClickListeners(Button button) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown if (!((Object)(object)button == (Object)null)) { button.onClick = new ButtonClickedEvent(); } } } internal static class PartyTargets { private static readonly List<Character> AdditionOrder = new List<Character>(); internal static bool IsLocal(Character character) { try { return character != null && character.Owned; } catch (Exception) { return false; } } internal static void NoteAddition(Character character) { if (IsLocal(character)) { AdditionOrder.RemoveAll((Character c) => c == null || c == character || !IsLocal(c)); AdditionOrder.Add(character); } } internal static void NoteRemoval(Character character) { if (character != null) { AdditionOrder.Remove(character); } } internal static int LocalPartyCount() { try { return NetworkingManager.Instance.MyPartyCharactersUnaccepted?.Count ?? 0; } catch (Exception) { return 0; } } internal static Character Resolve() { try { List<Character> myPartyCharactersUnaccepted = NetworkingManager.Instance.MyPartyCharactersUnaccepted; if (myPartyCharactersUnaccepted == null || myPartyCharactersUnaccepted.Count == 0) { return null; } for (int num = AdditionOrder.Count - 1; num >= 0; num--) { Character val = AdditionOrder[num]; if (val != null && myPartyCharactersUnaccepted.Contains(val)) { return val; } } return myPartyCharactersUnaccepted[myPartyCharactersUnaccepted.Count - 1]; } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao resolver o personagem da party: " + ex.Message)); return null; } } } [HarmonyPatch(typeof(CharacterChoiceManager), "ToggleSelectedCharacter", new Type[] { typeof(int) })] internal static class CharacterChoiceTogglePatch { private static Character _subject; private static bool _firstCallLogged; [HarmonyPrefix] private static void Prefix(CharacterChoiceManager __instance) { try { _subject = (((Object)(object)__instance != (Object)null && (Object)(object)__instance.selectedCharacterChoiceItem != (Object)null) ? __instance.selectedCharacterChoiceItem.Character : null); } catch (Exception) { _subject = null; } } [HarmonyPostfix] private static void Postfix(CharacterChoiceManager __instance, int controllerPlayerId) { try { if (!_firstCallLogged) { _firstCallLogged = true; Plugin.Log.LogInfo((object)("RSTV-2: gancho de adicao/remocao da party ATIVO (ToggleSelectedCharacter, controllerPlayerId=" + controllerPlayerId + ").")); } Character subject = _subject; _subject = null; if (subject != null && PartyTargets.IsLocal(subject)) { if (subject.SelectedForBattle) { PartyTargets.NoteAddition(subject); Plugin.Log.LogInfo((object)("RSTV-2: '" + subject.CharacterName + "' entrou na MINHA party — novo alvo do botao.")); } else { PartyTargets.NoteRemoval(subject); Character val = PartyTargets.Resolve(); Plugin.Log.LogInfo((object)("RSTV-2: '" + subject.CharacterName + "' saiu da minha party — alvo agora: " + ((val != null) ? val.CharacterName : "(nenhum)"))); } } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de ToggleSelectedCharacter: " + ex)); } } } [HarmonyPatch(typeof(SkillTreeManager), "AcceptSkillChanges", new Type[] { typeof(bool) })] internal static class SkillTreeManagerAcceptSkillChangesPatch { [HarmonyPrefix] private static bool Prefix(SkillTreeManager __instance, bool closeMenu) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 try { if (!ReadOnlySession.Active || (Object)(object)__instance == (Object)null) { return true; } if ((Object)(object)GUIManager.instance != (Object)null && (int)GUIManager.instance.CurrentGuiState == 1) { return true; } Character target = ReadOnlySession.Target; __instance.SkillsToAdd.Clear(); __instance.SkillsRemoved.Clear(); __instance.SkillsOnEnter.Clear(); HashSet<SkillInfo> hashSet = new HashSet<SkillInfo>(); if (target != null) { hashSet.UnionWith(target.SkillsFromPoints); } Character val = (((Object)(object)GameLogic.instance != (Object)null) ? GameLogic.instance.CurrentlySelectedCharacter : null); if (val != null && val != target) { hashSet.UnionWith(val.SkillsFromPoints); } __instance.SkillsOnEnter.AddRange(hashSet); Plugin.Log.LogInfo((object)("RSTV-2: commit higienizado (read-only, closeMenu=" + closeMenu + ") — nenhuma escrita no personagem (" + hashSet.Count + " skills no snapshot).")); return true; } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao higienizar AcceptSkillChanges — o original NAO vai rodar (zero escrita); fechando a janela para nao prender a UI: " + ex)); try { ReadOnlySession.Close(); } catch (Exception ex2) { Plugin.Log.LogError((object)("RSTV: e o fechamento de emergencia tambem falhou: " + ex2.Message)); } return false; } } } [HarmonyPatch(typeof(SkillTreeManager), "Initialize", new Type[] { typeof(List<SkillInfo>), typeof(int), typeof(bool) })] internal static class SkillTreeManagerInitializePatch { [HarmonyPostfix] private static void Postfix(SkillTreeManager __instance, bool creating) { try { if (!ReadOnlySession.Active || (Object)(object)__instance == (Object)null || creating) { return; } Character target = ReadOnlySession.Target; if (target != null) { bool num = __instance.startingUnspentPoints != 0 || __instance.SkillsToAdd.Count > 0 || __instance.SkillsRemoved.Count > 0 || __instance.SkillsOnEnter.Count != target.SkillsFromPoints.Count; __instance.SkillsToAdd.Clear(); __instance.SkillsRemoved.Clear(); __instance.SkillsOnEnter.Clear(); __instance.SkillsOnEnter.AddRange(target.SkillsFromPoints); __instance.startingUnspentPoints = 0; __instance.RefreshRespecFooter(); if (num) { __instance.UpdateCurrentTree(); Plugin.Log.LogInfo((object)"RSTV-2: estado interno reafirmado (read-only) depois de um Initialize do jogo."); } } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao reafirmar o modo somente leitura — fechando a arvore para nao deixar uma janela interativa em estado desconhecido: " + ex)); try { ReadOnlySession.Close(); } catch (Exception ex2) { Plugin.Log.LogError((object)("RSTV: e o fechamento de emergencia tambem falhou: " + ex2.Message)); } } } } [HarmonyPatch(typeof(SkillTreeManager), "RefreshRespecFooter", new Type[] { })] internal static class SkillTreeManagerRespecFooterPatch { [HarmonyPostfix] private static void Postfix(SkillTreeManager __instance) { try { if (ReadOnlySession.Active && (Object)(object)__instance != (Object)null && (Object)(object)__instance.RespecButton != (Object)null && __instance.RespecButton.activeSelf) { __instance.RespecButton.SetActive(false); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao esconder o RespecButton: " + ex)); } } } [HarmonyPatch(typeof(SkillTreeItem), "ToggleAddToSkillToAddList", new Type[] { })] internal static class SkillTreeItemTogglePatch { private static bool _firstBlockLogged; [HarmonyPrefix] private static bool Prefix(SkillTreeItem __instance) { bool flag; try { flag = ReadOnlySession.Active || SkillTreesTab.Aberto; } catch (Exception) { return true; } if (!flag) { return true; } try { if (!_firstBlockLogged) { _firstBlockLogged = true; string text = (((Object)(object)__instance != (Object)null && (Object)(object)__instance.SkillInfo != (Object)null) ? __instance.SkillInfo.SkillName : "?"); Plugin.Log.LogInfo((object)("RSTV-2: clique na arvore BLOQUEADO (read-only) — primeira skill clicada: " + text + ".")); } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("RSTV: nao deu para logar o bloqueio do clique (o clique continua bloqueado): " + ex2.Message)); } return false; } } [HarmonyPatch(typeof(SkillTreeManager), "ResetSkillPoints", new Type[] { })] internal static class SkillTreeManagerResetSkillPointsPatch { private static bool _firstBlockLogged; [HarmonyPrefix] private static bool Prefix() { try { if (!ReadOnlySession.Active) { return true; } if (!_firstBlockLogged) { _firstBlockLogged = true; Plugin.Log.LogInfo((object)"RSTV-2: ResetSkillPoints BLOQUEADO (read-only) — nada foi zerado no personagem."); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao avaliar o bloqueio de ResetSkillPoints — mantendo o reset BLOQUEADO por seguranca: " + ex)); return false; } return false; } } [HarmonyPatch(typeof(CharacterMenusManager), "OpenWindow", new Type[] { })] internal static class CharacterMenusManagerOpenWindowPatch { private static bool _firstCallLogged; [HarmonyPostfix] private static void Postfix(CharacterMenusManager __instance) { try { if (!_firstCallLogged) { _firstCallLogged = true; Plugin.Log.LogInfo((object)"RSTV-16: gancho da aba do inventario ATIVO (CharacterMenusManager.OpenWindow)."); } RstvHost.Ensure(); SkillTreesTab.Ensure(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-16: falha no postfix de CharacterMenusManager.OpenWindow: " + ex)); } } } [HarmonyPatch(typeof(SkillTreeManager), "OnDisable", new Type[] { })] internal static class SkillTreeManagerOnDisablePatch { [HarmonyPostfix] private static void Postfix(SkillTreeManager __instance) { try { if (ReadOnlySession.Active) { ReadOnlySession.End(); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de OnDisable: " + ex)); } } } [HarmonyPatch(typeof(CharacterMenusManager), "CloseSkillTreeMenu", new Type[] { })] internal static class CharacterMenusManagerCloseSkillTreePatch { [HarmonyPostfix] private static void Postfix() { try { if (ReadOnlySession.Active) { ReadOnlySession.End(); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de CharacterMenusManager.CloseSkillTreeMenu: " + ex)); } } } [HarmonyPatch(typeof(CurrentCharacterUI), "InitSingleton", new Type[] { })] internal static class CurrentCharacterUIInitPatch { private static bool _firstCallLogged; [HarmonyPostfix] private static void Postfix(CurrentCharacterUI __instance) { try { if (!_firstCallLogged) { _firstCallLogged = true; Plugin.Log.LogInfo((object)"RSTV-5: gancho do HUD da run ATIVO (CurrentCharacterUI.InitSingleton)."); } RstvHost.Ensure(); RunButton.Ensure(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de CurrentCharacterUI.InitSingleton: " + ex)); } } } [HarmonyPatch(typeof(PlayerMovement), "ProcessLeftMouseClick", new Type[] { typeof(HexCell) })] internal static class PlayerMovementProcessLeftMouseClickPatch { private static bool _firstBlockLogged; [HarmonyPrefix] private static bool Prefix() { try { if (!ReadOnlySession.Active) { return true; } if (!_firstBlockLogged) { _firstBlockLogged = true; Plugin.Log.LogInfo((object)"RSTV-5: clique no hex CONSUMIDO enquanto a arvore read-only esta aberta (o branch de Action NAO checa PointerOverUIObject)."); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao avaliar o bloqueio do clique do hex — deixando o jogo tratar o clique: " + ex)); return true; } return false; } } [HarmonyPatch(typeof(KeybindManager), "Update", new Type[] { })] internal static class KeybindManagerUpdatePatch { [HarmonyPostfix] private static void Postfix(KeybindManager __instance) { try { SkillTreeShortcut.Handle(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no gancho do atalho (KeybindManager.Update): " + ex)); } } } [HarmonyPatch(typeof(RoguelikeManager), "OpenSkillSelectWindow", new Type[] { typeof(CharacterLevelUpInfo), typeof(bool) })] internal static class RoguelikeManagerOpenSkillSelectWindowPatch { private static bool _firstCallLogged; [HarmonyPostfix] private static void Postfix(RoguelikeManager __instance) { try { if (!_firstCallLogged) { _firstCallLogged = true; Plugin.Log.LogInfo((object)"RSTV-11b: gancho da janela do level-up ATIVO (RoguelikeManager.OpenSkillSelectWindow)."); } LevelUpWindowButton.Ensure(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de OpenSkillSelectWindow: " + ex)); } } } [HarmonyPatch(typeof(RoguelikeSkillTreeRemovalWindow), "Open", new Type[] { typeof(Character) })] internal static class RoguelikeSkillTreeRemovalWindowOpenPatch { private static bool _firstCallLogged; [HarmonyPostfix] private static void Postfix(RoguelikeSkillTreeRemovalWindow __instance) { try { if (!_firstCallLogged) { _firstCallLogged = true; Plugin.Log.LogInfo((object)"RSTV-20: gancho do modal 'Remove Skill Trees' ATIVO (RoguelikeSkillTreeRemovalWindow.Open)."); } RstvHost.Ensure(); RemovalWindowSkillsButton.Ensure(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha no postfix de RoguelikeSkillTreeRemovalWindow.Open: " + ex)); } } } [HarmonyPatch(typeof(Tooltip), "get_TooltipCharacter")] internal static class TooltipCharacterRodapePatch { private static Character _alvoDoModal; private static bool _primeiroPreenchimentoLogado; internal static void ComAlvo(Character alvo) { _alvoDoModal = alvo; } internal static void SemAlvo() { _alvoDoModal = null; } [HarmonyPostfix] private static void Postfix(ref Character __result) { try { if (__result != null) { return; } Character alvoDoModal = _alvoDoModal; if (alvoDoModal != null) { __result = alvoDoModal; if (!_primeiroPreenchimentoLogado) { _primeiroPreenchimentoLogado = true; Plugin.Log.LogInfo((object)("RSTV-27: rodape da tooltip resolvido pelo personagem do MODAL (TooltipCharacter era null) — alvo=" + (alvoDoModal.CharacterName ?? "?") + ".")); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-27: falha no postfix de Tooltip.TooltipCharacter: " + ex.Message)); } } } [BepInPlugin("com.gumatos.roguelikeskilltreevisualizer", "Roguelike Skill Tree Visualizer", "0.3.5")] [BepInDependency("com.gumatos.realmapi", "0.1.1")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.gumatos.roguelikeskilltreevisualizer"; public const string Version = "0.3.5"; public const string ApiGuid = "com.gumatos.realmapi"; public const string ApiVersionMinima = "0.1.1"; internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<bool> AtivarBotao { get; private set; } internal static ConfigEntry<bool> AtivarBotaoNaRun { get; private set; } internal static ConfigEntry<bool> AtalhoSkillTree { get; private set; } internal static ConfigEntry<KeyCode> TeclaAtalhoSkillTree { get; private set; } internal static ConfigEntry<bool> AtivarBotaoNaRemocao { get; private set; } internal static bool BotaoLigado { get { if (AtivarBotao != null) { return AtivarBotao.Value; } return true; } } internal static bool RunBotaoLigado { get { if (BotaoLigado) { if (AtivarBotaoNaRun != null) { return AtivarBotaoNaRun.Value; } return true; } return false; } } internal static bool AtalhoLigado { get { if (AtalhoSkillTree != null) { return AtalhoSkillTree.Value; } return true; } } internal static bool RemocaoBotaoLigado { get { if (BotaoLigado) { if (AtivarBotaoNaRemocao != null) { return AtivarBotaoNaRemocao.Value; } return true; } return false; } } internal static string MotivoDoBotaoDaRunDesligado { get { if (!BotaoLigado) { return "AtivarBotao=false no arquivo de config (chave-mestra: desliga o botao da run, o da janela de level-up e o do modal)"; } return "AtivarBotaoNaRun=false no arquivo de config"; } } internal static string MotivoDoBotaoDoModalDesligado { get { if (!BotaoLigado) { return "AtivarBotao=false no arquivo de config (chave-mestra: desliga o botao da run, o da janela de level-up e o do modal)"; } return "AtivarBotaoNaRemocao=false no arquivo de config"; } } internal static KeyCode TeclaAtalho { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (TeclaAtalhoSkillTree == null) { return (KeyCode)291; } return TeclaAtalhoSkillTree.Value; } } private void Awake() { //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; try { AtivarBotao = ((BaseUnityPlugin)this).Config.Bind<bool>("Geral", "AtivarBotao", true, "CHAVE-MESTRA dos botoes 'Skills' que restam (RSTV-29): o do HUD da run, o da janela de LEVEL-UP e o do modal 'Remove Skill Trees'. Padrao: true. Com false o mod carrega e registra os ganchos, mas NAO cria botao nenhum em lugar nenhum — desliga o HUD da run, o botao da janela de level-up E o modal de uma vez (para desligar so' uma superficie use a chave especifica dela). A tela Select Party nao tem mais botao (a superficie foi removida)."); AtivarBotaoNaRun = ((BaseUnityPlugin)this).Config.Bind<bool>("Geral", "AtivarBotaoNaRun", true, "Injeta o botao 'Skills' no HUD DURANTE A RUN, na BARRA DE BAIXO — na mesma linha dos botoes nativos de inventario e de skills, no vao livre medido antes do controle que rotaciona a barra de skills (RSTV-30). Padrao: true. Com false (ou com a chave-mestra AtivarBotao=false) o mod nao cria esse botao. ATENCAO: o portao da run (RunTargets.GateOk) vale mesmo com true — em mira de hex ou de skill, com uma janela de UI aberta ou no posicionamento inicial da batalha o botao fica SEM CLIQUE (continua visivel, na barra) e o log diz por que."); AtalhoSkillTree = ((BaseUnityPlugin)this).Config.Bind<bool>("Geral", "AtalhoSkillTree", true, "Liga o atalho de TECLADO que abre a mesma skill tree read-only (sem depender do botao do HUD). Padrao: true. A tecla nao dispara durante chat, remap de tecla, janela de evento ou menu sem alvo: os guards do KeybindManager.Update sao replicados no mod."); TeclaAtalhoSkillTree = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Geral", "TeclaAtalhoSkillTree", (KeyCode)291, "A tecla do atalho da skill tree. Padrao: F10. Aceita qualquer KeyCode do Unity (F9, K, Mouse4, ...). Nao usa a acao 10 nativa, entao NAO abre a janela vanilla de skill tree junto."); AtivarBotaoNaRemocao = ((BaseUnityPlugin)this).Config.Bind<bool>("Geral", "AtivarBotaoNaRemocao", true, "Injeta o botao 'Skills' no CABECALHO do modal 'Remove Skill Trees' (canto superior direito do titulo), que abre a arvore read-only do personagem do proprio modal. Padrao: true. Com false (ou com a chave-mestra AtivarBotao=false) o mod nao cria esse botao."); } catch (Exception ex) { Log.LogError((object)("RSTV: falha ao ler/criar o arquivo de config — seguindo com o padrao (botoes LIGADOS): " + ex.Message)); } Log.LogInfo((object)"Roguelike Skill Tree Visualizer 0.3.5 carregado (RSTV-29: botoes 'Skills' no HUD da run e no modal 'Remove Skill Trees', mais o atalho de teclado; a arvore nativa abre em skill tree read-only)."); AplicarPatches(); Log.LogInfo((object)("RSTV DIAG: chave-mestra AtivarBotao=" + BotaoLigado + " — botao 'Skills' do HUD da run " + (RunBotaoLigado ? "HABILITADO" : "DESABILITADO") + " (AtivarBotaoNaRun=" + (AtivarBotaoNaRun == null || AtivarBotaoNaRun.Value) + "; RSTV-30: na BARRA DE BAIXO, visivel com o HUD — o portao da run decide so' o CLIQUE); botao 'Skills' do modal 'Remove Skill Trees' " + (RemocaoBotaoLigado ? "HABILITADO" : "DESABILITADO") + " (AtivarBotaoNaRemocao=" + (AtivarBotaoNaRemocao == null || AtivarBotaoNaRemocao.Value) + "); atalho " + (AtalhoLigado ? ("LIGADO na tecla " + ((object)TeclaAtalho/*cast due to .constrained prefix*/).ToString()) : "DESABILITADO") + " (RSTV-11a: guards do KeybindManager replicados; sem acao nativa).")); } private static void AplicarPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("com.gumatos.roguelikeskilltreevisualizer"); List<string> list = new List<string>(); int num = 0; int num2 = 0; int num3 = 0; Type[] types; try { types = typeof(Plugin).Assembly.GetTypes(); } catch (Exception ex) { Log.LogError((object)("RSTV: nao deu para listar os tipos do mod — nenhum gancho aplicado: " + ex)); return; } foreach (Type type in types) { if (EhClasseDeGancho(type)) { num++; try { int num4 = val.CreateClassProcessor(type).Patch()?.Count ?? 0; num3 += num4; num2++; Log.LogInfo((object)("RSTV: gancho aplicado — " + type.Name + " (" + num4 + " metodo(s) do jogo).")); } catch (Exception ex2) { list.Add(type.Name); Log.LogError((object)("RSTV: FALHA ao aplicar o gancho " + type.Name + " — " + ex2.Message)); } } } string text = "RSTV: patches Harmony aplicados (" + num2 + "/" + num + " ganchos, " + num3 + " metodos do jogo)."; if (list.Count == 0) { Log.LogInfo((object)text); } else { Log.LogError((object)(text + " GANCHOS QUE FALHARAM: " + string.Join(", ", list.ToArray()) + ". O mod continua de pe, mas o recurso que dependia deles nao existe nesta sessao.")); } } private static bool EhClasseDeGancho(Type tipo) { try { if (tipo == null || !tipo.IsClass) { return false; } if (tipo.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length == 0) { return false; } MethodInfo[] methods = tipo.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(HarmonyPrefix), inherit: false).Length != 0 || methodInfo.GetCustomAttributes(typeof(HarmonyPostfix), inherit: false).Length != 0) { return true; } } return false; } catch (Exception) { return false; } } } internal static class RemovalWindowSkillsButton { internal const string ButtonName = "RstvRemovalSkillsButton"; internal const string Label = "Skills"; internal const string TituloEsperado = "Remove Skill Trees"; internal const float Lado = 44f; private const float Margem = 8f; private const float LarguraMinimaDaFaixa = 120f; private static RoguelikeSkillTreeRemovalWindow _window; private static GameObject _button; private static string _reasonLogged; internal static void Ensure(RoguelikeSkillTreeRemovalWindow window) { try { EnsureInternal(window); } catch (Exception ex) { Fail("excecao durante a injecao (" + ex.GetType().Name + "): " + ex.Message, aviso: true); Plugin.Log.LogError((object)("RSTV-20: falha ao injetar o botao do modal 'Remove Skill Trees': " + ex)); } } private static void EnsureInternal(RoguelikeSkillTreeRemovalWindow window) { //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Expected O, but got Unknown if ((Object)(object)window == (Object)null) { Fail("a instancia do modal 'Remove Skill Trees' chegou nula", aviso: false); return; } if (!Plugin.RemocaoBotaoLigado) { Fail(Plugin.MotivoDoBotaoDoModalDesligado, aviso: false); return; } if ((Object)(object)_window == (Object)(object)window && (Object)(object)_button != (Object)null) { Reafirmar(); return; } if ((Object)(object)_button != (Object)null && (Object)(object)_window != (Object)(object)window) { Object.Destroy((Object)(object)_button); _button = null; } Button val = null; string text = null; if (window.CancelButton != null && (Object)(object)window.CancelButton.Root != (Object)null) { val = ((Component)window.CancelButton.Root).GetComponent<Button>(); text = "CancelButton"; } if ((Object)(object)val == (Object)null && window.AcceptButton != null && (Object)(object)window.AcceptButton.Root != (Object)null) { val = ((Component)window.AcceptButton.Root).GetComponent<Button>(); text = "AcceptButton"; } if ((Object)(object)val == (Object)null) { Button[] componentsInChildren = ((Component)window).GetComponentsInChildren<Button>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { val = componentsInChildren[0]; text = "primeiro Button filho do modal"; } } if ((Object)(object)val == (Object)null) { Fail("o modal nao tem nenhum Button nativo para servir de molde (CancelButton/AcceptButton ausentes)", aviso: true); return; } if ((Object)(object)((Component)val).transform == (Object)null || (Object)(object)((Component)val).transform.parent == (Object)null) { Fail("o botao molde ('" + text + "') esta sem Transform ou sem pai na hierarquia", aviso: true); return; } RectTransform val2 = null; string text2 = null; string textoAchado; RectTransform val3 = ProbeFaixaDoTitulo(window, out textoAchado); if ((Object)(object)val3 != (Object)null) { val2 = val3; text2 = "probe do titulo renderizado (\"" + textoAchado + "\")"; } else if ((Object)(object)window.Panel != (Object)null) { val2 = window.Panel; text2 = "Panel (fallback: o probe do titulo nao achou uma faixa larga)"; } else if ((Object)(object)window.TitleText != (Object)null && (Object)(object)((TMP_Text)window.TitleText).rectTransform != (Object)null) { Transform parent = ((Transform)((TMP_Text)window.TitleText).rectTransform).parent; val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); text2 = "pai do TitleText (fallback)"; } else if ((Object)(object)window.TitleDivider != (Object)null) { Transform parent2 = ((Transform)((Graphic)window.TitleDivider).rectTransform).parent; val2 = (RectTransform)(object)((parent2 is RectTransform) ? parent2 : null); text2 = "pai da TitleDivider (fallback)"; } else { Transform transform = ((Component)window).transform; val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); text2 = "transform do proprio modal (fallback)"; } if ((Object)(object)val2 == (Object)null) { Fail("nao foi possivel resolver a area do cabecalho (probe do titulo/Panel/TitleText/TitleDivider nulos)", aviso: true); return; } Transform val4 = Procurar(((Component)window).transform); GameObject val5; if ((Object)(object)val4 != (Object)null) { val5 = ((Component)val4).gameObject; if ((Object)(object)val5.transform.parent != (Object)(object)val2) { val5.transform.SetParent((Transform)(object)val2, false); } } else { val5 = RstvApiUi.Clonar(((Component)val).gameObject, (Transform)(object)val2, "RstvRemovalSkillsButton"); } val5.transform.SetAsLastSibling(); RectTransform component = val5.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { Fail("o clone do botao ficou sem RectTransform", aviso: true); return; } component.anchorMin = new Vector2(1f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(1f, 1f); ((Transform)component).localScale = Vector3.one; ((Transform)component).localRotation = Quaternion.identity; component.sizeDelta = new Vector2(44f, 44f); component.anchoredPosition = new Vector2(-8f, -8f); LayoutElement component2 = val5.GetComponent<LayoutElement>(); if ((Object)(object)component2 != (Object)null) { component2.ignoreLayout = true; } NativeUiHelpers.DisableLocalizers(val5); EnsureLabel(val5); Button component3 = val5.GetComponent<Button>(); if ((Object)(object)component3 == (Object)null) { Fail("o clone do botao ficou sem componente Button", aviso: true); return; } NativeUiHelpers.ClearClickListeners(component3); RstvApiUi.LigarClique(((Component)component3).gameObject, new UnityAction(OnClick)); ((Selectable)component3).interactable = true; val5.SetActive(((Component)window).gameObject.activeSelf); _window = window; _button = val5; _reasonLogged = null; Plugin.Log.LogInfo((object)("RSTV-20: botao 'Skills' injetado no cabecalho do modal 'Remove Skill Trees' (" + 44f.ToString("0.#") + "x" + 44f.ToString("0.#") + " px, canto superior direito de '" + ((Object)val2).name + "' via " + text2 + "), clone de '" + ((Object)((Component)val).gameObject).name + "' (" + text + "; onClick limpo -> SkillTreesTab.AbrirJanela(CurrentCharacter, RemocaoDeArvores) [RSTV-21: janela propria, sem inventario]; janela=" + ((Object)window).name + ".")); } private static void Reafirmar() { if ((Object)(object)_button == (Object)null || (Object)(object)_window == (Object)null) { return; } try { if (_button.activeSelf != ((Component)_window).gameObject.activeSelf) { _button.SetActive(((Component)_window).gameObject.activeSelf); } EnsureLabel(_button); } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-20: nao deu para reafirmar o botao do modal (" + ex.GetType().Name + "): " + ex.Message)); } } private static void OnClick() { try { RoguelikeSkillTreeRemovalWindow window = _window; Character val = (((Object)(object)window != (Object)null) ? window.CurrentCharacter : null); if (val == null) { Plugin.Log.LogWarning((object)"RSTV-20: clique no botao 'Skills' sem personagem no modal (CurrentCharacter nulo) — nada foi aberto."); return; } Plugin.Log.LogInfo((object)("RSTV-20: clique no botao 'Skills' do modal -> '" + val.CharacterName + "' (nivel " + val.Level + ") na JANELA read-only de todas as arvores (RSTV-21).")); SkillTreesTab.AbrirJanela(val, ReadOnlyContext.RemocaoDeArvores, ((Component)window).transform); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-20: falha no clique do botao do modal: " + ex)); } } private static void EnsureLabel(GameObject clone) { TextMeshProUGUI componentInChildren = clone.GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren == (Object)null) { Fail("o clone do botao ficou SEM TextMeshProUGUI — botao sem rotulo", aviso: true); } else { ((TMP_Text)componentInChildren).text = OptionsManager.Localize("Skills", (LanguageGender)0, (Gender)2); } } private static RectTransform ProbeFaixaDoTitulo(RoguelikeSkillTreeRemovalWindow window, out string textoAchado) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) textoAchado = null; try { string text = OptionsManager.Localize("Remove Skill Trees", (LanguageGender)0, (Gender)2); if (string.IsNullOrEmpty(text)) { return null; } TextMeshProUGUI[] componentsInChildren = ((Component)window).GetComponentsInChildren<TextMeshProUGUI>(true); foreach (TextMeshProUGUI val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && ((TMP_Text)val).text != null && !((Object)(object)((TMP_Text)val).rectTransform == (Object)null) && !(((TMP_Text)val).text.Trim() != text.Trim())) { Transform parent = ((Transform)((TMP_Text)val).rectTransform).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 == (Object)null) { return null; } Rect rect = val2.rect; float num = ((Rect)(ref rect)).width; if (num <= 1f) { num = val2.sizeDelta.x; } if (num < 120f) { Plugin.Log.LogInfo((object)("RSTV-20: o probe achou o titulo renderizado, mas o container dele e estreito (" + num.ToString("0.#") + " px < " + 120f.ToString("0.#") + ") — usando o `Panel`.")); return null; } textoAchado = ((TMP_Text)val).text; return val2; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-20: falha no probe do titulo renderizado (" + ex.GetType().Name + "): " + ex.Message)); } return null; } private static Transform Procurar(Transform raiz) { if ((Object)(object)raiz == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)raiz).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name == "RstvRemovalSkillsButton") { return val; } } return null; } private static void Fail(string motivo, bool aviso) { if (!(_reasonLogged == motivo)) { _reasonLogged = motivo; string text = "RSTV DIAG: botao 'Skills' do modal 'Remove Skill Trees' NAO injetado — " + motivo + "."; if (aviso) { Plugin.Log.LogWarning((object)text); } else { Plugin.Log.LogInfo((object)text); } } } } internal static class RstvApiUi { internal static bool Vinculada => UiFamily.IsBound; internal static string UltimoMotivo { get; private set; } internal static void AsegurarVinculo() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown if (UiFamily.IsBound) { return; } try { UiHosts val = new UiHosts { GuiManager = GUIManager.instance }; UiFamily.Bind(typeof(GUIManager).Assembly, val, true); UltimoMotivo = null; Plugin.Log.LogInfo((object)"RSTV INT-R1-C4: familia 'UI' da API vinculada (allowMutation=true) — clone/clique de UI passam a vir de Gumatos.RealmApi.UI."); } catch (Exception ex) { UltimoMotivo = ex.GetType().Name + ": " + ex.Message; Plugin.Log.LogError((object)("RSTV INT-R1-C4: NAO foi possivel vincular a familia 'UI' da API — a plumbing de UI desta chamada nao sera executada (" + UltimoMotivo + "). O mod depende de com.gumatos.realmapi; confira a versao instalada.")); throw; } } internal static GameObject Clonar(GameObject molde, Transform pai, string nome) { AsegurarVinculo(); return UIFactory.Clone(molde, pai, nome); } internal static void LigarClique(GameObject alvo, UnityAction acao) { AsegurarVinculo(); UIFactory.BindClick(alvo, acao); } } internal class RstvHost : MonoBehaviour { private static RstvHost _instance; private float _nextRunMirror; private float _lastErrorLog; internal static RstvHost Ensure() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("RstvHost"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<RstvHost>(); Plugin.Log.LogInfo((object)"RSTV: host criado (cena viva) — Update() ativo."); return _instance; } private void Update() { try { SkillTreesTab.Tick(); LevelUpWindowButton.Refresh(); if (Time.realtimeSinceStartup >= _nextRunMirror) { _nextRunMirror = Time.realtimeSinceStartup + 0.1f; RunButton.Mirror(); } } catch (Exception ex) { if (!(Time.realtimeSinceStartup - _lastErrorLog < 5f)) { _lastErrorLog = Time.realtimeSinceStartup; Plugin.Log.LogError((object)("RSTV: falha no Update do host: " + ex)); } } } } internal static class RunButton { internal const string ButtonName = "RstvRunSkillTreeButton"; internal const string Label = "Skills"; internal const string LabelChildName = "RstvRunLabel"; private const float Margem = 2f; private const float LarguraMinima = 10f; private static CurrentCharacterUI _owner; private static GameObject _button; private static Button _mold; private static CurrentCharacterUI _triedFor; private static float _proximaTentativa; private const float IntervaloDeReinjecao = 2f; private static string _reason; private static string _reasonLogged; private static float _nextReasonLog; private static bool _clicavelLogado; internal static void Ensure(CurrentCharacterUI ui) { try { EnsureInternal(ui); } catch (Exception ex) { Fail("excecao durante a injecao (" + ex.GetType().Name + "): " + ex.Message, aviso: true); Plugin.Log.LogError((object)("RSTV: falha ao injetar o botao da run: " + ex)); } } private static void EnsureInternal(CurrentCharacterUI ui) { //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Expected O, but got Unknown if ((Object)(object)ui == (Object)null) { Fail("a instancia do HUD (CurrentCharacterUI) chegou nula", aviso: false); return; } if (!Plugin.RunBotaoLigado) { Fail(Plugin.MotivoDoBotaoDaRunDesligado, aviso: false); return; } string origem; Button val = EscolherMolde(ui, out origem); if ((Object)(object)val == (Object)null) { Fail("nenhum botao nativo da barra de baixo serve de molde (CurrentCharacterUI.skillsBtn / characterBtn / pingBtn ausentes)", aviso: true); } else if ((Object)(object)((Component)val).transform == (Object)null || (Object)(object)((Component)val).transform.parent == (Object)null) { Fail("o botao nativo molde '" + ((Object)val).name + "' esta sem Transform ou sem pai na hierarquia", aviso: true); } else { if ((Object)(object)_owner == (Object)(object)ui && (Object)(object)_button != (Object)null && (Object)(object)_mold == (Object)(object)val) { return; } if ((Object)(object)_button != (Object)null && ((Object)(object)_owner != (Object)(object)ui || (Object)(object)_mold != (Object)(object)val)) { Object.Destroy((Object)(object)_button); _button = null; } Transform parent = ((Component)val).transform.parent; RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { Fail("o botao nativo molde '" + ((Object)val).name + "' nao tem RectTransform (sem ele nao da para medir o vao livre)", aviso: true); return; } Transform val2 = parent.Find("RstvRunSkillTreeButton"); GameObject val3 = ((!((Object)(object)val2 != (Object)null)) ? RstvApiUi.Clonar(((Component)val).gameObject, parent, "RstvRunSkillTreeButton") : ((Component)val2).gameObject); val3.transform.SetAsLastSibling(); LayoutElement val4 = val3.GetComponent<LayoutElement>(); if ((Object)(object)val4 == (Object)null) { val4 = val3.AddComponent<LayoutElement>(); } val4.ignoreLayout = true; NativeUiHelpers.DisableLocalizers(val3); AparenciaDoClone(val3); RectTransform component2 = val3.GetComponent<RectTransform>(); if ((Object)(object)component2 == (Object)null) { Fail("o clone do botao ficou sem RectTransform", aviso: true); return; } ColocarNaLinha(parent, component, component2, out var medidas); val3.SetActive(((Component)val).gameObject.activeSelf); Button component3 = val3.GetComponent<Button>(); if ((Object)(object)component3 != (Object)null) { NativeUiHelpers.ClearClickListeners(component3); ((UnityEvent)component3.onClick).AddListener(new UnityAction(OpenForTarget)); ((Selectable)component3).interactable = false; } _owner = ui; _button = val3; _mold = val; _triedFor = ui; _reason = null; _reasonLogged = null; _clicavelLogado = false; Plugin.Log.LogInfo((object)("RSTV-30: botao 'Skills' injetado na BARRA DE BAIXO do HUD (" + medidas + "); pai=" + ((Object)parent).name + " (o container dos botoes de inventario e de skills); molde=" + origem + "; grupo do pai=" + NativeUiHelpers.DescribeGroup(parent) + " — o clone esta com ignoreLayout, entao o grupo NAO reflui por nossa causa.")); } } private static Button EscolherMolde(CurrentCharacterUI ui, out string origem) { if ((Object)(object)ui.skillsBtn != (Object)null && (Object)(object)((Component)ui.skillsBtn).transform != (Object)null) { origem = "CurrentCharacterUI.skillsBtn ('Skills Tree Btn' da barra de baixo)"; return ui.skillsBtn; } if ((Object)(object)ui.characterBtn != (Object)null && (Object)(object)((Component)ui.characterBtn).transform != (Object)null) { origem = "CurrentCharacterUI.characterBtn (fallback: 'Character Btn', a mesma linha)"; return ui.characterBtn; } if ((Object)(object)ui.pingBtn != (Object)null && (Object)(object)((Component)ui.pingBtn).transform != (Object)null) { origem = "CurrentCharacterUI.pingBtn (ultimo fallback: o molde da RSTV-5)"; return ui.pingBtn; } origem = null; return null; } internal static void Mirror() { try { CurrentCharacterUI instance = CurrentCharacterUI.Instance; if ((Object)(object)instance == (Object)null) { return; } if (!Plugin.RunBotaoLigado) { Hide(Plugin.MotivoDoBotaoDaRunDesligado, aviso: false); return; } if ((Object)(object)_button == (Object)null) { if ((Object)(object)_triedFor == (Object)(object)instance && Time.realtimeSinceStartup < _proximaTentativa) { return; } _proximaTentativa = Time.realtimeSinceStartup + 2f; if ((Object)(object)_triedFor == (Object)(object)instance) { Fail("o clone do botao foi DESTRUIDO com o mesmo HUD ainda vivo (fake null) — reinjetando (uma tentativa a cada 2 s)", aviso: true); } Ensure(instance); if ((Object)(object)_button == (Object)null) { return; } } if (!((Object)(object)_owner != (Object)(object)instance)) { if ((Object)(object)_mold == (Object)null) { Hide("o botao nativo molde da barra de baixo sumiu do HUD", aviso: true); return; } EspelharVisibilidade(); AplicarClique(); } } catch (Exception ex) { if (!(Time.realtimeSinceStartup < _nextReasonLog)) { _nextReasonLog = Time.realtimeSinceStartup + 5f; Plugin.Log.LogError((object)("RSTV: falha no Mirror do botao da run: " + ex)); } } } private static void EspelharVisibilidade() { bool activeSelf = ((Component)_mold).gameObject.activeSelf; if (_button.activeSelf != activeSelf) { _button.SetActive(activeSelf); } } private static void AplicarClique() { string motivo = null; int num; if ((Object)(object)_mold != (Object)null) { num = (((Selectable)_mold).interactable ? 1 : 0); if (num != 0) { goto IL_0025; } } else { num = 0; } motivo = "o botao nativo 'Skills' do HUD esta desabilitado pelo jogo (GUIManager.Update l.120491: CurrentGuiState fora de InTown/InWorldMap/InCutscene/InBattle, ou Root.HideCharacterButtons ligado)"; goto IL_0025; IL_0025: bool flag = false; if (num != 0) { flag = RunTargets.GateOk(out motivo); } Character val = null; if (((uint)num & (flag ? 1u : 0u)) != 0) { val = RunTargets.Resolve(out motivo); } bool flag2 = ((uint)num & (flag ? 1u : 0u)) != 0 && val != null; Button val2 = (((Object)(object)_button != (Object)null) ? _button.GetComponent<Button>() : null); if ((Object)(object)val2 != (Object)null && ((Selectable)val2).interactable != flag2) { ((Selectable)val2).interactable = flag2; } if (flag2) { if (!_clicavelLogado) { _clicavelLogado = true; _reason = null; _reasonLogged = null; Plugin.Log.LogInfo((object)("RSTV DIAG: botao 'Skills' do HUD VISIVEL e clicavel — alvo '" + val.CharacterName + "' (nivel " + val.Level + ").")); } } else { _clicavelLogado = false; string text = ((motivo != null) ? motivo : "sem alvo local na party"); if (!(_reasonLogged == text)) { _reasonLogged = text; _reason = text; Plugin.Log.LogWarning((object)("RSTV DIAG: botao 'Skills' do HUD VISIVEL na barra de baixo e SEM clique agora — " + text + " (o botao NAO e escondido: quem manda na visibilidade e' o HUD).")); } } } private static void ColocarNaLinha(Transform container, RectTransform moldeRt, RectTransform novo, out string medidas) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4]; RectTransform val = (RectTransform)(object)((container is RectTransform) ? container : null); moldeRt.GetWorldCorners(array); float x = container.InverseTransformPoint(array[0]).x; float x2 = container.InverseTransformPoint(array[3]).x; float num = x2 - x; if (num <= 1f) { num = moldeRt.sizeDelta.x; } Rect rect = moldeRt.rect; float num2 = ((Rect)(ref rect)).height; if (num2 <= 1f) { num2 = moldeRt.sizeDelta.y; } float y = moldeRt.anchoredPosition.y; float num3 = float.MinValue; for (int i = 0; i < container.childCount; i++) { Transform child = container.GetChild(i); if (!((Object)(object)child == (Object)null) && !((Object)(object)child == (Object)(object)((Component)novo).transform) && ((Component)child).gameObject.activeSelf) { RectTransform val2 = (RectTransform)(object)((child is RectTransform) ? child : null); if (!((Object)(object)val2 == (Object)null)) { val2.GetWorldCorners(array); num3 = Mathf.Max(num3, container.InverseTransformPoint(array[3]).x); } } } if (num3 == float.MinValue) { num3 = x2; } float num4 = float.MinValue; string text = "nenhum"; Transform parent = container.parent; if ((Object)(object)parent != (Object)null && (Object)(object)val != (Object)null) { val.GetWorldCorners(array); float x3 = container.InverseTransformPoint(array[3]).x; float num5 = float.MaxValue; for (int j = 0; j < parent.childCount; j++) { Transform child2 = parent.GetChild(j); if ((Object)(object)child2 == (Object)null || (Object)(object)child2 == (Object)(object)container || (Object)(object)child2 == (Object)(object)((Component)novo).transform || !((Component)child2).gameObject.activeSelf) { continue; } RectTransform val3 = (RectTransform)(object)((child2 is RectTransform) ? child2 : null); if (!((Object)(object)val3 == (Object)null)) { val3.GetWorldCorners(array); float x4 = container.InverseTransformPoint(array[0]).x; if (x4 >= x3 - 0.5f && x4 < num5) { num5 = x4; text = ((Object)child2).name; } } } if (num5 < float.MaxValue) { num4 = num5; } } if (num4 == float.MinValue) { num4 = num3 + num + 2f; text = "nenhum (limite = fim dos nativos + largura do molde)"; } float num6 = num4 - num3 - 4f; float num7 = Mathf.Min(num, num6); if (num7 < 1f) { num7 = 1f; } float num8 = num4 - 2f - num7 * 0.5f; float num9 = num3 + 2f + num7 * 0.5f; if (num8 < num9) { num8 = num9; } novo.anchorMin = new Vector2(0f, 1f); novo.anchorMax = new Vector2(0f, 1f); novo.pivot = new Vector2(0.5f, 0.5f); novo.sizeDelta = new Vector2(num7, num2); float num10; if (!((Object)(object)val != (Object)null)) { num10 = 0f; } else { rect = val.rect; num10 = ((Rect)(ref rect)).xMin; } float num11 = num10; novo.anchoredPosition = new Vector2(num8 - num11, y); medidas = "largura=" + num7.ToString("0.#") + " px (nativo " + num.ToString("0.#") + " px), altura=" + num2.ToString("0.#") + " px; borda direita dos nativos=" + num3.ToString("0.#") + " px, limite do vizinho '" + text + "'=" + num4.ToString("0.#") + " px, vao livre=" + num6.ToString("0.#") + " px, margem=" + 2f.ToString("0.#") + " px no espaco local de '" + ((Object)container).name + "'" + ((num7 < 10f) ? (" [AVISO: vao livre abaixo do minimo de conforto (" + 10f.ToString("0.#") + " px) — o botao ficou com o que cabe SEM sobrepor nenhum nativo]") : string.Empty); } private static void AparenciaDoClone(GameObject clone) { try { Button component = clone.GetComponent<Button>(); Graphic val = (((Object)(object)component != (Object)null) ? ((Selectable)component).targetGraphic : null); Graphic[] componentsInChildren = clone.GetComponentsInChildren<Graphic>(true); int num = 0; List<string> list = new List<string>(); foreach (Graphic val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { if (val2 is TextMeshProUGUI) { ((Behaviour)val2).enabled = false; num++; } else if ((Object)(object)val2 == (Object)(object)val || (Object)(object)((Component)val2).transform == (Object)(object)clone.transform || ((Object)((Component)val2).gameObject).name.StartsWith("Icon")) { list.Add(((object)val2).GetType().Name + " em '" + ((Object)((Component)val2).gameObject).name + "'"); } else { ((Behaviour)val2).enabled = false; num++; } } } Plugin.Log.LogInfo((object)("RSTV-30: aparencia do clone — graficos desligados: " + num + "; mantidos: " + ((list.Count > 0) ? string.Join(", ", list.ToArray()) : "nenhum") + " (targetGraphic do clone: " + (((Object)(object)val != (Object)null) ? (((object)val).GetType().Name + " em '" + ((Object)((Component)val).gameObject).name + "'") : "nenhum") + ").")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV: nao deu para limpar a aparencia do clone (" + ex.Message + ").")); } } private static void Hide(string motivo, bool aviso) { _reason = motivo; try { if ((Object)(object)_button != (Object)null && _button.activeSelf) { _button.SetActive(false); } if ((Object)(object)_button != (Object)null) { Button component = _button.GetComponent<Button>(); if ((Object)(object)component != (Object)null && ((Selectable)component).interactable) { ((Selectable)component).interactable = false; } } } catch (Exception) { } if (!(_reasonLogged == motivo)) { _reasonLogged = motivo; _clicavelLogado = false; string text = "RSTV DIAG: botao 'Skills' do HUD escondido — " + motivo + "."; if (aviso) { Plugin.Log.LogWarning((object)text); } else { Plugin.Log.LogInfo((object)text); } } } private static void Fail(string motivo, bool aviso) { _reason = motivo; if (!(_reasonLogged == motivo)) { _reasonLogged = motivo; if (aviso) { Plugin.Log.LogWarning((object)("RSTV DIAG: botao 'Skills' da run NAO injetado — " + motivo + ".")); } else { Plugin.Log.LogInfo((object)("RSTV DIAG: botao 'Skills' da run desativado — " + motivo + ".")); } } } internal static void OpenForTarget() { try { if (!RunTargets.GateOk(out var motivo)) { Plugin.Log.LogWarning((object)("RSTV-5: abertura RECUSADA — " + motivo + ". Nada foi aberto.")); return; } Character val = RunTargets.Resolve(out motivo); if (val == null) { Plugin.Log.LogWarning((object)("RSTV-5: abertura sem alvo — " + motivo + ".")); return; } Plugin.Log.LogInfo((object)("RSTV-16: abrindo a visualizacao read-only -> '" + val.CharacterName + "' (nivel " + val.Level + ") na aba 'All Skill Trees' do inventario.")); SkillTreesTab.Abrir(val, ReadOnlyContext.Run); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao abrir a skill tree da run: " + ex)); } } } internal enum ReadOnlyContext { PartyScreen, Run, Inventario, RemocaoDeArvores } internal static class RunTargets { private static string _fallbackLogado; internal static bool Roguelike { get { try { Root val = GameRoot(); return val != null && val.PlayingRoguelike; } catch (Exception) { return false; } } } internal static bool EstadoPermiteMenuDePersonagem(GUIState estado) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)estado != 4 && (int)estado != 3 && (int)estado != 6) { return (int)estado == 2; } return true; } internal static Root GameRoot() { try { NetworkingManager instance = NetworkingManager.Instance; if ((Object)(object)instance == (Object)null || instance.NetworkManager == null) { return null; } return ((Observer<Root>)(object)instance.NetworkManager).Root; } catch (Exception) { return null; } } private static bool LevelUpAberto() { try { RoguelikeManager instance = RoguelikeManager.Instance; return (Object)(object)instance != (Object)null && (Object)(object)instance.SkillSelectWindow != (Object)null && instance.SkillSelectWindow.activeSelf; } catch (Exception) { return false; } } internal static bool JanelaDoLevelUpAberta() { return LevelUpAberto(); } internal static bool GateOk(out string motivo) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 motivo = null; try { GUIManager instance = GUIManager.instance; if ((Object)(object)instance == (Object)null) { motivo = "GUIManager.instance ausente"; return false; } if (!Roguelike) { motivo = "fora do modo Roguelike (Root.PlayingRoguelike=false)"; return false; } if (LevelUpAberto()) { return true; } if (instance.PingModeActive) { motivo = "modo de apontar o hex ligado (GUIManager.PingModeActive)"; return false; } UIWindowManager instance2 = UIWindowManager.Instance; if ((Object)(object)instance2 != (Object)null && instance2.AnyUIWindowOpen) { motivo = "ja existe uma janela de UI aberta (UIWindowManager.OpenedWindows)"; return false; } Root val = GameRoot(); if (val == null) { motivo = "Root ausente (NetworkingManager/NetworkManager nulos)"; return false; } if ((int)instance.CurrentGuiState == 2) { HexCellManager instance3 = HexCellManager.instance; if ((Object)(object)instance3 != (Object)null && (int)instance3.CurrentState == 2) { motivo = "mira de skill ativa (HexCellManager.CurrentState=Action): abrir aqui cancelaria o apontar hex"; return false; } if (val.SpawnPlacementActive) { motivo = "posicionamento inicial em andamento (Root.SpawnPlacementActive)"; return false; } } return true; } catch (Exception ex) { motivo = "falha ao avaliar o estado do jogo (" + ex.GetType().Name + ": " + ex.Message + ")"; return false; } } private static Character AlvoDoLevelUp() { try { if (!LevelUpAberto()) { return null; } RoguelikeManager instance = RoguelikeManager.Instance; Character currentRoguelikeSkillSelectingCharacter = instance.CurrentRoguelikeSkillSelectingCharacter; if (currentRoguelikeSkillSelectingCharacter != null) { return currentRoguelikeSkillSelectingCharacter; } List<CharacterLevelUpInfo> charactersWaitingForLevelUp = instance.CharactersWaitingForLevelUp; if (charactersWaitingForLevelUp != null && charactersWaitingForLevelUp.Count > 0 && charactersWaitingForLevelUp[0] != null) { return charactersWaitingForLevelUp[0].Character; } return null; } catch (Exception) { return null; } } internal static Character Resolve(out string motivo) { motivo = null; try { GameLogic instance = GameLogic.instance; if ((Object)(object)instance == (Object)null) { motivo = "GameLogic.instance ausente"; return null; } Character val = AlvoDoLevelUp(); if (val != null) { _fallbackLogado = null; if (!val.Owned) { motivo = "'" + val.CharacterName + "' esta em level-up mas e de outro jogador (Owned=false)"; return null; } return val; } Character currentlySelectedCharacter = instance.CurrentlySelectedCharacter; if (currentlySelectedCharacter != null) { _fallbackLogado = null; if (!currentlySelectedCharacter.Owned) { motivo = "'" + currentlySelectedCharacter.CharacterName + "' e de outro jogador (Owned=false)"; return null; } return currentlySelectedCharacter; } Character val2 = FirstOwned(LocalParty()); if (val2 == null) { motivo = "nenhum personagem SEU na party e nenhum selecionado no jogo"; return null; } if (_fallbackLogado != val2.CharacterName) { _fallbackLogado = val2.CharacterName; Plugin.Log.LogInfo((object)("RSTV-5: o jogo esta sem personagem selecionado — usando o fallback documentado '" + val2.CharacterName + "' (primeiro personagem local da party).")); } return val2; } catch (Exception ex) { motivo = "falha ao resolver o alvo (" + ex.GetType().Name + ": " + ex.Message + ")"; return null; } } private static List<Character> LocalParty() { NetworkingManager instance = NetworkingManager.Instance; if ((Object)(object)instance == (Object)null) { return null; } List<Character> myPartyCharacters = instance.MyPartyCharacters; if (myPartyCharacters != null && myPartyCharacters.Count > 0) { return myPartyCharacters; } return instance.MyPartyCharactersUnaccepted; } private static Character FirstOwned(List<Character> lista) { if (lista == null) { return null; } for (int i = 0; i < lista.Count; i++) { Character val = lista[i]; if (val != null && val.Owned) { return val; } } return null; } } internal static class ReadOnlySession { internal static bool Active { get; private set; } internal static Character Target { get; private set; } internal static ReadOnlyContext Context { get; private set; } internal static void Begin(Character target, ReadOnlyContext context) { Active = true; Target = target; Context = context; Plugin.Log.LogInfo((object)("RSTV-16: modo somente leitura ATIVO (contexto=" + context.ToString() + ", alvo=" + ((target != null) ? target.CharacterName : "nenhum") + ") — a vida agora e a do hospedeiro ativo (a aba do inventario ou a janela propria, RSTV-21).")); } internal static void End() { if (Active) { Active = false; Target = null; Plugin.Log.LogInfo((object)"RSTV-16: modo somente leitura encerrado (nada foi gravado no personagem)."); } } internal static void Close() { End(); try { CharacterMenusManager instance = CharacterMenusManager.Instance; if ((Object)(object)instance != (Object)null) { ((UIWindow)instance).CloseWindow(); } if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.tooltip != (Object)null) { GUIManager.instance.tooltip.HideTooltip(); } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-16: falha ao fechar a sessao read-only: " + ex.Message)); } } } internal static class SkillTreeShortcut { internal unsafe static void Handle(KeybindManager kb) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) try { if (!Plugin.AtalhoLigado) { return; } KeyCode teclaAtalho = Plugin.TeclaAtalho; if ((int)teclaAtalho != 0 && Input.GetKeyDown(teclaAtalho)) { if (!Liberado(kb, out var motivo)) { Plugin.Log.LogInfo((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&teclaAtalho))/*cast due to .constrained prefix*/).ToString() + " IGNORADO — " + motivo + ".")); } else { Abrir(teclaAtalho); } } } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV: falha ao tratar o atalho da skill tree: " + ex)); } } private unsafe static bool Liberado(KeybindManager kb, out string motivo) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Invalid comparison between Unknown and I4 motivo = null; if ((Object)(object)kb == (Object)null) { motivo = "KeybindManager ainda nao existe"; return false; } if (kb.DisableKeybinds) { motivo = "keybinds desabilitados pelo jogo (KeybindManager.DisableKeybinds)"; return false; } OptionsManager instance = OptionsManager.instance; if ((Object)(object)instance == (Object)null || instance.CurrentlyBindingControls) { motivo = "remap de tecla em andamento (OptionsManager.CurrentlyBindingControls)"; return false; } if (FocoDeTexto()) { motivo = "campo de texto em foco (chat/inventario/mochila/fortune)"; return false; } if (EventWindow.IsNotNullAndIsActive) { motivo = "janela de evento aberta (EventWindow)"; return false; } GUIManager instance2 = GUIManager.instance; if ((Object)(object)instance2 == (Object)null) { motivo = "GUIManager.instance ausente"; return false; } GUIState currentGuiState = instance2.CurrentGuiState; if ((int)currentGuiState == 1 || (int)currentGuiState == 5) { motivo = "GUIState " + ((object)(*(GUIState*)(¤tGuiState))/*cast due to .constrained prefix*/).ToString() + " (menu sem alvo para a arvore)"; return false; } return true; } private static bool FocoDeTexto() { try { MessageWindowManager instance = MessageWindowManager.instance; if ((Object)(object)instance != (Object)null && instance.TextInputIsFocused) { return true; } if (ItemStashManager.IsNotNullAndIsActive && LoadableUIWindow<ItemStashManager>.Instance.StashInventory.TextInputIsFocused) { return true; } if (ItemStashManager.IsNotNullAndIsActive && LoadableUIWindow<ItemStashManager>.Instance.PlayerInventory.TextInputIsFocused) { return true; } DebugWindow instance2 = DebugWindow.Instance; if ((Object)(object)instance2 != (Object)null && instance2.AllItemsInventory.TextInputIsFocused) { return true; } if (InventoryManager.IsNotNullAndIsActive && LoadableUIWindow<InventoryManager>.Instance.Inventory.TextInputIsFocused) { return true; } if (FortuneWindow.IsNotNullAndIsActive && LoadableUIWindow<FortuneWindow>.Instance.TextInputIsFocused) { return true; } return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-11: nao deu para ler o foco de texto (" + ex.Message + ") — atalho bloqueado por seguranca.")); return true; } } private unsafe static void Abrir(KeyCode tecla) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) RstvHost.Ensure(); if ((Object)(object)(CharacterChoiceManager.IsNotNullAndIsActive ? CharacterChoiceManager.Instance : null) != (Object)null) { Character val = PartyTargets.Resolve(); if (val == null) { Plugin.Log.LogWarning((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " na tela Select Party sem alvo (nenhum personagem SEU na party) — nada foi aberto.")); return; } Plugin.Log.LogInfo((object)("RSTV-16: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " -> aba 'All Skill Trees' do inventario para '" + val.CharacterName + "' (caminho da tela Select Party).")); SkillTreesTab.Abrir(val, ReadOnlyContext.PartyScreen); return; } GUIManager instance = GUIManager.instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogWarning((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " ignorado — GUIManager.instance ausente.")); } else if (!RunTargets.EstadoPermiteMenuDePersonagem(instance.CurrentGuiState)) { Plugin.Log.LogWarning((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " ignorado — GUIState " + ((object)instance.CurrentGuiState/*cast due to .constrained prefix*/).ToString() + " nao permite abrir o menu de personagem (InTown/InWorldMap/InCutscene/InBattle).")); } else { UIWindowManager instance2 = UIWindowManager.Instance; if (!RunTargets.JanelaDoLevelUpAberta() && (Object)(object)instance2 != (Object)null && instance2.AnyUIWindowOpenOtherThan((UIWindow)(object)RoguelikeManager.Instance)) { Plugin.Log.LogWarning((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " ignorado — ja existe uma janela de UI aberta (UIWindowManager.OpenedWindows).")); return; } Plugin.Log.LogInfo((object)("RSTV-11: atalho " + ((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString() + " -> despacho da run (RunButton.OpenForTarget).")); RunButton.OpenForTarget(); } } } internal static class SkillTreesTab { private sealed class BotaoManualDeClasse { internal SkillType Tipo; internal Image Highlight; } internal const string TabName = "RstvAllSkillTreesTab"; internal const string TabLabel = "All Trees"; internal const string PanelName = "RstvAllSkillTreesPanel"; internal const string ClassBarName = "RstvClassBar"; internal const string TreeAreaName = "RstvTreeArea"; internal const string NodeContainerName = "RstvNodeContainer"; private const float MargemSuperior = 6f; private const float MargemInferior = 8f; private const float MargemLateral = 8f; private const float AlturaDaBarraDeClasses = 84f; private const float LadoDoBotaoDeClasse = 64f; private const float LadoDoIconeDaClasse = 56f; private const float EspacamentoDaBarraDeClasses = 9.6f; private const float LarguraDoRotuloDaClasse = 37.86f; private const float AlturaDoRotuloDaClasse = 40f; private const float EscalaDoRotuloDaClasse = 0.7f; private const float YDoRotuloDaClasse = -27.1f; private const float DeslocamentoDoIconeDaClasse = 4f; private const float TamanhoDaFonteDoRotulo = 15f; private const float LarguraDoRotuloManual = 64f; private const float AlturaDoRotuloManual = 16f; private const float YDoRotuloManual = -29f; private const float PaddingHorizontalPadrao = 47f; private const float PaddingVerticalPadrao = 35f; private const float EscalaDoContainerDeNos = 1.7f; private const float LarguraDoContainerDeNos = 1000f; private const float AlturaDoContainerDeNos = 800f; private const float YDoContainerDeNos = 26.7f; private const float LadoDoNoDoPrefab = 30f; private const float EscalaDoNoDoPrefab = 0.9f; private static CharacterMenusManager _menu; private static MenuTabManager _mgr; private static MenuTab _aba; private static TextMeshProUGUI _rotuloAba; private static GameObject _painel; private static RectTransform _areaDaArvore; private static RectTransform _containerDeNos; private static GameObject _barraDeClasses; private static SkillType _tipoAtual = (SkillType)0; private static SkillType _construidoPara = (SkillType)(-1); private static readonly List<SkillTreeItem> _itens = new List<SkillTreeItem>(); private static readonly List<SkillTreeTab> _botoesDeClasse = new List<SkillTreeTab>(); private static readonly List<BotaoManualDeClasse> _botoesManuais = new List<BotaoManualDeClasse>(); private static bool _barraConstruida; private static bool _modoJanela; private static bool _pedido; private static float _pedidoEm; private static ReadOnlyContext _contextoPendente = ReadOnlyContext.Inventario; private static string _ultimoAviso; private static Character _alvoDoPedido; private static Vector2? _underlineOriginal; private static bool _underlineAjustado; internal static bool Aberto { get { if ((Object)(object)_painel != (Object)null) { return _painel.activeSelf; } return false; } } internal static void Ensure(CharacterMenusManager menu) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown try { if ((Object)(object)menu == (Object)null) { Aviso("CharacterMenusManager nulo — impossivel injetar a aba"); return; } _menu = menu; MenuTabManager componentInChildren = ((Component)menu).GetComponentInChildren<MenuTabManager>(true); if ((Object)(object)componentInChildren == (Object)null) { Aviso("MenuTabManager nao encontrado dentro do CharacterMenusManager (a barra de abas mudou?)"); return; } _mgr = componentInChildren; MenuTab val = Procurar(componentInChildren); if ((Object)(object)val != (Object)null) { _aba = val; _rotuloAba = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); FixarLarguraDaAba(((Component)val).gameObject, componentInChildren); return; } if ((Object)(object)menu.TabSkillTree == (Object)null) { Aviso("menu.TabSkillTree nulo — sem o molde nativo nao ha como clonar a aba"); return; } Transform parent = ((Component)menu.TabSkillTree).transform.parent; GameObject obj = Object.Instantiate<GameObject>(((Component)menu.TabSkillTree).gameObject, parent); ((Object)obj).name = "RstvAllSkillTreesTab"; obj.SetActive(true); obj.transform.SetAsLastSibling(); NativeUiHelpers.DisableLocalizers(obj); TextMeshProUGUI componentInChildren2 = obj.GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren2 != (Object)null) { ((TMP_Text)componentInChildren2).text = OptionsManager.Localize("All Trees", (LanguageGender)0, (Gender)2); _rotuloAba = componentInChildren2; } else { Aviso("o clone da aba ficou SEM TextMeshProUGUI — a aba aparece sem rotulo"); } FixarLarguraDaAba(obj, componentInChildren); MenuTab component = obj.GetComponent<MenuTab>(); if ((Object)(object)component == (Object)null) { Aviso("o clone da aba ficou SEM o componente MenuTab (o proprio jogo o reinicializa no Update da barra?)"); } Button component2 = obj.GetComponent<Button>(); if ((Object)(object)component2 != (Object)null) { NativeUiHelpers.ClearClickListeners(component2); ((UnityEvent)component2.onClick).AddListener(new UnityAction(SelecionarEMostrar)); } else { Aviso("o clone da aba ficou SEM Button — a aba nao seria clicavel"); } MenuTab[] array = componentInChildren.MenuTabs; if (array == null) { array = (MenuTab[])(object)new MenuTab[0]; } MenuTab[] array2 = (MenuTab[])(object)new MenuTab[array.Length + 1]; Array.Copy(array, array2, array.Length); array2[array.Length] = component; componentInChildren.MenuTabs = array2; _aba = component; Plugin.Log.LogInfo((object)("RSTV-16: aba 'All Trees' injetada na barra '" + (((Object)(object)parent != (Object)null) ? ((Object)parent).name : "?") + "' (clone de '" + ((Object)((Component)menu.TabSkillTree).gameObject).name + "'); abas agora: " + array2.Length + "; rotulo=" + (((Object)(object)componentInChildren2 != (Object)null) ? ((TMP_Text)componentInChildren2).text : "(sem TMP)") + "; onClick limpo -> SkillTreesTab.SelecionarEMostrar; MenuTabs inclui a aba.")); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-16: falha ao injetar a aba 'All Trees': " + ex)); } } private static MenuTab Procurar(MenuTabManager mgr) { if ((Object)(object)mgr == (Object)null) { return null; } MenuTab[] menuTabs = mgr.MenuTabs; if (menuTabs != null) { foreach (MenuTab val in menuTabs) { if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null && ((Object)((Component)val).gameObject).name == "RstvAllSkillTreesTab") { return val; } } } Transform val2 = ((Component)mgr).transform.Find("RstvAllSkillTreesTab"); if ((Object)(object)val2 != (Object)null) { return ((Component)val2).GetComponent<MenuTab>(); } return null; } private static void FixarLarguraDaAba(GameObject clone, MenuTabManager mgr) { try { float num = LarguraDaAbaNativa(mgr, clone); if (!(num <= 1f)) { LayoutElement val = clone.GetComponent<LayoutElement>(); if ((Object)(object)val == (Object)null) { val = clone.AddComponent<LayoutElement>(); } val.preferredWidth = num; val.minWidth = 0f; val.flexibleWidth = 0f; Plugin.Log.LogInfo((object)("RSTV-17: largura da aba 'All Trees' travada em " + num.ToString("0.##") + "u (a maior aba nativa) para o grupo centrado nao desequilibrar.")); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-17: nao deu para fixar a largura da aba: " + ex.Message)); } } private static float LarguraDaAbaNativa(MenuTabManager mgr, GameObject nova) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) float num = 0f; MenuTab[] array = (((Object)(object)mgr != (Object)null) ? mgr.MenuTabs : null); if (array != null) { foreach (MenuTab val in array) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || (Object)(object)((Component)val).gameObject == (Object)(object)nova) { continue; } float num2 = 0f; TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { num2 = ((TMP_Text)componentInChildren).preferredWidth; } if (num2 <= 1f) { Transform transform = ((Component)val).transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if ((Object)(object)val2 != (Object)null) { Rect rect = val2.rect; num2 = ((Rect)(ref rect)).width; } } if (num2 > num) { num = num2; } } } return num; } internal static void Abrir(Character alvo, ReadOnlyContext contexto) { try { CharacterMenusManager instance = CharacterMenusManager.Instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogError((object)"RSTV-16: CharacterMenusManager.Instance ausente — sem o menu nao ha aba; nada foi aberto."); return; } RstvHost.Ensure(); SairDoModoJanela(); _contextoPendente = contexto; _alvoDoPedido = alvo; Ensure(instance); if ((Object)(object)_mgr == (Object)null || (Object)(object)_aba == (Object)null) { Plugin.Log.LogWarning((object)"RSTV-16: a aba nao esta na barra — o inventario sera aberto, mas a aba 'All Trees' nao existe nesta sessao."); } if (((Component)instance).gameObject.activeSelf) { Plugar(); return; } _pedido = true; _pedidoEm = Time.realtimeSinceStartup; Plugin.Log.LogInfo((object)("RSTV-16: abrindo o inventario (CharacterMenusManager.OpenCharacterMenu) para selecionar a aba 'All Trees' (alvo=" + ((alvo != null) ? alvo.CharacterName : "nenhum") + ").")); instance.OpenCharacterMenu(); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-16: falha ao abrir a aba 'All Trees': " + ex)); } } private static void Plugar() { if ((Object)(object)_mgr == (Object)null || (Object)(object)_aba == (Object)null) { _pedido = false; return; } _pedido = false; _mgr.SelectButtonAndInvoke(_aba); } internal static void AbrirJanela(Character alvo, ReadOnlyContext contexto, Transform dono) { try { RstvHost.Ensure(); SkillTreesWindow.Fechou = AoFecharJanela; _contextoPendente = contexto; _alvoDoPedido = alvo; if ((Object)(object)SkillTreesWindow.Garantir(dono) == (Object)null) { Plugin.Log.LogError((object)"RSTV-21: nao foi possivel criar a janela read-only — nada foi aberto."); return; } if (!_modoJanela) { DestruirPainel(); } _modoJanela = true; IniciarSessaoReadOnly(); Mostrar(); Plugin.Log.LogInfo((object)("RSTV-21: janela read-only ABERTA com TODAS as arvores (alvo=" + ((alvo != null) ? alvo.CharacterName : "nenhum") + ", contexto=" + contexto.ToString() + ") — sem depender do inventario.")); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-21: falha ao abrir a janela read-only: " + ex)); } } private static void SairDoModoJanela() { if (_modoJanela) { _modoJanela = false; SkillTreesWindow.Fechar(); DestruirPainel(); } } private static void AoFecharJanela() { if (_modoJanela) { _modoJanela = false; DestruirPainel(); if (ReadOnlySession.Active) { ReadOnlySession.End(); Plugin.Log.LogInfo((object)"RSTV-21: a janela read-only fechou — modo janela largado e a sessao read-only encerrada."); } } } private static void DestruirPainel() { try { LimparItens(); AjustarUnderline(ligado: false); if ((Object)(object)_painel != (Object)null) { Object.Destroy((Object)(object)_painel); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-21: falha ao desmontar o painel das arvores: " + ex.Message)); } _painel = null; _areaDaArvore = null; _containerDeNos = null; _barraDeClasses = null; _barraConstruida = false; _botoesDeClasse.Clear(); _botoesManuais.Clear(); } internal static void SelecionarEMostrar() { try { RstvHost.Ensure(); SairDoModoJanela(); IniciarSessaoReadOnly(); if ((Object)(object)_mgr != (Object)null && (Object)(object)_aba != (Object)null) { _mgr.SelectButton(_aba); } FecharConteudosNativos(); Mostrar(); AjustarUnderline(ligado: true); Plugin.Log.LogInfo((object)("RSTV-16: aba 'All Trees' selecionada — arvores read-only visiveis (classe=" + ((object)Unsafe.As<SkillType, SkillType>(ref _tipoAtual)/*cast due to .constrained prefix*/).ToString() + ").")); } catch (Exception ex) { Plugin.Log.LogError((object)("RSTV-16: falha ao tratar o clique da aba 'All Trees': " + ex)); } } private static void IniciarSessaoReadOnly() { if (ReadOnlySession.Active) { return; } Character val = null; string motivo = null; Character alvoDoPedido = _alvoDoPedido; _alvoDoPedido = null; if (alvoDoPedido != null) { val = alvoDoPedido; motivo = "alvo explicito do pedido (" + alvoDoPedido.CharacterName + ")"; } else { try { val = RunTargets.Resolve(out motivo); } catch (Exception ex) { motivo = ex.GetType().Name + ": " + ex.Message; } } if (val == null) { Plugin.Log.LogInfo((object)("RSTV-16: nenhum personagem local resolvido para o contexto (" + motivo + ") — a aba mostra TODAS as arvores; o bloqueio de clique segue ativo pela sessao.")); } ReadOnlySession.Begin(val, _contextoPendente); } private static void FecharConteudosNativos() { CharacterMenusManager val = (((Object)(object)_menu != (Object)null) ? _menu : CharacterMenusManager.Instance); if (!((Object)(object)val == (Object)null)) { val.CloseCharacterMenu(); val.CloseSkillTreeMenu(); val.CloseFortuneMenu(); } } internal static void Tick() { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) try { SkillTreesWindow.Atualizar(); if (_pedido) { CharacterMenusManager val = (((Object)(object)_menu != (Object)null) ? _menu : CharacterMenusManager.Instance); if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy) { Plugar(); } else if (Time.realtimeSinceStartup - _pedidoEm > 5f) { _pedido = false; Plugin.Log.LogWarning((object)"RSTV-16: o inventario nao abriu em 5 s (CharacterMenusManager seguiu inativo) — o pedido da aba 'All Trees' foi descartado."); } } if ((Object)(object)_painel == (Object)null) { return; } bool flag = DeviaEstarVisivel(); if (_painel.activeSelf == flag) { if (flag && _construidoPara != _tipoAtual) { Popular(_tipoAtual); } return; } _painel.SetActive(flag); if (flag) { AjustarUnderline(ligado: true); if (_construidoPara != _tipoAtual) { Popular(_tipoAtual); } return; } AjustarUnderline(ligado: false); if (ReadOnlySession.Active) { ReadOnlySession.End(); Plugin.Log.LogInfo((object)(_modoJanela ? "RSTV-21: a janela read-only deixou de estar aberta — sessao read-only encerrada." : "RSTV-16: a aba 'All Trees' deixou de ser a selecionada — sessao read-only encerrada.")); } } catch (Exception ex) { if (!(_ultimoAviso == "tick")) { _ultimoAviso = "tick"; Plugin.Log.LogError((object)("RSTV-16: falha no Tick da aba: " + ex)); } } } private static bool DeviaEstarVisivel() { if (_modoJanela) { return SkillTreesWindow.Aberta; } if ((Object)(object)_aba == (Object)null || (Object)(object)_mgr == (Object)null) { return false; } CharacterMenusManager val = (((Object)(object)_menu != (Object)null) ? _menu : CharacterMenusManager.Instance); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { return false; } return (Object)(object)_mgr.SelectedMenuTab == (Object)(object)_aba; } private static void AjustarUnderline(bool ligado) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) try { if (_modoJanela || (Object)(object)_mgr == (Object)null || (Object)(object)_mgr.Underline == (Object)null) { return; } if (ligado) { if (!_underlineOriginal.HasValue) { _underlineOriginal = _mgr.Underline.sizeDelta; } float num = LarguraDoRotulo(); _mgr.Underline.sizeDelta = new Vector2(num, _underlineOriginal.Value.y); _underlineAjustado = true; } else if (_underlineAjustado && _underlineOriginal.HasValue) { _mgr.Underline.sizeDelta = _underlineOriginal.Value; _underlineAjustado = false; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("RSTV-16: nao deu para ajustar a Underline das abas: " + ex.Message)); } } private static float LarguraDoRotulo() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_rotuloAba != (Object)null) { float preferredWidth = ((TMP_Text)_rotuloAba).preferredWidth; if (preferredWidth > 1f) { return preferredWidth; } Vector2 preferredValues = ((TMP_Text)_rotuloAba).GetPreferredValues(((TMP_Text)_rotuloAba).text); if (preferredValues.x > 1f) { return preferredValues.x; } } } catch (Exception) { } return 130f; } private static void Mostrar() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_painel == (Object)null) { ConstruirPainel(); } if (!((Object)(object)_painel == (Object)null)) { _painel.SetActive(true); if (!_barraConstruida) { ConstruirBarraDeClasses(); } if (_construidoPara != _tipoAtual) { Popular(_tipoAtual); } } } internal static List<SkillType> TiposDaAba() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Invalid comparison between Unknown and I4 //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) List<SkillType> list = new List<SkillType>(); try { GlobalSettingsManager instance = GlobalSettingsManager.instance; SteamManager instance2 = SteamManager.instance; Game instance3 = Game.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.miscSettings == (Object)null || instance.miscSettings.SkillTabTypes == null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null || instance3.Skills == null) { Aviso("GlobalSettingsManager/SteamManager/Game.Skills indisponivel — sem isso nao ha classes para montar"); return list; } List<SkillType> skillTabTypes = instance.miscSettings.SkillTabTypes; for (int i = 0; i < skillTabTypes.Count; i++) { SkillType val = skillTabTypes[i]; if ((int)val != 13 && (int)val != 8 && (int)val != 9 && instance2.MeetsDLCRequirements(val) && TemSkillsVisiveis(val) && !list.Contains(val)) { list.Add(val); } } } catch (Exception ex) { Aviso("nao deu para montar a lista de classes: " + ex.Message); } return list; } private static bool TemSkillsVisiveis(SkillType tipo) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) try { Game instance = Game.Instance; if ((Object)(object)instance == (Object)null || instance.Skills == null) { return false; } List<SkillInfo> skills = instance.Skills; for (int i = 0; i < skills.Count; i++) { SkillInfo val = skill