using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using ExpandedRoster.Bard; using ExpandedRoster.Bard.Ascendancies; using ExpandedRoster.Bard.Buffs; using ExpandedRoster.Bard.Skills; using ExpandedRoster.Druid; using ExpandedRoster.Druid.Ascendancies; using ExpandedRoster.Druid.Buffs; using ExpandedRoster.Druid.Skills; using ExpandedRoster.Monk; using ExpandedRoster.Monk.Ascendancies; using ExpandedRoster.Monk.Buffs; using ExpandedRoster.Monk.Skills; using ExpandedRoster.Necromancer; using ExpandedRoster.Necromancer.Ascendancies; using ExpandedRoster.Necromancer.Buffs; using ExpandedRoster.Necromancer.Skills; using HarmonyLib; using LootClicker.Entities; using LootClicker.Entities.Buffs; using LootClicker.Entities.Characters; using LootClicker.Entities.Monsters; using LootClicker.Entities.Skills; using LootClicker.Inventory; using LootClicker.Items; using LootClicker.Services; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ExpandedRoster")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ExpandedRoster")] [assembly: AssemblyTitle("ExpandedRoster")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 ExpandedRoster { public abstract class ModdedClassDef { public abstract CharacterClass ClassId { get; } public abstract SkillCategory Category { get; } public abstract string ClassName { get; } public abstract string ClassIconPath { get; } public abstract EquipmentID ClassRelicId { get; } public abstract EquipmentID[] AscendancyRelicIds { get; } public abstract AttributeStat[] ClassRelicAttributes { get; } public abstract AttributeStat[] AscendancyRelicAttributes { get; } public abstract AttributeStat[] AscendancyDefensiveAttributes { get; } public abstract Character CreateCharacter(); public abstract Skill[] CreateAllSkills(Character owner); public abstract Buff[] CreateAllBuffs(); public abstract AscendancyDef[] GetAscendancies(); public abstract void EquipStartingGear(Character character); public virtual CharacterPassive GetClassPassive(Character character) { return null; } public virtual CharacterPassive GetDamagePassive(Character character) { return null; } public abstract Skill[] CreateDefaultAttacks(Character owner); public abstract Skill[] CreateOffensiveCooldowns(Character owner); public abstract Skill[] CreateDefensiveCooldowns(Character owner); protected static void EquipWithDefaults(Character c, EquipableItem weapon, EquipableItem offhand = null, byte statMultiplier = 1) { if (weapon != null) { AddDefaultAttributes(weapon, statMultiplier); c.Equipment.EquipItem(weapon, true, (InventoryBase)null, -1, -1); } if (offhand != null) { AddDefaultAttributes(offhand, statMultiplier); c.Equipment.EquipItem(offhand, true, (InventoryBase)null, -1, -1); } } private static void AddDefaultAttributes(EquipableItem item, byte statMultiplier) { //IL_000b: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0034: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown item.Attributes.Clear(); HealthPoints val = new HealthPoints { Locked = true, MaxRank = 10 }; ((AttributeBase)val).SetValue(1, statMultiplier); item.Attributes.Add((AttributeBase)(object)val); Luck val2 = new Luck { Locked = true, MaxRank = 10 }; ((AttributeBase)val2).SetValue(1, statMultiplier); item.Attributes.Add((AttributeBase)(object)val2); } } public class AscendancyDef { public AscendancyClass Class; public string Name; public string IconPath; public Ascendancy Instance; public AscendancyPower Power; public string PowerTooltip; public bool PowerIsProc; } public class ClassButtonState { public Image Panel; public Button ButtonComponent; public bool Initialized; } public static class ClassRegistry { public static readonly List All = new List(); public static readonly Dictionary ByClassId = new Dictionary(); public static readonly Dictionary ButtonStates = new Dictionary(); public static bool UIInitialized; public static void Register(ModdedClassDef def) { //IL_0006: 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_0054: 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_007e: Expected I4, but got Unknown if (ByClassId.ContainsKey(def.ClassId)) { Plugin.Log.LogWarning((object)("ClassRegistry: " + def.ClassName + " already registered, skipping.")); return; } All.Add(def); ByClassId[def.ClassId] = def; ButtonStates[def.ClassId] = new ClassButtonState(); Plugin.Log.LogInfo((object)$"ClassRegistry: Registered {def.ClassName} (ClassId={(int)def.ClassId})"); } public static ModdedClassDef Get(CharacterClass classId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ByClassId.TryGetValue(classId, out var value); return value; } public static bool IsModdedClass(CharacterClass classId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return ByClassId.ContainsKey(classId); } } [BepInPlugin("com.corga.expandedroster", "ExpandedRoster", "0.3.0")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "com.corga.expandedroster"; public const string PluginName = "ExpandedRoster"; public const string PluginVersion = "0.3.0"; internal static ManualLogSource Log; internal static Harmony HarmonyInstance; internal static string DebugLogPath; private static string _altLog = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NecroRuntime.log"); private int _frameCount; internal static void DebugLog(string msg) { try { File.AppendAllText(DebugLogPath, msg + "\n"); } catch { } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)msg); } } private void Awake() { //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; DebugLogPath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "NecroDebug.log"); try { File.WriteAllText(DebugLogPath, $"=== ExpandedRoster Debug Log {DateTime.Now} ===\n"); } catch { } DebugLog("ExpandedRoster v0.3.0 loaded!"); DebugLog("Location: " + ((BaseUnityPlugin)this).Info.Location); ClassRegistry.Register(new NecromancerClassDef()); ClassRegistry.Register(new MonkClassDef()); ClassRegistry.Register(new DruidClassDef()); ClassRegistry.Register(new BardClassDef()); Assembly assembly = typeof(SkillStore).Assembly; DebugLog("Assembly-CSharp: " + assembly.FullName); MethodInfo methodInfo = AccessTools.Method(typeof(SkillStore), "SetupSkillStore", (Type[])null, (Type[])null); DebugLog($"SkillStore.SetupSkillStore: {methodInfo != null} -> {methodInfo}"); MethodInfo methodInfo2 = AccessTools.Method(typeof(CharacterCreationController), "SetupPanel", (Type[])null, (Type[])null); DebugLog($"CharacterCreationController.SetupPanel: {methodInfo2 != null} -> {methodInfo2}"); if (methodInfo != null) { MethodInfo method = typeof(Plugin).GetMethod("TestPostfix", BindingFlags.Static | BindingFlags.NonPublic); HarmonyInstance = new Harmony("com.corga.expandedroster"); HarmonyInstance.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); DebugLog("Manual test patch applied on SetupSkillStore"); } HarmonyInstance.PatchAll(); foreach (MethodBase patchedMethod in HarmonyInstance.GetPatchedMethods()) { DebugLog(" Patched: " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name); } if (methodInfo != null) { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo != null) { DebugLog($" SetupSkillStore postfixes: {patchInfo.Postfixes.Count}"); foreach (Patch postfix in patchInfo.Postfixes) { DebugLog(" - " + postfix.owner + ": " + postfix.PatchMethod.DeclaringType?.Name + "." + postfix.PatchMethod.Name); } } } DebugLog("Harmony patches applied."); } private void OnEnable() { try { File.AppendAllText(_altLog, $"[{DateTime.Now}] OnEnable\n"); } catch { } DebugLog("[LIFECYCLE] OnEnable"); } private void Start() { try { File.AppendAllText(_altLog, $"[{DateTime.Now}] Start\n"); } catch { } DebugLog("[LIFECYCLE] Start"); } private void Update() { _frameCount++; if (_frameCount <= 3 || _frameCount % 600 == 0) { string text = $"[{DateTime.Now}] Update frame={_frameCount}"; try { File.AppendAllText(_altLog, text + "\n"); } catch { } DebugLog(text); } } private void OnDisable() { try { File.AppendAllText(_altLog, $"[{DateTime.Now}] OnDisable\n"); } catch { } } private void OnDestroy() { try { File.AppendAllText(_altLog, $"[{DateTime.Now}] OnDestroy\n"); } catch { } } private static void TestPostfix() { try { File.AppendAllText(_altLog, $"[{DateTime.Now}] TestPostfix FIRED\n"); } catch { } try { File.AppendAllText(DebugLogPath, "[NECRO-TEST] MANUAL POSTFIX FIRED\n"); } catch { } } } public static class SpriteHelper { private static readonly Dictionary _cache = new Dictionary(); public static Sprite LoadEmbedded(string resourceName) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (_cache.TryGetValue(resourceName, out var value)) { return value; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = "ExpandedRoster." + resourceName + ".png"; using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { Plugin.DebugLog("[SpriteHelper] Embedded resource not found: " + text); return null; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Texture)val).filterMode = (FilterMode)1; if (!ImageConversion.LoadImage(val, array)) { Plugin.DebugLog("[SpriteHelper] Failed to decode image: " + text); return null; } Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)val2).name = resourceName; _cache[resourceName] = val2; return val2; } } } namespace ExpandedRoster.Patches { [HarmonyPatch(typeof(SkillStore), "SetupSkillStore")] public static class SkillStorePatch { [HarmonyPostfix] private static void Postfix() { //IL_0023: 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) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) Plugin.DebugLog("[MOD] SkillStore.SetupSkillStore postfix FIRED"); try { foreach (ModdedClassDef item in ClassRegistry.All) { SkillCategory category = item.Category; if (!SkillStore.SkillCategoryLookup.ContainsKey(category)) { SkillStore.SkillCategoryLookup[category] = new List(); } Skill[] array = item.CreateAllSkills(null); Skill[] array2 = array; foreach (Skill val in array2) { if (val != null) { SkillStore.SkillDatabase[val.ID] = val; SkillStore.SkillClassLookup[val.ID] = item.ClassId; SkillStore.SkillCategoryLookup[category].Add(val); SkillStore.SkillOrder.Add(val.ID); } } Plugin.Log.LogInfo((object)$"Registered {array.Length} {item.ClassName} skills."); } TextHelperPatches.ApplyIfNeeded(Plugin.HarmonyInstance); RelicPatches.ApplyIfNeeded(Plugin.HarmonyInstance); AscendancyPowerTooltipPatch.ApplyIfNeeded(Plugin.HarmonyInstance); WeaponTooltipConversionPatch.Apply(Plugin.HarmonyInstance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to register modded skills: {arg}"); } } } [HarmonyPatch(typeof(AscendancyStore), "SetupAscendancies")] public static class AscendancyStorePatch { [HarmonyPostfix] private static void Postfix() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) try { foreach (ModdedClassDef item in ClassRegistry.All) { Sprite value = Resources.Load(item.ClassIconPath); AscendancyStore.ClassIcons[item.ClassId] = value; AscendancyDef[] ascendancies = item.GetAscendancies(); foreach (AscendancyDef ascendancyDef in ascendancies) { AscendancyStore.AscendancyDatabase[ascendancyDef.Class] = ascendancyDef.Instance; AscendancyStore.AscendancyPowers[ascendancyDef.Class] = ascendancyDef.Power; AscendancyStore.AscendancyIcons[ascendancyDef.Class] = Resources.Load(ascendancyDef.IconPath); } Plugin.Log.LogInfo((object)("Registered " + item.ClassName + " ascendancies.")); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to register modded ascendancies: {arg}"); } } } [HarmonyPatch(typeof(Character), "SetupPassives")] public static class SetupPassivesPatch { [HarmonyPostfix] private static void Postfix(Character __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 if (__instance == null || __instance.Passives == null || !ClassRegistry.ByClassId.TryGetValue(__instance.Class, out var value)) { return; } CharacterPassive classPassive = value.GetClassPassive(__instance); if (classPassive != null) { __instance.Passives.Insert(3, classPassive); for (int i = 0; i < __instance.Passives.Count; i++) { ((Passive)__instance.Passives[i]).ID = (byte)(i + 1); } } CharacterPassive damagePassive = value.GetDamagePassive(__instance); if (damagePassive == null) { return; } for (int j = 0; j < __instance.Passives.Count; j++) { CharacterPassive val = __instance.Passives[j]; if (val.RequiredLevel == 20 && val.Attributes != null && val.Attributes.Length == 1 && (int)val.Attributes[0].Item1 == 10) { ((Passive)damagePassive).ID = (byte)(j + 1); __instance.Passives[j] = damagePassive; break; } } } } public static class AscendancyPowerTooltipPatch { private static bool _applied; public static void ApplyIfNeeded(Harmony harmony) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown if (!_applied) { _applied = true; MethodInfo methodInfo = AccessTools.Method(typeof(AscendancyStore), "GetAscendancyPowerTooltipText", (Type[])null, (Type[])null); MethodInfo method = typeof(AscendancyPowerTooltipPatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.DebugLog("[MOD] AscendancyPowerTooltipPatch applied (deferred)"); } } private static bool Prefix(AscendancyClass ascendancyClass, int multi, ref string __result) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) foreach (ModdedClassDef item in ClassRegistry.All) { AscendancyDef[] ascendancies = item.GetAscendancies(); foreach (AscendancyDef ascendancyDef in ascendancies) { if (ascendancyDef.Class == ascendancyClass && ascendancyDef.PowerTooltip != null) { StringBuilder stringBuilder = new StringBuilder(); string value = (ascendancyDef.PowerIsProc ? (TextHelper.AscensionTitle + " " + TextHelper.ProcTitle) : TextHelper.AscensionTitle); stringBuilder.AppendLine(value); stringBuilder.Append(ascendancyDef.PowerTooltip); __result = stringBuilder.ToString(); return false; } } } return true; } } [HarmonyPatch(typeof(BuffStore), "SetupBuffs")] public static class BuffStorePatch { [HarmonyPostfix] private static void Postfix() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) try { foreach (ModdedClassDef item in ClassRegistry.All) { Buff[] array = item.CreateAllBuffs(); Buff[] array2 = array; foreach (Buff val in array2) { if (val != null) { BuffStore.BuffDatabase[val.ID] = val; } } Plugin.Log.LogInfo((object)$"Registered {array.Length} {item.ClassName} buffs."); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to register modded buffs: {arg}"); } } } [HarmonyPatch(typeof(GameData), "AddNewCharacter")] public static class AddNewCharacterPatch { [HarmonyPrefix] private static void Prefix(Character characterToAdd) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ClassRegistry.Get(characterToAdd.Class)?.EquipStartingGear(characterToAdd); } } [HarmonyPatch(typeof(CharacterCreationController), "CreateCharacter")] public static class CreateCharacterPatch { [HarmonyPostfix] private static void Postfix(CharacterCreationController __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) try { Traverse val = Traverse.Create((object)__instance); ModdedClassDef moddedClassDef = ClassRegistry.Get(val.Property("CurrentClass", (object[])null).GetValue()); if (moddedClassDef == null || val.Property("CharacterEdit", (object[])null).GetValue()) { return; } TMP_InputField value = val.Field("CharacterNameInput").GetValue(); if (!((Object)(object)value == (Object)null) && !string.IsNullOrEmpty(value.text)) { Character val2 = moddedClassDef.CreateCharacter(); val2.UpdateName(value.text); Image value2 = val.Field("AvatarIcon").GetValue(); if (val.Property("CustomAvatar", (object[])null).GetValue()) { string value3 = val.Property("CustomAvatarName", (object[])null).GetValue(); val2.UpdateAvatar(value2.sprite, value3); } else { val2.UpdateAvatar(value2.sprite); } GameData.AddNewCharacter(val2); val.Method("CloseWindow", Array.Empty()).GetValue(); Plugin.Log.LogInfo((object)("Created new " + moddedClassDef.ClassName + " character.")); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to create modded character: {arg}"); } } } [HarmonyPatch] public static class LoadCharacterPatch { internal static int _pendingClassId = -1; [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(SaveFile), "LoadCharacter", (Type[])null, (Type[])null); } internal static Character CreateModdedCharacter() { ModdedClassDef moddedClassDef = ClassRegistry.Get((CharacterClass)_pendingClassId); if (moddedClassDef != null) { return moddedClassDef.CreateCharacter(); } Plugin.DebugLog($"[MOD] Unknown modded class ID {_pendingClassId}, falling back to first registered"); if (ClassRegistry.All.Count <= 0) { return null; } return ClassRegistry.All[0].CreateCharacter(); } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown List list = new List(instructions); ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(Paladin), (Type[])null, false); MethodInfo methodInfo = AccessTools.Method(typeof(LoadCharacterPatch), "CreateModdedCharacter", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(LoadCharacterPatch), "_pendingClassId"); if (constructorInfo == null || methodInfo == null) { Plugin.Log.LogError((object)"LoadCharacter transpiler: Could not find constructors/methods"); return list; } int num = -1; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Newobj && list[i].operand is ConstructorInfo constructorInfo2 && constructorInfo2 == constructorInfo) { num = i; break; } } if (num < 0) { Plugin.Log.LogError((object)"LoadCharacter transpiler: Could not find Paladin constructor"); return list; } int num2 = -1; for (int num3 = num - 1; num3 >= 0; num3--) { if (list[num3].opcode == OpCodes.Switch) { num2 = num3; break; } } if (num2 < 0) { Plugin.Log.LogError((object)"LoadCharacter transpiler: Could not find CharacterClass switch opcode"); return list; } bool flag = false; for (int num4 = num2 - 1; num4 >= Math.Max(0, num2 - 10); num4--) { if (list[num4].opcode == OpCodes.Call && list[num4].operand is MethodInfo methodInfo2 && methodInfo2.Name == "ReadByte") { list.Insert(num4 + 1, new CodeInstruction(OpCodes.Dup, (object)null)); list.Insert(num4 + 2, new CodeInstruction(OpCodes.Stsfld, (object)fieldInfo)); num2 += 2; num += 2; flag = true; Plugin.Log.LogInfo((object)"LoadCharacter transpiler: Inserted class ID capture"); break; } } if (!flag) { Plugin.Log.LogError((object)"LoadCharacter transpiler: Could not find ReadByte before switch"); return list; } int localIndex = GetLocalIndex(list[num + 1]); if (localIndex < 0) { Plugin.Log.LogError((object)"LoadCharacter transpiler: Could not determine character local index"); return list; } int index = num2 + 1; CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)methodInfo); CodeInstruction item = MakeStloc(localIndex); val.labels.AddRange(list[index].labels); list[index].labels.Clear(); list.Insert(index, item); list.Insert(index, val); Plugin.Log.LogInfo((object)"LoadCharacter transpiler: Injected factory as switch default case"); return list; } private static int GetLocalIndex(CodeInstruction instr) { if (instr.opcode == OpCodes.Stloc_0) { return 0; } if (instr.opcode == OpCodes.Stloc_1) { return 1; } if (instr.opcode == OpCodes.Stloc_2) { return 2; } if (instr.opcode == OpCodes.Stloc_3) { return 3; } if (instr.opcode == OpCodes.Stloc_S && instr.operand is LocalBuilder localBuilder) { return localBuilder.LocalIndex; } if (instr.opcode == OpCodes.Stloc_S) { object operand = instr.operand; if (operand is byte) { return (byte)operand; } } if (instr.opcode == OpCodes.Stloc && instr.operand is LocalBuilder localBuilder2) { return localBuilder2.LocalIndex; } if (instr.opcode == OpCodes.Stloc) { object operand = instr.operand; if (operand is int) { return (int)operand; } } return -1; } private static bool IsLdloc(CodeInstruction instr, int localIndex) { switch (localIndex) { case 0: return instr.opcode == OpCodes.Ldloc_0; case 1: return instr.opcode == OpCodes.Ldloc_1; case 2: return instr.opcode == OpCodes.Ldloc_2; case 3: return instr.opcode == OpCodes.Ldloc_3; default: if (instr.opcode == OpCodes.Ldloc_S || instr.opcode == OpCodes.Ldloc) { if (instr.operand is LocalBuilder localBuilder) { return localBuilder.LocalIndex == localIndex; } if (instr.operand is byte b) { return b == localIndex; } if (instr.operand is int num) { return num == localIndex; } } return false; } } private static CodeInstruction MakeStloc(int localIndex) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown return (CodeInstruction)(localIndex switch { 0 => (object)new CodeInstruction(OpCodes.Stloc_0, (object)null), 1 => (object)new CodeInstruction(OpCodes.Stloc_1, (object)null), 2 => (object)new CodeInstruction(OpCodes.Stloc_2, (object)null), 3 => (object)new CodeInstruction(OpCodes.Stloc_3, (object)null), _ => (object)new CodeInstruction(OpCodes.Stloc_S, (object)(byte)localIndex), }); } } [HarmonyPatch(typeof(AscendancySelectionController), "LoadCharacter")] public static class AscendancySelectionPatch { [HarmonyPostfix] private static void Postfix(AscendancySelectionController __instance, Character character) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_007d: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) if (character == null) { return; } ModdedClassDef moddedClassDef = ClassRegistry.Get(character.Class); if (moddedClassDef == null) { return; } try { AscendancyDef[] ascendancies = moddedClassDef.GetAscendancies(); if (ascendancies != null && ascendancies.Length >= 3) { Traverse obj = Traverse.Create((object)__instance); obj.Property("AscendancyClass1", (object[])null).SetValue((object)ascendancies[0].Class); obj.Property("AscendancyClass2", (object[])null).SetValue((object)ascendancies[1].Class); obj.Property("AscendancyClass3", (object[])null).SetValue((object)ascendancies[2].Class); TMP_Text value = obj.Field("AscendancyName1").GetValue(); TMP_Text value2 = obj.Field("AscendancyName2").GetValue(); TMP_Text value3 = obj.Field("AscendancyName3").GetValue(); Image value4 = obj.Field("AscendancyImage1").GetValue(); Image value5 = obj.Field("AscendancyImage2").GetValue(); Image value6 = obj.Field("AscendancyImage3").GetValue(); if ((Object)(object)value != (Object)null) { value.text = ascendancies[0].Name; } if ((Object)(object)value2 != (Object)null) { value2.text = ascendancies[1].Name; } if ((Object)(object)value3 != (Object)null) { value3.text = ascendancies[2].Name; } if ((Object)(object)value4 != (Object)null) { value4.sprite = AscendancyStore.GetIcon(ascendancies[0].Class); } if ((Object)(object)value5 != (Object)null) { value5.sprite = AscendancyStore.GetIcon(ascendancies[1].Class); } if ((Object)(object)value6 != (Object)null) { value6.sprite = AscendancyStore.GetIcon(ascendancies[2].Class); } obj.Method("SelectAscendancy", new Type[1] { typeof(AscendancyClass) }, (object[])null).GetValue(new object[1] { ascendancies[0].Class }); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to setup {moddedClassDef.ClassName} ascendancy selection: {arg}"); } } } [HarmonyPatch(typeof(CharacterCreationController), "LoadClassPreview")] public static class LoadClassPreviewPatch { [HarmonyPostfix] private static void Postfix(CharacterCreationController __instance, CharacterClass newClass) { //IL_0000: 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: 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_00fa: Unknown result type (might be due to invalid IL or missing references) ModdedClassDef moddedClassDef = ClassRegistry.Get(newClass); if (moddedClassDef == null) { return; } try { Traverse val = Traverse.Create((object)__instance); if (val.Property("CurrentClass", (object[])null).GetValue() != moddedClassDef.ClassId) { val.Property("CurrentClass", (object[])null).SetValue((object)moddedClassDef.ClassId); } Character testCharacter = GameData.TestCharacter; List value = val.Field("DefaultSkills").GetValue>(); Skill[] skills = moddedClassDef.CreateDefaultAttacks(testCharacter); LoadSkillPreview(value, skills); List value2 = val.Field("OffensiveSkills").GetValue>(); Skill[] skills2 = moddedClassDef.CreateOffensiveCooldowns(testCharacter); LoadSkillPreview(value2, skills2); List value3 = val.Field("DefensiveSkills").GetValue>(); Skill[] skills3 = moddedClassDef.CreateDefensiveCooldowns(testCharacter); LoadSkillPreview(value3, skills3); List value4 = val.Field("AscendancySkills").GetValue>(); AscendancyDef[] ascendancies = moddedClassDef.GetAscendancies(); if (value4 != null && ascendancies != null) { int num = Math.Min(ascendancies.Length, value4.Count); for (int i = 0; i < num; i++) { DisplaySkillController obj = value4[i]; if (obj != null) { obj.LoadAscendancy(ascendancies[i].Class, 1); } } } GameObject value5 = val.Field("ClassPreviewPanel").GetValue(); if ((Object)(object)value5 != (Object)null && !value5.activeSelf) { value5.SetActive(true); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to load {moddedClassDef.ClassName} class preview: {arg}"); } } private static void LoadSkillPreview(List controllers, Skill[] skills) { if (controllers == null || skills == null) { return; } int num = Math.Min(skills.Length, controllers.Count); for (int i = 0; i < num; i++) { DisplaySkillController obj = controllers[i]; if (obj != null) { obj.LoadSkill(skills[i], true); } } } } [HarmonyPatch(typeof(CharacterCreationController), "SetupPanel")] public static class SetupPanelPatch { [HarmonyPostfix] private static void Postfix(CharacterCreationController __instance) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018d: 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_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Expected O, but got Unknown //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) Plugin.DebugLog("[MOD] SetupPanel postfix FIRED"); if (ClassRegistry.UIInitialized) { return; } try { Image paladinPanel = __instance.PaladinPanel; if ((Object)(object)paladinPanel == (Object)null) { Plugin.DebugLog("[MOD] PaladinPanel is null, aborting"); return; } GameObject gameObject = ((Component)paladinPanel).gameObject; Transform parent = gameObject.transform.parent; RectTransform component = ((Component)__instance.WarriorPanel).GetComponent(); RectTransform component2 = ((Component)__instance.RangerPanel).GetComponent(); RectTransform component3 = ((Component)__instance.MagePanel).GetComponent(); RectTransform component4 = gameObject.GetComponent(); TMP_Text componentInChildren = ((Component)__instance.WarriorPanel).GetComponentInChildren(true); Plugin.DebugLog($"[MOD] Warrior pos={component.anchoredPosition} size={component.sizeDelta} pivot={component.pivot} anchor=({component.anchorMin},{component.anchorMax})"); Plugin.DebugLog($"[MOD] Ranger pos={component2.anchoredPosition} size={component2.sizeDelta}"); Plugin.DebugLog($"[MOD] Mage pos={component3.anchoredPosition} size={component3.sizeDelta}"); Plugin.DebugLog($"[MOD] Paladin pos={component4.anchoredPosition} size={component4.sizeDelta}"); float y = component.sizeDelta.y; float x = component.sizeDelta.x; float[] array = new float[4] { component.anchoredPosition.x, component2.anchoredPosition.x, component3.anchoredPosition.x, component4.anchoredPosition.x }; float num = 4f; int count = ClassRegistry.All.Count; int num2 = 4; int num3 = (count + num2 - 1) / num2; for (int i = 0; i < count; i++) { ModdedClassDef moddedClassDef = ClassRegistry.All[i]; ClassButtonState classButtonState = ClassRegistry.ButtonStates[moddedClassDef.ClassId]; if (!classButtonState.Initialized) { int num4 = i / num2; int num5 = i % num2; float num6 = component.anchoredPosition.y - (float)(num4 + 1) * (y + num); GameObject val = Object.Instantiate(gameObject, parent); ((Object)val).name = moddedClassDef.ClassName + "Button"; classButtonState.ButtonComponent = val.GetComponent