Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SubSkillsDisplay v1.1.4
SubSkillsDisplay.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using EntityStates; using EntityStates.Acolyte; using EntityStates.Chef; using EntityStates.Drifter; using EntityStates.Drifter.Bag; using EntityStates.Railgunner.Backpack; using EntityStates.Railgunner.Reload; using EntityStates.Railgunner.Scope; using EntityStates.Railgunner.Weapon; using EntityStates.VoidSurvivor.CorruptMode; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using On.RoR2.UI; using RoR2; using RoR2.ContentManagement; using RoR2.Skills; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Events; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SubSkillsDisplay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.4.0")] [assembly: AssemblyInformationalVersion("1.1.4+bf65db680d0bf3c1095f54e07a57bb8e880209c6")] [assembly: AssemblyProduct("SubSkillsDisplay")] [assembly: AssemblyTitle("SubSkillsDisplay")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SubSkillsDisplay { internal static class CharacterSelectDump { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static hook_Awake <>9__1_0; internal void <Init>b__1_0(orig_Awake orig, CharacterSelectController self) { orig.Invoke(self); if (!logged) { ((MonoBehaviour)self).StartCoroutine(DumpAfterLayout(self)); } } } private static bool logged; internal static void Init() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown object obj = <>c.<>9__1_0; if (obj == null) { hook_Awake val = delegate(orig_Awake orig, CharacterSelectController self) { orig.Invoke(self); if (!logged) { ((MonoBehaviour)self).StartCoroutine(DumpAfterLayout(self)); } }; <>c.<>9__1_0 = val; obj = (object)val; } CharacterSelectController.Awake += (hook_Awake)obj; } private static IEnumerator DumpAfterLayout(CharacterSelectController controller) { yield return (object)new WaitForSecondsRealtime(2f); if (logged || !Object.op_Implicit((Object)(object)controller) || !Object.op_Implicit((Object)(object)controller.skillStripContainer)) { yield break; } logged = true; Transform val = (Transform)(object)controller.skillStripContainer; for (int i = 0; i < 2; i++) { if (!Object.op_Implicit((Object)(object)val.parent)) { break; } val = val.parent; } StringBuilder stringBuilder = new StringBuilder("Character select hierarchy:\n"); Append(stringBuilder, val, 0); Log.Info(stringBuilder.ToString()); } private static void Append(StringBuilder sb, Transform transform, int depth) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) sb.Append(' ', depth * 2).Append("- ").Append(((Object)transform).name); if (!((Component)transform).gameObject.activeSelf) { sb.Append(" (inactive)"); } RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null) { StringBuilder stringBuilder = sb.Append(" rect="); Rect rect = val.rect; StringBuilder stringBuilder2 = stringBuilder.Append(Mathf.Round(((Rect)(ref rect)).width)).Append('x'); rect = val.rect; stringBuilder2.Append(Mathf.Round(((Rect)(ref rect)).height)); } LayoutElement component = ((Component)transform).GetComponent<LayoutElement>(); if (Object.op_Implicit((Object)(object)component)) { sb.Append(" LE(prefW=").Append(component.preferredWidth).Append(",prefH=") .Append(component.preferredHeight) .Append(",ignore=") .Append(component.ignoreLayout) .Append(')'); } sb.Append('\n'); for (int i = 0; i < transform.childCount; i++) { Append(sb, transform.GetChild(i), depth + 1); } } } internal readonly struct ExtraSkill { internal readonly SkillDef skill; internal readonly SkillSlot slot; internal readonly string lineToken; internal readonly string sourceToken; internal readonly string descriptionToken; internal readonly bool inLoadout; internal readonly bool unlocked; internal string LineKey { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) string? text; if ((int)slot == -1) { text = lineToken; if (text == null) { return string.Empty; } } else { text = ((object)slot/*cast due to .constrained prefix*/).ToString(); } return text; } } internal ExtraSkill(SkillDef skill, SkillSlot slot, string sourceToken, bool inLoadout, bool unlocked, string descriptionToken = null, string lineToken = null) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 this.skill = skill; this.slot = slot; this.lineToken = (((int)slot == -1) ? lineToken : null); this.sourceToken = sourceToken; this.inLoadout = inLoadout; this.unlocked = unlocked; this.descriptionToken = (string.IsNullOrEmpty(descriptionToken) ? skill.skillDescriptionToken : descriptionToken); } } internal static class ExtraSkillCatalog { private sealed class StateRule { internal readonly Type parentState; private readonly Func<IEnumerable<(SkillSlot, SkillDef)>> resolve; private (SkillSlot slot, SkillDef skill)[] extras; internal (SkillSlot slot, SkillDef skill)[] Extras => extras ?? (extras = (from extra in resolve() where Object.op_Implicit((Object)(object)extra.Item2) select extra).ToArray()); internal StateRule(Type parentState, Func<IEnumerable<(SkillSlot, SkillDef)>> resolve) { this.parentState = parentState; this.resolve = resolve; } } internal static bool includeModdedSurvivors = true; private static readonly StateRule[] stateRules = new StateRule[6] { new StateRule(typeof(WindUpScopeHeavy), ScopeShots<ActiveScopeHeavy>), new StateRule(typeof(WindUpScopeLight), ScopeShots<ActiveScopeLight>), new StateRule(typeof(ChargeSnipeSuper), () => new(SkillSlot, SkillDef)[1] { ((SkillSlot)0, ((BaseCharged)Configured<ChargedSuper>()).primaryOverride) }), new StateRule(typeof(ChargeSnipeCryo), () => new(SkillSlot, SkillDef)[1] { ((SkillSlot)0, ((BaseCharged)Configured<ChargedCryo>()).primaryOverride) }), new StateRule(typeof(AimRepossess), delegate { BaggedObject val = Configured<BaggedObject>(); return new(SkillSlot, SkillDef)[2] { ((SkillSlot)0, val.primaryOverride), ((SkillSlot)2, val.utilityOverride) }; }), new StateRule(typeof(ChargeTornadoSlam), () => new(SkillSlot, SkillDef)[1] { ((SkillSlot)0, Configured<TornadoSlam>().primaryOverride) }) }; internal static List<ExtraSkill> For(SurvivorLoadout body, bool includeOtherLoadouts) { List<ExtraSkill> found = new List<ExtraSkill>(); if (!body.IsValid) { return found; } Collect("hidden loadout rows", delegate { AddHiddenSlots(body, found); }); Collect("Acolyte forms", delegate { AddAcolyteForms(body, found); }); Collect("CHEF boosts", delegate { AddChefBoosts(body, found); }); Collect("Void Fiend corruption", delegate { AddCorruptedSkills(body, found); }); StateRule[] array = stateRules; foreach (StateRule rule in array) { Collect(rule.parentState.Name, delegate { AddForState(body, rule.parentState, rule.Extras, null, found); }); } if (includeModdedSurvivors) { Collect("modded survivors", delegate { ModdedExtraSkills.Add(body, found); }); } HashSet<(string, string)> choices = new HashSet<(string, string)>(); foreach (GenericSkill item2 in body.slots.Where((GenericSkill slot) => !slot.hideInCharacterSelect)) { foreach (var item3 in body.Variants(item2)) { SkillDef item = item3.skill; choices.Add((item.skillNameToken, item.skillDescriptionToken)); } } HashSet<(string, string, string)> listed = new HashSet<(string, string, string)>(); return (from extra in found where extra.unlocked && (extra.inLoadout || includeOtherLoadouts) where !choices.Contains((extra.skill.skillNameToken, extra.descriptionToken)) where listed.Add((extra.LineKey, extra.skill.skillNameToken, extra.descriptionToken)) select extra).ToList(); } internal static void LogAll(UserProfile profile) { //IL_0029: 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_003e: Unknown result type (might be due to invalid IL or missing references) Loadout val = Loadout.RequestInstance(); try { StringBuilder stringBuilder = new StringBuilder("Extra skills per unlocked survivor (all unlocked loadouts):"); foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs) { if (!SurvivorCatalog.SurvivorIsUnlockedOnThisClient(orderedSurvivorDef.survivorIndex)) { continue; } List<ExtraSkill> list = For(SurvivorLoadout.FromLoadout(SurvivorCatalog.GetBodyIndexFromSurvivorIndex(orderedSurvivorDef.survivorIndex), val, profile), includeOtherLoadouts: true); if (list.Count != 0) { stringBuilder.Append("\n ").Append(Language.GetString(orderedSurvivorDef.displayNameToken)).Append(": "); stringBuilder.Append(string.Join(", ", list.Select((ExtraSkill extra) => extra.LineKey + ": " + Language.GetString(extra.skill.skillNameToken) + " [" + extra.skill.skillName + "] (" + Language.GetString(extra.sourceToken ?? "") + ")"))); } } Log.Info(stringBuilder.ToString()); } finally { Loadout.ReturnInstance(val); } } private static void AddHiddenSlots(SurvivorLoadout body, List<ExtraSkill> found) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) CaptainSupplyDropController component = body.GetComponent<CaptainSupplyDropController>(); AcolyteFormController component2 = body.GetComponent<AcolyteFormController>(); foreach (GenericSkill item in body.slots.Where((GenericSkill val) => val.hideInCharacterSelect)) { if (Object.op_Implicit((Object)(object)component2) && (Object)(object)item == (Object)(object)component2.transformSkillSlot) { continue; } SkillSlot slot = (SkillSlot)(-1); string sourceToken = null; if (Object.op_Implicit((Object)(object)component) && ((Object)(object)item == (Object)(object)component.supplyDrop1Skill || (Object)(object)item == (Object)(object)component.supplyDrop2Skill)) { slot = (SkillSlot)(!((Object)(object)item == (Object)(object)component.supplyDrop1Skill)); sourceToken = body.Selected(component.prepSupplyDropSkill)?.skillNameToken; } string lineToken = (string.IsNullOrEmpty(item.loadoutTitleToken) ? null : item.loadoutTitleToken); foreach (var (skill, inLoadout, unlocked) in body.Variants(item)) { found.Add(new ExtraSkill(skill, slot, sourceToken, inLoadout, unlocked, null, lineToken)); } } } private static void AddAcolyteForms(SurvivorLoadout body, List<ExtraSkill> found) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) AcolyteBodySwapController component = body.GetComponent<AcolyteBodySwapController>(); if (!Object.op_Implicit((Object)(object)component)) { return; } AcolyteFormController component2 = body.GetComponent<AcolyteFormController>(); GenericSkill val = (Object.op_Implicit((Object)(object)component2) ? component2.transformSkillSlot : null); foreach (var (skill, inLoadout, unlocked) in body.Variants(val)) { found.Add(new ExtraSkill(skill, (SkillSlot)3, val.loadoutTitleToken, inLoadout, unlocked)); } List<(SkillSlot, SkillDef)> list = new List<(SkillSlot, SkillDef)> { ((SkillSlot)0, component.primarySkillOverride), ((SkillSlot)1, component.secondarySkillOverride), ((SkillSlot)2, component.utilitySkillOverride), ((SkillSlot)3, component.specialSkillOverride) }; list.AddRange(component.reaperProjectileSkillOverrides.Select((ProjectileSkillOverrideData projectileOverride) => (body.KindOf(projectileOverride.skill), skillOverride: projectileOverride.skillOverride))); AddForState(body, typeof(EnterBodySwap), list, component.baseNameToken, found); ProjectileSkillOverrideData[] acolyteProjectileSkillOverrides = component.acolyteProjectileSkillOverrides; foreach (ProjectileSkillOverrideData val2 in acolyteProjectileSkillOverrides) { if (Object.op_Implicit((Object)(object)val2.skillOverride) && Object.op_Implicit((Object)(object)val2.skill)) { found.Add(new ExtraSkill(val2.skillOverride, body.KindOf(val2.skill), body.Selected(val2.skill)?.skillNameToken, inLoadout: true, unlocked: true)); } } } private static void AddChefBoosts(SurvivorLoadout body, List<ExtraSkill> found) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) ChefController component = body.GetComponent<ChefController>(); if (!Object.op_Implicit((Object)(object)component)) { return; } (SkillSlot, SkillDef)[] array = new(SkillSlot, SkillDef)[5] { ((SkillSlot)0, component.primarySkillOverrideDef), ((SkillSlot)1, component.secondarySkillOverrideDef), ((SkillSlot)1, component.secondaryAltSkillOverrideDef), ((SkillSlot)2, component.utilitySkillOverrideDef), ((SkillSlot)2, component.utilityAltSkillOverrideDef) }; GenericSkill[] slots = body.slots; foreach (GenericSkill slot in slots) { foreach (var item4 in from variant in body.Variants(slot) where Enters(variant.skill, typeof(YesChef)) select variant) { SkillDef item = item4.skill; bool item2 = item4.selected; bool item3 = item4.unlocked; (SkillSlot, SkillDef)[] array2 = array; for (int num = 0; num < array2.Length; num++) { var (val, val2) = array2[num]; if (Object.op_Implicit((Object)(object)val2)) { SkillDef val3 = body.Selected(val); bool flag = Object.op_Implicit((Object)(object)val3) && val3.skillName == val2.skillName; bool flag2 = body.IsUnlocked(val, val2.skillName); found.Add(new ExtraSkill(val2, val, item.skillNameToken, item2 && flag, item3 && flag2)); } } } } } private static void AddCorruptedSkills(SurvivorLoadout body, List<ExtraSkill> found) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)body.GetComponent<VoidSurvivorController>())) { return; } CorruptMode val = Configured<CorruptMode>(); (SkillSlot, SkillDef)[] obj = new(SkillSlot, SkillDef)[4] { ((SkillSlot)0, val.primaryOverrideSkillDef), ((SkillSlot)1, val.secondaryOverrideSkillDef), ((SkillSlot)2, val.utilityOverrideSkillDef), ((SkillSlot)3, val.specialOverrideSkillDef) }; SkillDef val2 = body.slots.Where((GenericSkill slot) => !slot.hideInCharacterSelect && (int)body.KindOf(slot) == -1).Select(body.Selected).FirstOrDefault((Func<SkillDef, bool>)((SkillDef skill) => Object.op_Implicit((Object)(object)skill))); (SkillSlot, SkillDef)[] array = obj; for (int num = 0; num < array.Length; num++) { var (val3, val4) = array[num]; if (!Object.op_Implicit((Object)(object)val4)) { continue; } SkillDef val5 = body.Selected(val3); string descriptionToken = null; if (Object.op_Implicit((Object)(object)val5) && val5.skillDescriptionToken == val4.skillDescriptionToken && val5.keywordTokens != null) { descriptionToken = val5.keywordTokens.FirstOrDefault((string token) => !token.StartsWith("KEYWORD_", StringComparison.Ordinal)); } found.Add(new ExtraSkill(val4, val3, Object.op_Implicit((Object)(object)val2) ? val2.skillNameToken : null, inLoadout: true, unlocked: true, descriptionToken)); } } private static void AddForState(SurvivorLoadout body, Type parentState, IEnumerable<(SkillSlot slot, SkillDef skill)> extras, string sourceToken, List<ExtraSkill> found) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) (SkillSlot, SkillDef)[] array = extras.Where(((SkillSlot slot, SkillDef skill) extra) => Object.op_Implicit((Object)(object)extra.skill)).ToArray(); GenericSkill[] slots = body.slots; foreach (GenericSkill slot in slots) { foreach (var item4 in from variant in body.Variants(slot) where Enters(variant.skill, parentState) select variant) { SkillDef item = item4.skill; bool item2 = item4.selected; bool item3 = item4.unlocked; (SkillSlot, SkillDef)[] array2 = array; for (int num2 = 0; num2 < array2.Length; num2++) { var (slot2, skill) = array2[num2]; found.Add(new ExtraSkill(skill, slot2, sourceToken ?? item.skillNameToken, item2, item3)); } } } } private static IEnumerable<(SkillSlot, SkillDef)> ScopeShots<TActiveScope>() where TActiveScope : BaseActive, new() { SkillDef shot = ((BaseActive)Configured<TActiveScope>()).primaryOverride; yield return ((SkillSlot)0, shot); Type type = (Object.op_Implicit((Object)(object)shot) ? ((SerializableEntityStateType)(ref shot.activationState)).stateType : null); if (type != null) { EntityState obj = EntityStateCatalog.InstantiateState(type); BaseFireSnipe val = (BaseFireSnipe)(object)((obj is BaseFireSnipe) ? obj : null); if (val != null && val.queueReload) { yield return ((SkillSlot)0, Configured<Reloading>().primaryOverride); } } } private static bool Enters(SkillDef skill, Type state) { Type stateType = ((SerializableEntityStateType)(ref skill.activationState)).stateType; if (stateType != null) { if (!(stateType == state)) { return stateType.IsSubclassOf(state); } return true; } return false; } private static T Configured<T>() where T : EntityState, new() { return new T(); } private static void Collect(string source, Action collect) { try { collect(); } catch (Exception arg) { Log.Warning($"Could not read the extra skills from {source}: {arg}"); } } } internal static class ExtraSkillsTab { internal class ExtraSkillsView : MonoBehaviour { private RectTransform panel; private TMP_Text intro; private LanguageTextMeshController hoverText; private UILayerKey requiredTopLayer; private List<GameObject> rows = new List<GameObject>(); internal void Init(RectTransform panel, TMP_Text intro, LanguageTextMeshController hoverText, UILayerKey requiredTopLayer) { this.panel = panel; this.intro = intro; this.hoverText = hoverText; this.requiredTopLayer = requiredTopLayer; } internal void Rebuild(CharacterSelectController controller) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) List<ExtraSkill> extras = new List<ExtraSkill>(); Color color = Color.gray; LocalUser localUser = controller.localUser; NetworkUser val = ((localUser != null) ? localUser.currentNetworkUser : null); SurvivorDef val2 = (Object.op_Implicit((Object)(object)val) ? val.GetSurvivorPreference() : null); if (Object.op_Implicit((Object)(object)val2) && localUser.userProfile != null && SurvivorCatalog.SurvivorIsUnlockedOnThisClient(val2.survivorIndex)) { BodyIndex bodyIndexFromSurvivorIndex = SurvivorCatalog.GetBodyIndexFromSurvivorIndex(val2.survivorIndex); CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndexFromSurvivorIndex); if (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent)) { color = bodyPrefabBodyComponent.bodyColor; } Loadout val3 = Loadout.RequestInstance(); try { localUser.userProfile.CopyLoadout(val3); extras = ExtraSkillCatalog.For(SurvivorLoadout.FromLoadout(bodyIndexFromSurvivorIndex, val3, localUser.userProfile), includeOtherLoadouts: true); } finally { Loadout.ReturnInstance(val3); } } foreach (GameObject row in rows) { Object.Destroy((Object)(object)row); } List<SkillLine> list = SkillLine.FromExtras(extras); rows = SkillLines.Build(panel, list, color, hoverText, requiredTopLayer); if (Object.op_Implicit((Object)(object)intro)) { intro.SetText(Language.GetString((list.Count > 0) ? "SUBSKILLSDISPLAY_EXTRA_INTRO" : "SUBSKILLSDISPLAY_EXTRA_NONE"), true); intro.transform.SetAsFirstSibling(); } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static hook_Awake <>9__2_0; public static hook_RebuildLocal <>9__2_1; public static Predicate<Header> <>9__3_0; internal void <Init>b__2_0(orig_Awake orig, CharacterSelectController self) { orig.Invoke(self); Build(self); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); UserProfile val = ((firstLocalUser != null) ? firstLocalUser.userProfile : null); if (logPending && val != null) { logPending = false; ExtraSkillCatalog.LogAll(val); } } internal void <Init>b__2_1(orig_RebuildLocal orig, CharacterSelectController self, bool deselectButtons) { orig.Invoke(self, deselectButtons); ExtraSkillsView component = ((Component)self).GetComponent<ExtraSkillsView>(); if (Object.op_Implicit((Object)(object)component)) { component.Rebuild(self); } } internal bool <Build>b__3_0(Header header) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)header.headerRoot)) { return Object.op_Implicit((Object)(object)header.headerRoot.GetComponent<LoadoutPanelController>()); } return false; } } private const string HeaderName = "SubSkillsDisplayExtra"; private static bool logPending; internal static void Init(bool logExtraSkills) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_003e: 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) //IL_0049: Expected O, but got Unknown logPending = logExtraSkills; object obj = <>c.<>9__2_0; if (obj == null) { hook_Awake val = delegate(orig_Awake orig, CharacterSelectController self) { orig.Invoke(self); Build(self); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); UserProfile val3 = ((firstLocalUser != null) ? firstLocalUser.userProfile : null); if (logPending && val3 != null) { logPending = false; ExtraSkillCatalog.LogAll(val3); } }; <>c.<>9__2_0 = val; obj = (object)val; } CharacterSelectController.Awake += (hook_Awake)obj; object obj2 = <>c.<>9__2_1; if (obj2 == null) { hook_RebuildLocal val2 = delegate(orig_RebuildLocal orig, CharacterSelectController self, bool deselectButtons) { orig.Invoke(self, deselectButtons); ExtraSkillsView component = ((Component)self).GetComponent<ExtraSkillsView>(); if (Object.op_Implicit((Object)(object)component)) { component.Rebuild(self); } }; <>c.<>9__2_1 = val2; obj2 = (object)val2; } CharacterSelectController.RebuildLocal += (hook_RebuildLocal)obj2; } private static void Build(CharacterSelectController controller) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Expected O, but got Unknown //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Expected O, but got Unknown RectTransform skillPanel = controller.skillStripContainer; HGHeaderNavigationController navigation = null; int num = -1; if (Object.op_Implicit((Object)(object)skillPanel)) { HGHeaderNavigationController[] componentsInChildren = ((Component)controller).GetComponentsInChildren<HGHeaderNavigationController>(true); foreach (HGHeaderNavigationController val in componentsInChildren) { num = val.headers.FindIndex((Header header) => (Object)(object)header.headerRoot == (Object)(object)((Component)skillPanel).gameObject); if (num >= 0) { navigation = val; break; } } } if (!Object.op_Implicit((Object)(object)navigation)) { Log.Warning("Character select has no Skills tab to model the Extra Skills tab on; skipping it."); return; } ModTokens.Register(); Header val2 = navigation.headers[num]; int num2 = navigation.headers.FindIndex((Header header) => Object.op_Implicit((Object)(object)header.headerRoot) && Object.op_Implicit((Object)(object)header.headerRoot.GetComponent<LoadoutPanelController>())); MPButton headerButton = navigation.headers[(num2 >= 0) ? num2 : (navigation.headers.Count - 1)].headerButton; GameObject val3 = Object.Instantiate<GameObject>(((Component)skillPanel).gameObject, ((Transform)skillPanel).parent, false); ((Object)val3).name = "ExtraSkillPanel"; val3.SetActive(false); VerticalLayoutGroup component = val3.GetComponent<VerticalLayoutGroup>(); if (Object.op_Implicit((Object)(object)component)) { ((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false; } GameObject val4 = UiHierarchy.Counterpart((Transform)(object)skillPanel, val3.transform, controller.skillStripPrefab); HGButton val5 = (Object.op_Implicit((Object)(object)val4) ? val4.GetComponent<HGButton>() : null); object obj; if (!Object.op_Implicit((Object)(object)val4)) { obj = null; } else { Transform obj2 = val4.transform.Find("Inner/SkillDescriptionPanel/SkillDescription"); obj = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null); } TMP_Text val6 = (TMP_Text)obj; TMP_Text val7 = (Object.op_Implicit((Object)(object)val6) ? UiHierarchy.AddText(val6, val3.transform, "Intro") : null); if (Object.op_Implicit((Object)(object)val7)) { val7.transform.SetAsFirstSibling(); } MPButton headerButton2 = val2.headerButton; GameObject val8 = Object.Instantiate<GameObject>(((Component)headerButton2).gameObject, ((Component)headerButton2).transform.parent, false); ((Object)val8).name = "GenericMenuButton (Extra Skills)"; val8.transform.SetSiblingIndex(((Component)headerButton).transform.GetSiblingIndex() + 1); MPButton button = val8.GetComponent<MPButton>(); ((Button)button).onClick = new ButtonClickedEvent(); ((UnityEvent)((Button)button).onClick).AddListener((UnityAction)delegate { navigation.ChooseHeaderByButton(button); }); LanguageTextMeshController component2 = val8.GetComponent<LanguageTextMeshController>(); if (Object.op_Implicit((Object)(object)component2)) { component2.token = "SUBSKILLSDISPLAY_TAB_EXTRA"; } controller.primaryColorImages = WithCopies<Image>(controller.primaryColorImages, ((Component)headerButton2).transform, val8.transform); controller.primaryColorTexts = WithCopies<TextMeshProUGUI>(controller.primaryColorTexts, ((Component)headerButton2).transform, val8.transform); navigation.headers.Add(new Header { headerButton = button, headerName = "SubSkillsDisplayExtra", tmpHeaderText = UiHierarchy.Counterpart<TextMeshProUGUI>(((Component)headerButton2).transform, val8.transform, val2.tmpHeaderText), headerRoot = val3, AreConsolePlatformsSupported = val2.AreConsolePlatformsSupported, isPrimaryPlayerOnly = val2.isPrimaryPlayerOnly }); ((Component)controller).gameObject.AddComponent<ExtraSkillsView>().Init((RectTransform)val3.transform, val7, Object.op_Implicit((Object)(object)val5) ? val5.hoverLanguageTextMeshController : null, Object.op_Implicit((Object)(object)val5) ? ((MPButton)val5).requiredTopLayer : null); Log.Info("Added the Extra Skills tab to character select."); } private static T[] WithCopies<T>(T[] painted, Transform original, Transform copy) where T : Component { if (painted == null) { return null; } List<T> list = new List<T>(painted); foreach (T val in painted) { T val2 = ((Object.op_Implicit((Object)(object)val) && ((Component)val).transform.IsChildOf(original)) ? UiHierarchy.Counterpart(original, copy, val) : default(T)); if (Object.op_Implicit((Object)(object)val2)) { list.Add(val2); } } return list.ToArray(); } } internal static class Keywords { private static readonly Regex keywordName = new Regex("<style=cKeywordName>(.*?)</style>", RegexOptions.Singleline); private static readonly Regex highlighted = new Regex("<style=c[A-Za-z]+>(.*?)</style>", RegexOptions.Singleline); private static readonly Regex tags = new Regex("<[^>]+>"); private static Dictionary<string, string> tokenByName; private static string builtForLanguage; internal static List<string> For(string[] ownTokens, string description) { Build(); List<string> list = (ownTokens ?? Array.Empty<string>()).Where((string token) => !string.IsNullOrEmpty(token)).Distinct().ToList(); foreach (Match item in highlighted.Matches(description ?? string.Empty)) { string input = tags.Replace(item.Groups[1].Value, string.Empty); foreach (KeyValuePair<string, string> item2 in tokenByName) { if (item2.Value != null && !list.Contains(item2.Value) && Regex.IsMatch(input, "\\b" + Regex.Escape(item2.Key) + "(s|es|d|ed)?\\b", RegexOptions.IgnoreCase)) { list.Add(item2.Value); } } } return list; } private static void Build() { if (tokenByName != null && builtForLanguage == Language.currentLanguageName) { return; } builtForLanguage = Language.currentLanguageName; tokenByName = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (string item in (from token in SkillCatalog.allSkillDefs.Where((SkillDef skill) => Object.op_Implicit((Object)(object)skill) && skill.keywordTokens != null).SelectMany((SkillDef skill) => skill.keywordTokens).Concat(from body in BodyCatalog.allBodyPrefabBodyBodyComponents where Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)((Component)body).GetComponent<SkillLocator>()) select ((Component)body).GetComponent<SkillLocator>().passiveSkill.keywordToken) where !string.IsNullOrEmpty(token) select token).Distinct()) { Match match = keywordName.Match(Language.GetString(item)); string text = (match.Success ? tags.Replace(match.Groups[1].Value, string.Empty).Trim() : null); if (!string.IsNullOrEmpty(text) && text.Length >= 3) { if (!tokenByName.TryGetValue(text, out var value)) { tokenByName[text] = item; } else if (value != null && value != item) { bool flag = value.StartsWith("KEYWORD_", StringComparison.Ordinal); bool flag2 = item.StartsWith("KEYWORD_", StringComparison.Ordinal); tokenByName[text] = ((flag == flag2) ? null : (flag ? value : item)); } } } } } internal static class Log { private static ManualLogSource _source; internal static void Init(ManualLogSource source) { _source = source; } internal static void Debug(object data) { _source.LogDebug(data); } internal static void Info(object data) { _source.LogInfo(data); } internal static void Message(object data) { _source.LogMessage(data); } internal static void Warning(object data) { _source.LogWarning(data); } internal static void Error(object data) { _source.LogError(data); } internal static void Fatal(object data) { _source.LogFatal(data); } } internal static class ModdedExtraSkills { private sealed class ModdedSurvivor { internal BodyIndex bodyIndex; internal GameObject body; internal string tokenStem; internal HashSet<string> stateNamespaces; internal HashSet<Assembly> assemblies; internal readonly Dictionary<SkillDef, SkillSlot> unlinked = new Dictionary<SkillDef, SkillSlot>(); internal void AddUnlinked(SkillDef skill, SkillSlot slot) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (!unlinked.TryGetValue(skill, out var value) || (int)value == -1) { unlinked[skill] = slot; } } } private static readonly string[] slotWords = new string[4] { "primary", "secondary", "utility", "special" }; private static Dictionary<BodyIndex, ModdedSurvivor> survivors; private static HashSet<SkillDef> loadoutChoices; private static readonly Dictionary<Type, (SkillDef skill, SkillSlot slot)[]> skillsNamedByState = new Dictionary<Type, (SkillDef, SkillSlot)[]>(); internal static void Add(SurvivorLoadout body, List<ExtraSkill> found) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Invalid comparison between Unknown and I4 //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Invalid comparison between Unknown and I4 //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) if (survivors == null) { FindSurvivors(); } if (!survivors.TryGetValue(body.bodyIndex, out var value)) { return; } Dictionary<SkillDef, (SkillSlot slot, string sourceToken, bool selected, bool unlocked)> links = new Dictionary<SkillDef, (SkillSlot, string, bool, bool)>(); GenericSkill[] slots = body.slots; foreach (GenericSkill slot in slots) { foreach (var (val, flag, flag2) in body.Variants(slot)) { foreach (var item3 in from entry in SkillsNamedBy(((SerializableEntityStateType)(ref val.activationState)).stateType) where IsCandidate(entry.skill) select entry) { SkillDef item = item3.skill; SkillSlot item2 = item3.slot; SkillSlot value2; SkillSlot val2 = (SkillSlot)(((int)item2 != -1) ? ((int)item2) : (value.unlinked.TryGetValue(item, out value2) ? ((int)value2) : (-1))); links[item] = (links.TryGetValue(item, out (SkillSlot, string, bool, bool) value3) ? (((int)value3.Item1 != -1) ? value3.Item1 : val2, flag ? val.skillNameToken : value3.Item2, value3.Item3 || flag, value3.Item4 || flag2) : (val2, val.skillNameToken, flag, flag2)); } } } foreach (KeyValuePair<SkillDef, (SkillSlot, string, bool, bool)> item4 in links) { found.Add(new ExtraSkill(item4.Key, item4.Value.Item1, item4.Value.Item2, item4.Value.Item3, item4.Value.Item4)); } foreach (KeyValuePair<SkillDef, SkillSlot> item5 in value.unlinked.Where((KeyValuePair<SkillDef, SkillSlot> entry) => !links.ContainsKey(entry.Key))) { found.Add(new ExtraSkill(item5.Key, item5.Value, null, inLoadout: true, unlocked: true)); } } private static void FindSurvivors() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Invalid comparison between Unknown and I4 //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) survivors = new Dictionary<BodyIndex, ModdedSurvivor>(); loadoutChoices = new HashSet<SkillDef>(from variant in SkillCatalog.allSkillFamilies.Where((SkillFamily family) => Object.op_Implicit((Object)(object)family)).SelectMany((SkillFamily family) => family.variants) select variant.skillDef into val3 where Object.op_Implicit((Object)(object)val3) select val3); foreach (ReadOnlyContentPack item in ((IEnumerable<ReadOnlyContentPack>)(object)ContentManager.allLoadedContentPacks).Where((ReadOnlyContentPack pack) => !IsVanilla(((ReadOnlyContentPack)(ref pack)).identifier))) { ReadOnlyContentPack current = item; AssetEnumerator<SurvivorDef> enumerator2 = ((ReadOnlyContentPack)(ref current)).survivorDefs.GetEnumerator(); try { while (enumerator2.MoveNext()) { SurvivorDef current2 = enumerator2.Current; BodyIndex val = (BodyIndex)((!Object.op_Implicit((Object)(object)current2) || current2.hidden || !Object.op_Implicit((Object)(object)current2.bodyPrefab)) ? (-1) : ((int)BodyCatalog.FindBodyIndex(current2.bodyPrefab))); if ((int)val != -1 && !survivors.ContainsKey(val)) { survivors[val] = Describe(current2, val); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } if (survivors.Count == 0) { return; } foreach (Assembly assembly in survivors.Values.SelectMany((ModdedSurvivor survivor) => survivor.assemblies).Distinct()) { List<ModdedSurvivor> list = survivors.Values.Where((ModdedSurvivor survivor) => survivor.assemblies.Contains(assembly)).ToList(); List<OverrideCallScanner.Found> source; try { source = OverrideCallScanner.Scan(assembly, list.Select((ModdedSurvivor owner) => owner.body).ToArray()); } catch (Exception ex) { Log.Warning("Could not read " + assembly.GetName().Name + "'s code for skill overrides: " + ex.Message); continue; } foreach (OverrideCallScanner.Found swap in source.Where((OverrideCallScanner.Found found) => IsCandidate(found.skill))) { (Object.op_Implicit((Object)(object)swap.body) ? list.FirstOrDefault((ModdedSurvivor survivor) => (Object)(object)survivor.body == (Object)(object)swap.body) : ((list.Count == 1) ? list[0] : Owner(swap.skill, list)))?.AddUnlinked(swap.skill, swap.slot); } } foreach (ModdedSurvivor value in survivors.Values) { MonoBehaviour[] componentsInChildren = value.body.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val2) || val2 is GenericSkill) { continue; } foreach (var (skill, slot) in from entry in SkillsIn(val2) where IsCandidate(entry.skill) select entry) { value.AddUnlinked(skill, slot); } } } Log.Info($"Searched {survivors.Count} modded survivor(s) for extra skills; found {survivors.Values.Sum((ModdedSurvivor survivor) => survivor.unlinked.Count)} outside their loadout states."); } private static ModdedSurvivor Describe(SurvivorDef survivorDef, BodyIndex bodyIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(bodyIndex); CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex); Type[] array = (from variant in (BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex) ?? Array.Empty<GenericSkill>()).Where((GenericSkill slot) => Object.op_Implicit((Object)(object)slot) && Object.op_Implicit((Object)(object)slot.skillFamily)).SelectMany((GenericSkill slot) => slot.skillFamily.variants) select (!Object.op_Implicit((Object)(object)variant.skillDef)) ? null : ((SerializableEntityStateType)(ref variant.skillDef.activationState)).stateType into type where type != null select type).ToArray(); IEnumerable<Type> second = from component in bodyPrefab.GetComponentsInChildren<MonoBehaviour>(true) where Object.op_Implicit((Object)(object)component) select ((object)component).GetType(); return new ModdedSurvivor { bodyIndex = bodyIndex, body = bodyPrefab, tokenStem = (TokenStem(Object.op_Implicit((Object)(object)bodyPrefabBodyComponent) ? bodyPrefabBodyComponent.baseNameToken : null) ?? TokenStem(survivorDef.displayNameToken)), stateNamespaces = new HashSet<string>(from type in array select type.Namespace into name where !string.IsNullOrEmpty(name) select name), assemblies = new HashSet<Assembly>((from type in array.Concat(second) select type.Assembly).Where(IsModCode)) }; } private static bool IsCandidate(SkillDef skill) { if (!Object.op_Implicit((Object)(object)skill) || loadoutChoices.Contains(skill)) { return false; } string skillNameToken = skill.skillNameToken; if (!string.IsNullOrEmpty(skillNameToken)) { return Language.GetString(skillNameToken) != skillNameToken; } return false; } private static ModdedSurvivor Owner(SkillDef skill, List<ModdedSurvivor> candidates) { List<ModdedSurvivor> list = (from survivor in candidates where survivor.tokenStem != null && skill.skillNameToken.StartsWith(survivor.tokenStem, StringComparison.OrdinalIgnoreCase) orderby survivor.tokenStem.Length descending select survivor).ToList(); if (list.Count == 1 || (list.Count > 1 && list[0].tokenStem.Length > list[1].tokenStem.Length)) { return list[0]; } string stateNamespace = ((SerializableEntityStateType)(ref skill.activationState)).stateType?.Namespace; List<ModdedSurvivor> list2 = ((stateNamespace == null) ? new List<ModdedSurvivor>() : candidates.Where((ModdedSurvivor survivor) => survivor.stateNamespaces.Contains(stateNamespace)).ToList()); if (list2.Count != 1) { return null; } return list2[0]; } private static string TokenStem(string token) { if (string.IsNullOrEmpty(token)) { return null; } int num = token.LastIndexOf("BODY", StringComparison.OrdinalIgnoreCase); if (num < 0) { num = token.LastIndexOf("NAME", StringComparison.OrdinalIgnoreCase); } if (num < 3) { return null; } return token.Substring(0, num); } private static SkillSlot SlotFromName(string name) { for (int i = 0; i < slotWords.Length; i++) { if (name.IndexOf(slotWords[i], StringComparison.OrdinalIgnoreCase) >= 0) { return (SkillSlot)(sbyte)i; } } return (SkillSlot)(-1); } private static bool IsVanilla(string identifier) { if (identifier != null && identifier.StartsWith("RoR2.", StringComparison.Ordinal)) { return identifier != "RoR2.LegacyModContent"; } return false; } private static bool IsModCode(Assembly assembly) { if (assembly.IsDynamic || assembly == typeof(ModdedExtraSkills).Assembly) { return false; } try { string location = assembly.Location; return !string.IsNullOrEmpty(location) && Path.GetFullPath(location).StartsWith(Path.GetFullPath(Paths.PluginPath), StringComparison.OrdinalIgnoreCase); } catch (NotSupportedException) { return false; } } private static (SkillDef skill, SkillSlot slot)[] SkillsNamedBy(Type stateType) { if (stateType == null) { return Array.Empty<(SkillDef, SkillSlot)>(); } if (skillsNamedByState.TryGetValue(stateType, out (SkillDef, SkillSlot)[] value)) { return value; } List<(SkillDef, SkillSlot)> list = new List<(SkillDef, SkillSlot)>(); try { List<FieldInfo> list2 = new List<FieldInfo>(); Type type = stateType; while (type != null && type != typeof(EntityState)) { list2.AddRange(from fieldInfo in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where OverrideCallScanner.HoldsSkills(fieldInfo.FieldType) select fieldInfo); type = type.BaseType; } EntityState val = (list2.Any((FieldInfo fieldInfo) => !fieldInfo.IsStatic) ? EntityStateCatalog.InstantiateState(stateType) : null); foreach (FieldInfo field in list2) { object value2 = (field.IsStatic ? field.GetValue(null) : ((val != null) ? field.GetValue(val) : null)); list.AddRange(from skill in Skills(value2) select (skill: skill, SlotFromName(field.Name))); } } catch (Exception ex) { Log.Debug("Could not read the skills " + stateType.FullName + " names: " + ex.Message); } (SkillDef, SkillSlot)[] array = list.Where(((SkillDef, SkillSlot) entry) => Object.op_Implicit((Object)(object)entry.Item1)).Distinct().ToArray(); skillsNamedByState[stateType] = array; return array; } private static IEnumerable<(SkillDef skill, SkillSlot slot)> SkillsIn(MonoBehaviour component) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) List<(SkillDef, SkillSlot)> list = new List<(SkillDef, SkillSlot)>(); try { Type type = ((object)component).GetType(); while (type != null && type != typeof(MonoBehaviour)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo field in fields) { if (OverrideCallScanner.HoldsSkills(field.FieldType)) { list.AddRange(from skill in Skills(field.GetValue(component)) select (skill: skill, SlotFromName(field.Name))); continue; } FieldInfo[] array = (from inner in DataType(field.FieldType)?.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where OverrideCallScanner.HoldsSkills(inner.FieldType) select inner).ToArray(); if (array == null || array.Length == 0) { continue; } object value = field.GetValue(component); IEnumerable enumerable3; if (!(value is IEnumerable enumerable)) { IEnumerable enumerable2 = new object[1] { value }; enumerable3 = enumerable2; } else { enumerable3 = enumerable; } foreach (object item in enumerable3) { if (item == null) { continue; } FieldInfo[] array2 = array; foreach (FieldInfo fieldInfo in array2) { SkillSlot slot = SlotFromName(fieldInfo.Name); list.AddRange(from skill in Skills(fieldInfo.GetValue(item)) select (skill: skill, ((int)slot != -1) ? slot : SlotFromName(field.Name))); } } } type = type.BaseType; } } catch (Exception ex) { Log.Debug("Could not read the skills " + ((object)component).GetType().FullName + " names: " + ex.Message); } return list; } private static Type DataType(Type type) { Type type2 = (type.IsArray ? type.GetElementType() : ((type.IsGenericType && typeof(IEnumerable).IsAssignableFrom(type)) ? ((type.GetGenericArguments().Length == 1) ? type.GetGenericArguments()[0] : null) : type)); if (type2 != null && !type2.IsPrimitive && !type2.IsEnum && type2 != typeof(string) && !typeof(Object).IsAssignableFrom(type2) && !typeof(Delegate).IsAssignableFrom(type2) && (type2.IsValueType || type2.IsClass)) { string? text = type2.Namespace; if (text == null || !text.StartsWith("System", StringComparison.Ordinal)) { string? text2 = type2.Namespace; if (text2 == null || !text2.StartsWith("UnityEngine", StringComparison.Ordinal)) { return type2; } } } return null; } private static IEnumerable<SkillDef> Skills(object value) { SkillDef val = (SkillDef)((value is SkillDef) ? value : null); if (val == null) { if (!(value is IEnumerable source)) { return Enumerable.Empty<SkillDef>(); } return source.OfType<SkillDef>(); } return (IEnumerable<SkillDef>)(object)new SkillDef[1] { val }; } } internal static class ModTokens { internal const string ExtraTab = "SUBSKILLSDISPLAY_TAB_EXTRA"; internal const string ExtraIntro = "SUBSKILLSDISPLAY_EXTRA_INTRO"; internal const string ExtraNone = "SUBSKILLSDISPLAY_EXTRA_NONE"; internal const string PauseAbilities = "SUBSKILLSDISPLAY_PAUSE_ABILITIES"; internal const string PauseIntro = "SUBSKILLSDISPLAY_PAUSE_INTRO"; internal const string PassiveLine = "SUBSKILLSDISPLAY_LINE_PASSIVE"; internal const string Back = "SUBMENU_BACK"; internal static void Register() { Language english = Language.english; if (english != null) { english.SetStringByToken("SUBSKILLSDISPLAY_TAB_EXTRA", "Extra Skills"); english.SetStringByToken("SUBSKILLSDISPLAY_EXTRA_INTRO", "<style=cSub>What this survivor's skills turn into during a run, in the line of the skill they replace. Hover one for details. Skills from choices you haven't unlocked are hidden.</style>"); english.SetStringByToken("SUBSKILLSDISPLAY_EXTRA_NONE", "<style=cSub>This survivor has no extra skills: everything it uses is on the Skills tab.</style>"); english.SetStringByToken("SUBSKILLSDISPLAY_PAUSE_ABILITIES", "Abilities"); english.SetStringByToken("SUBSKILLSDISPLAY_PAUSE_INTRO", "<style=cSub>Your skills, each followed by what it turns into during the run. Hover one for details.</style>"); english.SetStringByToken("SUBSKILLSDISPLAY_LINE_PASSIVE", "Passive"); } } } internal static class OverrideCallScanner { internal readonly struct Found { internal readonly SkillDef skill; internal readonly SkillSlot slot; internal readonly GameObject body; internal Found(SkillDef skill, SkillSlot slot, GameObject body) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) this.skill = skill; this.slot = slot; this.body = body; } } private const BindingFlags Declared = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static List<Found> Scan(Assembly assembly, GameObject[] bodies) { //IL_003a: 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_0046: Unknown result type (might be due to invalid IL or missing references) List<Found> list = new List<Found>(); ModuleDefinition val = ModuleDefinition.ReadModule(assembly.Location); try { foreach (SkillOverrideSites.Site item in SkillOverrideSites.Find(val)) { try { SkillSlot result; SkillSlot slot = (SkillSlot)((!Enum.TryParse<SkillSlot>(item.slot, out result)) ? (-1) : ((int)result)); Read(assembly, bodies, item.load, slot, list); } catch (Exception ex) { Log.Debug("Could not read a skill override in " + ((MemberReference)item.method).FullName + ": " + ex.Message); } } return list; } finally { ((IDisposable)val)?.Dispose(); } } private static void Read(Assembly assembly, GameObject[] bodies, Instruction load, SkillSlot slot, List<Found> found) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) OpCode opCode = load.OpCode; Code code = ((OpCode)(ref opCode)).Code; if ((int)code != 120) { if ((int)code == 123) { object operand = load.Operand; Add(ToReflection(assembly, (FieldReference)((operand is FieldReference) ? operand : null))?.GetValue(null), slot, null, found); return; } MethodInfo getter = default(MethodInfo); ref MethodInfo reference = ref getter; object operand2 = load.Operand; reference = ToReflection(assembly, (MethodReference)((operand2 is MethodReference) ? operand2 : null)); if (!(getter != null) || getter.GetParameters().Length != 0 || !HoldsSkills(getter.ReturnType)) { return; } if (getter.IsStatic) { Add(getter.Invoke(null, null), slot, null, found); return; } ReadFromInstances(assembly, bodies, getter.DeclaringType, (object instance) => getter.Invoke(instance, null), slot, found); return; } FieldInfo field = default(FieldInfo); ref FieldInfo reference2 = ref field; object operand3 = load.Operand; reference2 = ToReflection(assembly, (FieldReference)((operand3 is FieldReference) ? operand3 : null)); if (field != null) { ReadFromInstances(assembly, bodies, field.DeclaringType, (object instance) => field.GetValue(instance), slot, found); } } private static void ReadFromInstances(Assembly assembly, GameObject[] bodies, Type type, Func<object, object> read, SkillSlot slot, List<Found> found) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (typeof(EntityState).IsAssignableFrom(type)) { IEnumerable<Type> enumerable2; if (!type.IsAbstract) { IEnumerable<Type> enumerable = new Type[1] { type }; enumerable2 = enumerable; } else { enumerable2 = from candidate in assembly.GetTypes() where !candidate.IsAbstract && type.IsAssignableFrom(candidate) select candidate; } { foreach (Type item in enumerable2) { Add(read(EntityStateCatalog.InstantiateState(item)), slot, null, found); } return; } } if (!typeof(Component).IsAssignableFrom(type)) { return; } foreach (GameObject val in bodies) { Component[] componentsInChildren = val.GetComponentsInChildren(type, true); foreach (Component arg in componentsInChildren) { Add(read(arg), slot, val, found); } } } private static void Add(object value, SkillSlot slot, GameObject body, List<Found> found) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) SkillDef val = (SkillDef)((value is SkillDef) ? value : null); if (val != null) { found.Add(new Found(val, slot, body)); } else if (value is IEnumerable source) { found.AddRange(from item in source.OfType<SkillDef>() where Object.op_Implicit((Object)(object)item) select new Found(item, slot, body)); } } private static FieldInfo ToReflection(Assembly assembly, FieldReference field) { if (field != null) { return ToReflection(assembly, ((MemberReference)field).DeclaringType)?.GetField(((MemberReference)field).Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } return null; } private static MethodInfo ToReflection(Assembly assembly, MethodReference method) { return ((method == null) ? null : ToReflection(assembly, ((MemberReference)method).DeclaringType))?.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo candidate) => candidate.Name == ((MemberReference)method).Name && candidate.GetParameters().Length == method.Parameters.Count); } private static Type ToReflection(Assembly assembly, TypeReference type) { if (type == null || type.IsGenericInstance) { return null; } string name = ((MemberReference)type).FullName.Replace('/', '+'); return assembly.GetType(name) ?? (from candidate in AppDomain.CurrentDomain.GetAssemblies() select candidate.GetType(name)).FirstOrDefault((Type match) => match != null); } internal static bool HoldsSkills(Type type) { if (!typeof(SkillDef).IsAssignableFrom(type) && (!type.IsArray || !typeof(SkillDef).IsAssignableFrom(type.GetElementType()))) { if (type.IsGenericType && typeof(IEnumerable).IsAssignableFrom(type)) { return type.GetGenericArguments().Any(typeof(SkillDef).IsAssignableFrom); } return false; } return true; } } internal static class PauseAbilitiesPanel { private class AbilitiesButton : MonoBehaviour { internal GameObject buttonObject; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static hook_Awake <>9__9_0; public static hook_OnEnable <>9__9_1; public static Func<SkillDef, bool> <>9__13_1; public static Func<ExtraSkill, bool> <>9__13_2; internal void <Init>b__9_0(orig_Awake orig, PauseScreenController self) { orig.Invoke(self); AddButton(self); } internal void <Init>b__9_1(orig_OnEnable orig, PauseScreenController self) { orig.Invoke(self); AbilitiesButton component = ((Component)self).GetComponent<AbilitiesButton>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.buttonObject)) { GameObject buttonObject = component.buttonObject; int active; if (Object.op_Implicit((Object)(object)Run.instance) && Run.instance.isRunning) { LocalUser localUser = self.localUser; active = (Object.op_Implicit((Object)(object)((localUser != null) ? localUser.cachedMaster : null)) ? 1 : 0); } else { active = 0; } buttonObject.SetActive((byte)active != 0); } } internal bool <Lines>b__13_1(SkillDef skill) { return Object.op_Implicit((Object)(object)skill); } internal bool <Lines>b__13_2(ExtraSkill extra) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)extra.slot == -1; } } private const string CharacterSelectAddress = "RoR2/Base/UI/CharacterSelectUIMain.prefab"; private const string PanelName = "SubSkillsDisplayAbilitiesPanel"; private const float ColumnWidth = 640f; private const float HoverBoxWidth = 520f; private const float BackButtonWidth = 320f; private const float BackButtonHeight = 48f; private const int LayerPriority = 1005; private static CharacterSelectController template; private static UILayer layer; internal static void Init() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown object obj = <>c.<>9__9_0; if (obj == null) { hook_Awake val = delegate(orig_Awake orig, PauseScreenController self) { orig.Invoke(self); AddButton(self); }; <>c.<>9__9_0 = val; obj = (object)val; } PauseScreenController.Awake += (hook_Awake)obj; object obj2 = <>c.<>9__9_1; if (obj2 == null) { hook_OnEnable val2 = delegate(orig_OnEnable orig, PauseScreenController self) { orig.Invoke(self); AbilitiesButton component = ((Component)self).GetComponent<AbilitiesButton>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.buttonObject)) { GameObject buttonObject = component.buttonObject; int active; if (Object.op_Implicit((Object)(object)Run.instance) && Run.instance.isRunning) { LocalUser localUser = self.localUser; active = (Object.op_Implicit((Object)(object)((localUser != null) ? localUser.cachedMaster : null)) ? 1 : 0); } else { active = 0; } buttonObject.SetActive((byte)active != 0); } }; <>c.<>9__9_1 = val2; obj2 = (object)val2; } PauseScreenController.OnEnable += (hook_OnEnable)obj2; } private static void AddButton(PauseScreenController controller) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown GameObject inventoryButtonObject = controller.inventoryButtonObject; if (!Object.op_Implicit((Object)(object)inventoryButtonObject)) { Log.Warning("The pause menu has no Inventory button to put Abilities after; skipping it."); return; } ModTokens.Register(); GameObject val = Object.Instantiate<GameObject>(inventoryButtonObject, inventoryButtonObject.transform.parent, false); ((Object)val).name = "GenericMenuButton (Abilities)"; val.transform.SetSiblingIndex(inventoryButtonObject.transform.GetSiblingIndex() + 1); MPButton component = val.GetComponent<MPButton>(); ((Button)component).onClick = new ButtonClickedEvent(); ((UnityEvent)((Button)component).onClick).AddListener((UnityAction)delegate { Open(controller); }); LanguageTextMeshController component2 = val.GetComponent<LanguageTextMeshController>(); if (Object.op_Implicit((Object)(object)component2)) { component2.token = "SUBSKILLSDISPLAY_PAUSE_ABILITIES"; } ((Component)controller).gameObject.AddComponent<AbilitiesButton>().buttonObject = val; } private static void Open(PauseScreenController controller) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) LocalUser localUser = controller.localUser; CharacterMaster val = ((localUser != null) ? localUser.cachedMaster : null); if (!Object.op_Implicit((Object)(object)val)) { return; } CharacterBody body = val.GetBody(); Loadout val2 = null; SurvivorLoadout body2; BodyIndex val3; if (Object.op_Implicit((Object)(object)body)) { body2 = SurvivorLoadout.FromBody(body, localUser.userProfile); val3 = body.bodyIndex; } else { val3 = (BodyIndex)((!Object.op_Implicit((Object)(object)val.bodyPrefab)) ? (-1) : ((int)BodyCatalog.FindBodyIndex(val.bodyPrefab))); val2 = Loadout.RequestInstance(); UserProfile userProfile = localUser.userProfile; if (userProfile != null) { userProfile.CopyLoadout(val2); } body2 = SurvivorLoadout.FromLoadout(val3, val2, localUser.userProfile); } try { List<SkillLine> lines = Lines(body2, ExtraSkillCatalog.For(body2, includeOtherLoadouts: false)); CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(val3); string title = (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent) ? Language.GetString(bodyPrefabBodyComponent.baseNameToken) : string.Empty); Color color = (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent) ? bodyPrefabBodyComponent.bodyColor : Color.white); GameObject val4 = Build(controller, title, color, lines); if (Object.op_Implicit((Object)(object)val4)) { Object.Destroy((Object)(object)controller.submenuObject); controller.submenuObject = val4; ((Component)controller.pausePanel).gameObject.SetActive(false); ((Component)controller.gameMenuPanel).gameObject.SetActive(true); ((Component)controller.mainPanel).gameObject.SetActive(false); val4.SetActive(true); UILayerKey component = val4.GetComponent<UILayerKey>(); if (!Object.op_Implicit((Object)(object)component._eventSystem)) { component._eventSystem = val4.GetComponent<MPEventSystemLocator>().eventSystem; } } } catch (Exception arg) { Log.Error($"Could not open the Abilities panel: {arg}"); Transform val5 = ((Transform)controller.rootPanel).Find("SubSkillsDisplayAbilitiesPanel"); if (Object.op_Implicit((Object)(object)val5) && (Object)(object)((Component)val5).gameObject != (Object)(object)controller.submenuObject) { Object.Destroy((Object)(object)((Component)val5).gameObject); } } finally { if (val2 != null) { Loadout.ReturnInstance(val2); } } } private static List<SkillLine> Lines(SurvivorLoadout body, List<ExtraSkill> extras) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) List<SkillLine> list = new List<SkillLine>(); if (!body.IsValid) { return list; } SkillLine skillLine = new SkillLine("SUBSKILLSDISPLAY_LINE_PASSIVE"); if (body.skillLocator.passiveSkill.enabled) { skillLine.entries.Add(SkillEntry.Of(body.skillLocator.passiveSkill)); } skillLine.entries.AddRange((from skill in body.slots.Where((GenericSkill slot) => !slot.hideInCharacterSelect && (int)body.KindOf(slot) == -1).Select(body.Selected) where Object.op_Implicit((Object)(object)skill) select skill).Select(SkillEntry.Of)); if (skillLine.entries.Count > 0) { list.Add(skillLine); } SkillSlot[] array = new SkillSlot[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); SkillSlot[] array2 = (SkillSlot[])(object)array; foreach (SkillSlot kind in array2) { SkillLine skillLine2 = new SkillLine(SkillLine.TitleFor(kind)); SkillDef val = body.Selected(kind); if (Object.op_Implicit((Object)(object)val)) { skillLine2.entries.Add(SkillEntry.Of(val)); } skillLine2.entries.AddRange(extras.Where((ExtraSkill extra) => extra.slot == kind).Select(SkillEntry.Of)); if (skillLine2.entries.Count > 0) { list.Add(skillLine2); } } list.AddRange(SkillLine.FromExtras(extras.Where((ExtraSkill extra) => (int)extra.slot == -1))); return list; } private static GameObject Build(PauseScreenController controller, string title, Color color, List<SkillLine> lines) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Expected O, but got Unknown //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) CharacterSelectController val = Template(); RectTransform val2 = (Object.op_Implicit((Object)(object)val) ? val.skillStripContainer : null); if (!Object.op_Implicit((Object)(object)val2)) { Log.Warning("Could not load character select's skill strips; the Abilities panel can't be shown."); return null; } GameObject root = new GameObject("SubSkillsDisplayAbilitiesPanel", new Type[1] { typeof(RectTransform) }); root.SetActive(false); root.transform.SetParent((Transform)(object)controller.rootPanel, false); RectTransform val3 = (RectTransform)root.transform; Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 0.5f); val3.pivot = val4; Vector2 anchorMin = (val3.anchorMax = val4); val3.anchorMin = anchorMin; val3.anchoredPosition = Vector2.zero; Transform val6 = (Object.op_Implicit((Object)(object)val.survivorName) ? ((TMP_Text)val.survivorName).transform.parent : null); Image val7 = ((Object.op_Implicit((Object)(object)val6) && Object.op_Implicit((Object)(object)val6.parent)) ? ((Component)val6.parent).GetComponent<Image>() : null); if (Object.op_Implicit((Object)(object)val7)) { Image obj = root.AddComponent<Image>(); obj.sprite = val7.sprite; obj.type = val7.type; ((Graphic)obj).color = ((Graphic)val7).color; ((Graphic)obj).material = ((Graphic)val7).material; obj.pixelsPerUnitMultiplier = val7.pixelsPerUnitMultiplier; } VerticalLayoutGroup obj2 = root.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj2).padding = new RectOffset(6, 6, 6, 6); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 6f; ((LayoutGroup)obj2).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; ContentSizeFitter obj3 = root.AddComponent<ContentSizeFitter>(); obj3.horizontalFit = (FitMode)2; obj3.verticalFit = (FitMode)2; UILayerKey val8 = root.AddComponent<UILayerKey>(); val8.layer = Layer(); val8.onBeginRepresentTopLayer = new UnityEvent(); val8.onEndRepresentTopLayer = new UnityEvent(); HGGamepadInputEvent obj4 = root.AddComponent<HGGamepadInputEvent>(); obj4.actionName = "UICancel"; obj4.requiredTopLayer = val8; obj4.enabledObjectsIfActive = Array.Empty<GameObject>(); obj4.actionEvent = new UnityEvent(); obj4.actionEvent.AddListener((UnityAction)delegate { Object.Destroy((Object)(object)root); }); if (Object.op_Implicit((Object)(object)val6)) { GameObject val9 = Object.Instantiate<GameObject>(((Component)val6).gameObject, root.transform, false); TMP_Text val10 = UiHierarchy.Counterpart<TMP_Text>(val6, val9.transform, (TMP_Text)(object)val.survivorName); if (Object.op_Implicit((Object)(object)val10)) { val10.SetText(title, true); ((Graphic)val10).color = color; } } GameObject val11 = Object.Instantiate<GameObject>(((Component)val2).gameObject, root.transform, false); ((Object)val11).name = "SkillLines"; VerticalLayoutGroup component = val11.GetComponent<VerticalLayoutGroup>(); if (Object.op_Implicit((Object)(object)component)) { ((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false; } GameObject val12 = UiHierarchy.Counterpart((Transform)(object)val2, val11.transform, val.skillStripPrefab); HGButton val13 = (Object.op_Implicit((Object)(object)val12) ? val12.GetComponent<HGButton>() : null); object obj5; if (!Object.op_Implicit((Object)(object)val12)) { obj5 = null; } else { Transform obj6 = val12.transform.Find("Inner/SkillDescriptionPanel/SkillDescription"); obj5 = ((obj6 != null) ? ((Component)obj6).GetComponent<TMP_Text>() : null); } TMP_Text val14 = (TMP_Text)obj5; if (Object.op_Implicit((Object)(object)val14)) { UiHierarchy.AddText(val14, root.transform, "Intro", 640f).SetText(Language.GetString("SUBSKILLSDISPLAY_PAUSE_INTRO"), true); val11.transform.SetAsLastSibling(); } LanguageTextMeshController val15 = (Object.op_Implicit((Object)(object)val13) ? val13.hoverLanguageTextMeshController : null); SkillLines.Build((RectTransform)val11.transform, lines, color, val15, val8); float num = (Object.op_Implicit((Object)(object)component) ? ((float)((LayoutGroup)component).padding.vertical) : 0f); float num2 = (Object.op_Implicit((Object)(object)component) ? ((HorizontalOrVerticalLayoutGroup)component).spacing : 0f); LayoutElement obj7 = LayoutElementOf(val11); float minWidth = (obj7.preferredWidth = 640f); obj7.minWidth = minWidth; minWidth = (obj7.preferredHeight = num + (float)Mathf.Max(1, lines.Count) * 96f + (float)Mathf.Max(0, lines.Count - 1) * num2); obj7.minHeight = minWidth; Transform val16 = (Object.op_Implicit((Object)(object)val15) ? ((Component)val15).transform : null); while (Object.op_Implicit((Object)(object)val16) && (Object)(object)val16.parent != (Object)(object)val11.transform) { val16 = val16.parent; } RectTransform val17 = (RectTransform)(object)((val16 is RectTransform) ? val16 : null); if (val17 != null) { val17.sizeDelta = new Vector2(520f, val17.sizeDelta.y); } AddBackButton(controller, root); MPButton[] componentsInChildren = root.GetComponentsInChildren<MPButton>(true); for (int num5 = 0; num5 < componentsInChildren.Length; num5++) { componentsInChildren[num5].requiredTopLayer = val8; } return root; } private static void AddBackButton(PauseScreenController controller, GameObject root) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown AbilitiesButton component = ((Component)controller).GetComponent<AbilitiesButton>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.buttonObject)) { GameObject val = new GameObject("BackRow", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(root.transform, false); HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)obj).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; GameObject obj2 = Object.Instantiate<GameObject>(component.buttonObject, val.transform, false); ((Object)obj2).name = "GenericMenuButton (Back)"; obj2.SetActive(true); LayoutElement obj3 = LayoutElementOf(obj2); obj3.preferredWidth = 320f; obj3.preferredHeight = 48f; MPButton component2 = obj2.GetComponent<MPButton>(); ((Button)component2).onClick = new ButtonClickedEvent(); ((UnityEvent)((Button)component2).onClick).AddListener((UnityAction)delegate { Object.Destroy((Object)(object)root); }); component2.defaultFallbackButton = true; LanguageTextMeshController component3 = obj2.GetComponent<LanguageTextMeshController>(); if (Object.op_Implicit((Object)(object)component3)) { component3.token = "SUBMENU_BACK"; } } } private static LayoutElement LayoutElementOf(GameObject gameObject) { LayoutElement component = gameObject.GetComponent<LayoutElement>(); if (!Object.op_Implicit((Object)(object)component)) { return gameObject.AddComponent<LayoutElement>(); } return component; } private static CharacterSelectController Template() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)template)) { return template; } AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/UI/CharacterSelectUIMain.prefab"); GameObject val2 = val.WaitForCompletion(); template = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<CharacterSelectController>() : null); if (!Object.op_Implicit((Object)(object)template)) { Log.Error(string.Format("Could not load {0} ({1}): {2}", "RoR2/Base/UI/CharacterSelectUIMain.prefab", val.Status, val.OperationException?.Message ?? "no character select controller on it")); } return template; } private static UILayer Layer() { if (!Object.op_Implicit((Object)(object)layer)) { layer = ScriptableObject.CreateInstance<UILayer>(); ((Object)layer).name = "uilSubSkillsDisplayAbilities"; layer.priority = 1005; ((Object)layer).hideFlags = (HideFlags)32; } return layer; } } internal readonly struct SkillEntry { internal readonly Sprite icon; private readonly string nameToken; private readonly string sourceToken; private readonly string descriptionToken; private readonly string[] keywordTokens; private static readonly Regex keywordTitle = new Regex("<style=cKeywordName>.*?</style>", RegexOptions.Singleline); private static readonly Regex subduedBody = new Regex("^<style=cSub>(.*)</style>$", RegexOptions.Singleline); internal string Title { get { string text = Language.GetString(nameToken); string text2 = (string.IsNullOrEmpty(sourceToken) ? null : Language.GetString(sourceToken)); if (!string.IsNullOrEmpty(text2) && !(text2 == text)) { return text + " (" + text2 + ")"; } return text; } } internal string Description { get { string text = keywordTitle.Replace(Language.GetString(descriptionToken), string.Empty).Trim(); Match match = subduedBody.Match(text); if (!match.Success) { return text; } return match.Groups[1].Value; } } private SkillEntry(Sprite icon, string nameToken, string sourceToken, string descriptionToken, string[] keywordTokens) { this.icon = icon; this.nameToken = nameToken; this.sourceToken = sourceToken; this.descriptionToken = descriptionToken; this.keywordTokens = keywordTokens; } internal static SkillEntry Of(SkillDef skill) { return new SkillEntry(skill.icon, skill.skillNameToken, null, skill.skillDescriptionToken, skill.keywordTokens); } internal static SkillEntry Of(ExtraSkill extra) { return new SkillEntry(extra.skill.icon, extra.skill.skillNameToken, extra.sourceToken, extra.descriptionToken, extra.skill.keywordTokens); } internal static SkillEntry Of(PassiveSkill passive) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) return new SkillEntry(passive.icon, passive.skillNameToken, null, passive.skillDescriptionToken, string.IsNullOrEmpty(passive.keywordToken) ? null : new string[1] { passive.keywordToken }); } internal string HoverText(Color color) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) string description = Description; color.a = 0.2f; string stringFormatted = Language.GetStringFormatted("LOGBOOK_HOVER_DESCRIPTION_FORMAT", new object[3] { Title, description, ColorUtility.ToHtmlStringRGBA(color) }); string[] array = ((IEnumerable<string>)Keywords.For(keywordTokens, description)).Select((Func<string, string>)Language.GetString).ToArray(); if (array.Length != 0) { return stringFormatted + "\n\n" + string.Join("\n\n", array); } return stringFormatted; } } internal sealed class SkillLine { internal readonly string titleToken; internal readonly List<SkillEntry> entries = new List<SkillEntry>(); internal const string MiscTitleToken = "LOADOUT_SKILL_MISC"; internal SkillLine(string titleToken) { this.titleToken = titleToken; } internal static string TitleFor(SkillSlot slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown return (int)slot switch { 0 => "LOADOUT_SKILL_PRIMARY", 1 => "LOADOUT_SKILL_SECONDARY", 2 => "LOADOUT_SKILL_UTILITY", 3 => "LOADOUT_SKILL_SPECIAL", _ => "LOADOUT_SKILL_MISC", }; } internal static List<SkillLine> FromExtras(IEnumerable<ExtraSkill> extras) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 //IL_0080: Unknown result type (might be due to invalid IL or missing references) List<SkillLine> list = new List<SkillLine>(); foreach (IGrouping<string, ExtraSkill> item in from extra in extras group extra by extra.LineKey into @group orderby Order(@group.First().slot) select @group) { ExtraSkill extraSkill = item.First(); SkillLine skillLine = new SkillLine(((int)extraSkill.slot != -1) ? TitleFor(extraSkill.slot) : (extraSkill.lineToken ?? "LOADOUT_SKILL_MISC")); skillLine.entries.AddRange(item.Select(SkillEntry.Of)); list.Add(skillLine); } return list; } private static int Order(SkillSlot slot) { //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: Expected I4, but got Unknown if ((int)slot != -1) { return (int)slot; } return 4; } } internal static class SkillLines { internal const float LineHeight = 96f; internal static List<GameObject> Build(RectTransform container, IEnumerable<SkillLine> lines, Color color, LanguageTextMeshController hoverText, UILayerKey requiredTopLayer) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = new List<GameObject>(); GameObject rowPrefab = LoadoutPanelController.rowPrefab; GameObject loadoutButtonPrefab = LoadoutPanelController.loadoutButtonPrefab; if (!Object.op_Implicit((Object)(object)rowPrefab) || !Object.op_Implicit((Object)(object)loadoutButtonPrefab)) { Log.Warning("The Loadout tab's row prefabs aren't loaded; skill lines can't be shown."); return list; } foreach (SkillLine line in lines) { GameObject val = Object.Instantiate<GameObject>(rowPrefab, (Transform)(object)container, false); ((Object)val).name = "SkillLine"; list.Add(val); Transform val2 = val.transform.Find("ButtonSelectionHighlight, Checkbox"); if (Object.op_Implicit((Object)(object)val2)) { Object.Destroy((Object)(object)((Component)val2).gameObject); } Transform val3 = val.transform.Find("SlotLabel"); if (Object.op_Implicit((Object)(object)val3)) { LanguageTextMeshController component = ((Component)val3).GetComponent<LanguageTextMeshController>(); if (Object.op_Implicit((Object)(object)component)) { component.token = line.titleToken; } HGTextMeshProUGUI component2 = ((Component)val3).GetComponent<HGTextMeshProUGUI>(); if (Object.op_Implicit((Object)(object)component2)) { ((Graphic)component2).color = color; } } Transform val4 = val.transform.Find("ButtonContainer") ?? val.transform; foreach (SkillEntry entry in line.entries) { AddButton(loadoutButtonPrefab, val4, entry, color, hoverText, requiredTopLayer); } Transform obj = val4.Find("Spacer"); if (obj != null) { obj.SetAsLastSibling(); } } return list; } private static void AddButton(GameObject buttonPrefab, Transform parent, SkillEntry entry, Color color, LanguageTextMeshController hoverText, UILayerKey requiredTopLayer) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(buttonPrefab, parent, false); HGButton component = val.GetComponent<HGButton>(); if (Object.op_Implicit((Object)(object)component)) { Graphic targetGraphic = ((Selectable)component).targetGraphic; Image val2 = (Image)(object)((targetGraphic is Image) ? targetGraphic : null); if (val2 != null) { val2.sprite = entry.icon; } component.updateTextOnHover = true; component.hoverLanguageTextMeshController = hoverText; component.hoverToken = entry.HoverText(color); ((MPButton)component).requiredTopLayer = requiredTopLayer; ((Selectable)component).interactable = true; ((MPButton)component).disablePointerClick = true; ((MPButton)component).disableGamepadClick = true; ColorBlock colors = ((Selectable)component).colors; ((ColorBlock)(ref colors)).colorMultiplier = 1f; ((Selectable)component).colors = colors; TooltipProvider component2 = val.GetComponent<TooltipProvider>(); if (Object.op_Implicit((Object)(object)component2)) { Object.Destroy((Object)(object)component2); } } } } internal static class SkillOverrideSites { internal readonly struct Site { internal readonly MethodDefinition method; internal readonly Instruction load; internal readonly string slot; internal Site(MethodDefinition method, Instruction load, string slot) { this.method = method; this.load = load; this.slot = slot; } } private static readonly Dictionary<string, string> overrideHolderFields = new Dictionary<string, string> { ["EntityStates.SkillStateOverrideData::primarySkillOverride"] = "Primary", ["EntityStates.SkillStateOverrideData::secondarySkillOverride"] = "Secondary", ["EntityStates.SkillStateOverrideData::utilitySkillOverride"] = "Utility", ["EntityStates.SkillStateOverrideData::specialSkillOverride"] = "Special", ["RoR2.SkillTransformationController/SkillDefRelationship::overrideSkillDef"] = null }; private static readonly string[] slotNames = new string[4] { "Primary", "Secondary", "Utility", "Special" }; private const int MaximumWrapperDepth = 2; internal static List<Site> Find(ModuleDefinition module) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Invalid comparison between Unknown and I4 List<MethodDefinition> list = (from method in module.GetTypes().SelectMany((TypeDefinition type) => (IEnumerable<MethodDefinition>)type.Methods) where method.HasBody select method).ToList(); Dictionary<MethodDefinition, List<(MethodDefinition, Instruction)>> dictionary = new Dictionary<MethodDefinition, List<(MethodDefinition, Instruction)>>(); foreach (MethodDefinition item in list) { Enumerator<Instruction> enumerator2 = item.Body.Instructions.GetEnumerator(); try { while (enumerator2.MoveNext()) { Instruction current2 = enumerator2.Current; if (!IsCall(current2)) { continue; } object operand = current2.Operand; MethodDefinition val = (MethodDefinition)((operand is MethodDefinition) ? operand : null); if (val != null) { if (!dictionary.TryGetValue(val, out var value)) { value = (dictionary[val] = new List<(MethodDefinition, Instruction)>()); } value.Add((item, current2)); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } List<Site> list3 = new List<Site>(); foreach (MethodDefinition item2 in list) { Enumerator<Instruction> enumerator2 = item2.Body.Instructions.GetEnumerator(); try { while (enumerator2.MoveNext()) { Instruction current4 = enumerator2.Current; if (IsCall(current4)) { object operand2 = current4.Operand; MethodReference val2 = (MethodReference)((operand2 is MethodReference) ? operand2 : null); if (val2 != null && ((MemberReference)val2).Name == "SetSkillOverride" && ((MemberReference)((MemberReference)val2).DeclaringType).FullName == "RoR2.GenericSkill") { Follow(item2, current4, 1, 3, null, dictionary, 0, list3); continue; } } OpCode opCode = current4.OpCode; if ((int)((OpCode)(ref opCode)).Code == 122) { object operand3 = current4.Operand; FieldReference val3 = (FieldReference)((operand3 is FieldReference) ? operand3 : null); if (val3 != null && overrideHolderFields.TryGetValue(((MemberReference)((MemberReference)val3).DeclaringType).FullName + "::" + ((MemberReference)val3).Name, out var value2)) { Follow(item2, current4, 0, -1, value2, dictionary, 0, list3); } } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } return (from site in list3 group site by (method: site.method, load: site.load) into @group select @group.First()).ToList(); } private static void Follow(MethodDefinition method, Instruction consumer, int skillFromTop, int slotFromTop, string knownSlot, Dictionary<MethodDefinition, List<(MethodDefinition caller, Instruction call)>> callSites, int depth, List<Site> sites) { //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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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) //IL_0047: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 string text = knownSlot; int parameter = -1; if (text == null && slotFromTop >= 0) { text = SlotAt(method, consumer, slotFromTop, out parameter); } foreach (Instruction item in Producers(method, consumer, skillFromTop)) { OpCode opCode = item.OpCode; Code code = ((OpCode)(ref opCode)).Code; if ((int)code <= 110) { if ((int)code == 39 || (int)code == 110) { goto IL_006e; } } else { if ((int)code == 120 || (int)code == 123) { goto IL_006e; } if ((int)code == 151) { Fol