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 BenowyQol v0.3.1
BepInEx/plugins/BenowyQol/BenowyQol.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace BenowyQol; internal static class ClockTime { public static string Format(float dayFraction) { if (float.IsNaN(dayFraction) || float.IsInfinity(dayFraction)) { return "--:--"; } double num = (double)dayFraction - Math.Floor(dayFraction); int num2 = (int)Math.Floor(num * 1440.0); return (num2 / 60).ToString("00", CultureInfo.InvariantCulture) + ":" + (num2 % 60).ToString("00", CultureInfo.InvariantCulture); } } internal static class FoodFactorPolicy { public static float Apply(float nativeFactor, bool active) { if (!active || !(nativeFactor > 0f)) { return nativeFactor; } return 1f; } } internal abstract class QolFeature : IDisposable { private readonly ConfigEntry<bool> setting; private readonly ToggleState state; public string Title { get; private set; } public string Description { get; private set; } public string Status { get; protected set; } public bool Available { get; private set; } public bool Running { get; private set; } public bool Enabled => state.Enabled; protected QolFeature(ConfigFile config, string key, string title, string description) { Title = title; Description = description; setting = config.Bind<bool>("Features", key, true, description); state = new ToggleState(setting.Value, OnToggle); Available = true; Running = true; Status = ""; } public void SetEnabled(bool value) { if (Available && state.Set(value)) { setting.Value = value; } } public virtual void Initialize() { } public void Tick() { if (Available && Running && Enabled) { OnTick(); } } protected virtual void OnTick() { } protected virtual void OnToggle(bool next) { } public void Fail(Exception error) { Available = false; Status = "Unavailable: " + error.Message; Dispose(); } public void Dispose() { if (Running) { Running = false; OnStop(); } } protected virtual void OnStop() { } } internal sealed class FullFoodFeature : QolFeature { private const string Id = "benowy.qol.food"; private static FullFoodFeature instance; private Harmony harmony; public FullFoodFeature(ConfigFile config) : base(config, "FullDurationFood", "Full-duration food", "Personal: full food health, stamina and Eitr benefits until normal expiry. Changes apply on the next normal food tick; timers and regeneration stay normal.") { } public override void Initialize() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown instance = this; harmony = new Harmony("benowy.qol.food"); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "UpdateFood", new Type[2] { typeof(float), typeof(bool) }, (Type[])null); if (methodInfo == null) { throw new MissingMethodException("Player.UpdateFood changed."); } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FullFoodFeature), "RemoveDecay", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } private static float AdjustFactor(float nativeFactor, Player player) { bool active = instance != null && instance.Running && instance.Available && instance.Enabled && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer; return FoodFactorPolicy.Apply(nativeFactor, active); } private static IEnumerable<CodeInstruction> RemoveDecay(IEnumerable<CodeInstruction> instructions) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = -1; for (int i = 11; i + 25 < list.Count; i++) { if (MatchesDecay(list, i)) { if (num >= 0) { throw new InvalidOperationException("Multiple food-decay sites; refusing an ambiguous patch."); } num = i; } } if (num < 0) { throw new InvalidOperationException("Expected food-decay calculation not found; game or another food mod changed it."); } list.Insert(num + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(num + 2, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(FullFoodFeature), "AdjustFactor", (Type[])null, (Type[])null))); return list; } private static bool MatchesDecay(List<CodeInstruction> code, int i) { if (!Calls(code[i], typeof(Mathf), "Pow") || code[i - 1].opcode != OpCodes.Ldc_R4 || !(code[i - 1].operand is float) || (float)code[i - 1].operand != 0.3f || !Calls(code[i - 4], typeof(Mathf), "Clamp01") || code[i - 5].opcode != OpCodes.Div || !Field(code[i - 6], OpCodes.Ldfld, typeof(SharedData), "m_foodBurnTime") || !Field(code[i - 10], OpCodes.Ldfld, typeof(Food), "m_time")) { return false; } int num = Local(code[i + 1], store: true); if (num < 0 || Local(code[i - 3], store: true) != num || Local(code[i - 2], store: false) != num) { return false; } string[] array = new string[3] { "m_food", "m_foodStamina", "m_foodEitr" }; string[] array2 = new string[3] { "m_health", "m_stamina", "m_eitr" }; for (int j = 0; j < 3; j++) { int num2 = i + j * 8; if (!Field(code[num2 + 6], OpCodes.Ldfld, typeof(SharedData), array[j]) || Local(code[num2 + 7], store: false) != num || code[num2 + 8].opcode != OpCodes.Mul || !Field(code[num2 + 9], OpCodes.Stfld, typeof(Food), array2[j])) { return false; } } return true; } private static bool Calls(CodeInstruction instruction, Type type, string name) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (instruction.opcode == OpCodes.Call && methodInfo != null && methodInfo.DeclaringType == type) { return methodInfo.Name == name; } return false; } private static bool Field(CodeInstruction instruction, OpCode opcode, Type type, string name) { FieldInfo fieldInfo = instruction.operand as FieldInfo; if (instruction.opcode == opcode && fieldInfo != null && fieldInfo.DeclaringType == type) { return fieldInfo.Name == name; } return false; } private static int Local(CodeInstruction instruction, bool store) { OpCode opcode = instruction.opcode; if (opcode == (store ? OpCodes.Stloc_0 : OpCodes.Ldloc_0)) { return 0; } if (opcode == (store ? OpCodes.Stloc_1 : OpCodes.Ldloc_1)) { return 1; } if (opcode == (store ? OpCodes.Stloc_2 : OpCodes.Ldloc_2)) { return 2; } if (opcode == (store ? OpCodes.Stloc_3 : OpCodes.Ldloc_3)) { return 3; } if (opcode != (store ? OpCodes.Stloc : OpCodes.Ldloc) && opcode != (store ? OpCodes.Stloc_S : OpCodes.Ldloc_S)) { return -1; } if (!(instruction.operand is LocalBuilder localBuilder)) { return Convert.ToInt32(instruction.operand); } return localBuilder.LocalIndex; } protected override void OnStop() { if (harmony != null) { harmony.UnpatchSelf(); } if (instance == this) { instance = null; } } } internal sealed class InputGuard : IDisposable { private Harmony harmony; private static InputGuard current; private readonly MenuInputState state = new MenuInputState(); private KeyCode releaseKey; private static bool readingMenuInput; public bool Blocking => state.Blocking; private static bool Block { get { if (current != null && current.Blocking) { return !readingMenuInput; } return false; } } public void Install() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown current = this; harmony = new Harmony("benowy.qol.menu"); Patch(typeof(Player), "TakeInput", Type.EmptyTypes, "BlockBoolean"); Patch(typeof(PlayerController), "TakeInput", new Type[1] { typeof(bool) }, "BlockBoolean"); Patch(typeof(GameCamera), "UpdateMouseCapture", Type.EmptyTypes, "CaptureCursor"); string[] array = new string[3] { "GetButton", "GetButtonDown", "GetButtonUp" }; foreach (string method in array) { Patch(typeof(ZInput), method, new Type[1] { typeof(string) }, "BlockBoolean"); } string[] array2 = new string[3] { "GetMouseButton", "GetMouseButtonDown", "GetMouseButtonUp" }; foreach (string method2 in array2) { Patch(typeof(ZInput), method2, new Type[1] { typeof(int) }, "BlockBoolean"); } string[] array3 = new string[3] { "GetKey", "GetKeyDown", "GetKeyUp" }; foreach (string method3 in array3) { Patch(typeof(ZInput), method3, new Type[2] { typeof(KeyCode), typeof(bool) }, "BlockBoolean"); } string[] array4 = new string[4] { "GetJoyLeftStickX", "GetJoyLeftStickY", "GetJoyRightStickX", "GetJoyRightStickY" }; foreach (string method4 in array4) { Patch(typeof(ZInput), method4, new Type[1] { typeof(bool) }, "BlockFloat"); } string[] array5 = new string[3] { "GetMouseScrollWheel", "GetJoyLTrigger", "GetJoyRTrigger" }; foreach (string method5 in array5) { Patch(typeof(ZInput), method5, Type.EmptyTypes, "BlockFloat"); } Patch(typeof(ZInput), "GetMouseDelta", Type.EmptyTypes, "BlockVector"); } private void Patch(Type type, string method, Type[] args, string prefix) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, method, args, (Type[])null); if (methodInfo == null) { throw new MissingMethodException(type.Name, method); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(InputGuard), prefix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } public bool KeyDown(KeyCode key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) readingMenuInput = true; try { return ZInput.GetKeyDown(key, true); } finally { readingMenuInput = false; } } public void SetOpen(bool value, KeyCode key) { //IL_001b: 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) state.SetOpen(value, Time.unscaledTime); if (value) { Unlock(); return; } releaseKey = key; PlayerController.SetTakeInputDelay(0.2f); ZInput.IgnoreMouseInputForFrames(2); } public void Update() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (state.Open) { Unlock(); } else if (state.Blocking) { readingMenuInput = true; try { bool closingInputHeld = ZInput.GetKey(releaseKey, true) || ZInput.GetKey((KeyCode)27, true) || ZInput.GetMouseButton(0) || ZInput.GetMouseButton(1) || ZInput.GetMouseButton(2) || ZInput.GetButton("Attack") || ZInput.GetButton("SecondaryAttack") || ZInput.GetJoyLTrigger() > 0.2f || ZInput.GetJoyRTrigger() > 0.2f; state.Update(Time.unscaledTime, closingInputHeld); } finally { readingMenuInput = false; } } } private static void Unlock() { ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } private static bool CaptureCursor() { if (!Block) { return true; } Unlock(); return false; } private static bool BlockBoolean(ref bool __result) { if (!Block) { return true; } __result = false; return false; } private static bool BlockFloat(ref float __result) { if (!Block) { return true; } __result = 0f; return false; } private static bool BlockVector(ref Vector2 __result) { //IL_000a: 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) if (!Block) { return true; } __result = Vector2.zero; return false; } public void Dispose() { state.Reset(); if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } if (current == this) { current = null; } } } internal sealed class MenuInputState { private bool pending; private float releaseAfter; public bool Open { get; private set; } public bool Blocking { get { if (!Open) { return pending; } return true; } } public void SetOpen(bool value, float now) { Open = value; pending = !value; releaseAfter = now + 0.2f; } public void Update(float now, bool closingInputHeld) { if (!Open && pending && now >= releaseAfter && !closingInputHeld) { pending = false; } } public void Reset() { Open = false; pending = false; } } internal sealed class MinimapClockFeature : QolFeature { private TextMeshProUGUI label; private Minimap owner; public MinimapClockFeature(ConfigFile config) : base(config, "MinimapClock", "24-hour minimap clock", "Show Valheim's in-game time above the minimap (HH:mm).") { } protected override void OnTick() { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; if ((Object)(object)owner != (Object)(object)instance) { Clear(); } if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.m_smallRoot) || !Object.op_Implicit((Object)(object)instance.m_mapImageSmall) || !Object.op_Implicit((Object)(object)instance.m_biomeNameSmall)) { return; } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)EnvMan.instance) || !Object.op_Implicit((Object)(object)Hud.instance) || !Hud.instance.IsVisible() || !instance.m_smallRoot.activeInHierarchy) { if (Object.op_Implicit((Object)(object)label)) { ((Component)label).gameObject.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)label)) { owner = instance; GameObject val = new GameObject("BenowyQolClock", new Type[1] { typeof(RectTransform) }); val.SetActive(false); val.transform.SetParent(((Component)instance.m_mapImageSmall).transform, false); label = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)label).font = instance.m_biomeNameSmall.font; ((TMP_Text)label).fontSharedMaterial = instance.m_biomeNameSmall.fontSharedMaterial; ((TMP_Text)label).fontSize = 20f; ((TMP_Text)label).fontStyle = (FontStyles)1; ((Graphic)label).color = Color.white; ((TMP_Text)label).alignment = (TextAlignmentOptions)514; ((Graphic)label).raycastTarget = false; ((MaskableGraphic)label).maskable = false; ((TMP_Text)label).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)label).overflowMode = (TextOverflowModes)0; RectTransform rectTransform = ((TMP_Text)label).rectTransform; Vector2 anchorMin = (rectTransform.anchorMax = new Vector2(0.5f, 1f)); rectTransform.anchorMin = anchorMin; rectTransform.pivot = new Vector2(0.5f, 0f); rectTransform.sizeDelta = new Vector2(120f, 26f); rectTransform.anchoredPosition = new Vector2(0f, 4f); } bool flag = !((Component)label).gameObject.activeSelf; ((Component)label).gameObject.SetActive(true); ((TMP_Text)label).text = ClockTime.Format(EnvMan.instance.GetDayFraction()); if (flag) { label.canvasRenderer.cull = false; ((Graphic)label).SetAllDirty(); ((TMP_Text)label).ForceMeshUpdate(false, false); } } protected override void OnToggle(bool next) { if (next) { OnTick(); } else if (Object.op_Implicit((Object)(object)label)) { ((Component)label).gameObject.SetActive(false); } } protected override void OnStop() { Clear(); } private void Clear() { if (Object.op_Implicit((Object)(object)label)) { ((Component)label).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)label).gameObject); } label = null; owner = null; } } internal sealed class OrderedSummonsFeature : QolFeature { private sealed class Cursor { public ConfigEntry<int> Saved; public SummonCycleState State; } private sealed class Ticket { public long Caster; public int SelectedIndex; public GameObject Created; } private static OrderedSummonsFeature instance; private static readonly FieldInfo Owner = AccessTools.Field(typeof(SpawnAbility), "m_owner"); private static readonly FieldInfo Weapon = AccessTools.Field(typeof(SpawnAbility), "m_weapon"); private readonly ConfigFile config; private readonly Action<string> warn; private Harmony harmony; private readonly Dictionary<long, Cursor> cursors = new Dictionary<long, Cursor>(); private readonly Dictionary<SpawnAbility, Ticket> tickets = new Dictionary<SpawnAbility, Ticket>(); private readonly List<SpawnAbility> expired = new List<SpawnAbility>(); public OrderedSummonsFeature(ConfigFile config, Action<string> warn) : base(config, "OrderedSpiritSummons", "Ordered Spirit Caller summons", "Personal cast order: boar > wolf > bear > moose. Advances after a successful spawn; native caps/costs stay normal. Saves per character. In-flight casts finish their selected mode.") { this.config = config; this.warn = warn; } public override void Initialize() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown instance = this; if (Owner == null || Weapon == null) { throw new MissingFieldException("SpawnAbility caster/item fields changed."); } MethodInfo methodInfo = AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(SpawnAbility), "Spawn", (Type[])null, (Type[])null)); if (methodInfo == null) { throw new MissingMethodException("Spawn coroutine changed."); } harmony = new Harmony("benowy.qol.orderedspirits"); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(OrderedSummonsFeature), "PatchSpawn", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } private Cursor GetCursor(long id) { if (!cursors.TryGetValue(id, out var value)) { ConfigEntry<int> val = config.Bind<int>("SpiritCycle", "Character_" + id.ToString(CultureInfo.InvariantCulture), 0, "Next ordered spirit for this character: 0 boar, 1 wolf, 2 bear, 3 moose. Saved after successful ordered spawns; independent of world and army composition."); Cursor cursor = new Cursor(); cursor.Saved = val; cursor.State = new SummonCycleState(val.Value); value = cursor; cursors.Add(id, value); } return value; } private static bool Caster(SpawnAbility ability, out Player player) { player = null; if (!Object.op_Implicit((Object)(object)ability) || PrefabName(((Component)ability).gameObject) != "staff_SpiritCaller_spawn" || ability.m_minToSpawn != 1 || ability.m_maxToSpawn != 1) { return false; } object? value = Owner.GetValue(ability); player = (Player)((value is Player) ? value : null); object? value2 = Weapon.GetValue(ability); ItemData val = (ItemData)((value2 is ItemData) ? value2 : null); if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && player.GetPlayerID() != 0 && val != null && Object.op_Implicit((Object)(object)val.m_dropPrefab)) { return ((Object)val.m_dropPrefab).name == "StaffSpiritCaller"; } return false; } private static GameObject[] Prefabs(SpawnAbility ability) { if (ability.m_spawnPrefab == null || ability.m_spawnPrefab.Length != 4) { return null; } GameObject[] array = (GameObject[])(object)new GameObject[4]; GameObject[] spawnPrefab = ability.m_spawnPrefab; foreach (GameObject val in spawnPrefab) { if (!Object.op_Implicit((Object)(object)val)) { return null; } int num = Array.IndexOf(SummonCycleState.PrefabOrder, ((Object)val).name); if (num < 0 || Object.op_Implicit((Object)(object)array[num])) { return null; } array[num] = val; } return array; } private static string PrefabName(GameObject obj) { string name = ((Object)obj).name; if (!name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name; } return name.Substring(0, name.Length - 7); } private static GameObject Select(GameObject nativeRandom, SpawnAbility ability) { OrderedSummonsFeature orderedSummonsFeature = instance; if (orderedSummonsFeature == null || !orderedSummonsFeature.Running || !orderedSummonsFeature.Available) { return nativeRandom; } orderedSummonsFeature.Prune(); orderedSummonsFeature.tickets.Remove(ability); if (!orderedSummonsFeature.Enabled) { return nativeRandom; } try { if (!Caster(ability, out var player)) { return nativeRandom; } GameObject[] array = Prefabs(ability); if (array == null) { return nativeRandom; } long playerID = player.GetPlayerID(); int nextIndex = orderedSummonsFeature.GetCursor(playerID).State.NextIndex; orderedSummonsFeature.tickets[ability] = new Ticket { Caster = playerID, SelectedIndex = nextIndex }; return array[nextIndex]; } catch (Exception ex) { orderedSummonsFeature.warn("Ordered selection skipped: " + ex.Message); return nativeRandom; } } private static GameObject Create(GameObject selected, Vector3 position, Quaternion rotation, SpawnAbility ability, Vector3 target) { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) OrderedSummonsFeature orderedSummonsFeature = instance; Ticket value = null; GameObject val = selected; if (orderedSummonsFeature != null && orderedSummonsFeature.Running && orderedSummonsFeature.Available && orderedSummonsFeature.tickets.TryGetValue(ability, out value)) { try { GameObject[] array = Prefabs(ability); if (!Caster(ability, out var player) || player.GetPlayerID() != value.Caster || array == null) { orderedSummonsFeature.tickets.Remove(ability); value = null; } else { value.SelectedIndex = orderedSummonsFeature.GetCursor(value.Caster).State.NextIndex; val = array[value.SelectedIndex]; if (ability.m_maxSpawned > 0 && SpawnSystem.GetNrOfInstances(val, target, 0f, false, false) >= ability.m_maxSpawned) { orderedSummonsFeature.tickets.Remove(ability); ((Character)player).Message((MessageType)2, ability.m_maxSummonReached, 0, (Sprite)null, false); return null; } } } catch (Exception ex) { orderedSummonsFeature.tickets.Remove(ability); value = null; val = selected; orderedSummonsFeature.warn("Ordered spawn preparation skipped: " + ex.Message); } } GameObject val2 = Object.Instantiate<GameObject>(val, position, rotation); if (value != null) { value.Created = val2; } return val2; } private static void Commit(GameObject created, SpawnAbility ability) { OrderedSummonsFeature orderedSummonsFeature = instance; if (orderedSummonsFeature == null || !orderedSummonsFeature.tickets.TryGetValue(ability, out var value)) { return; } orderedSummonsFeature.tickets.Remove(ability); try { if (!Object.op_Implicit((Object)(object)created) || (Object)(object)created != (Object)(object)value.Created || !Object.op_Implicit((Object)(object)created.GetComponent<Character>()) || PrefabName(created) != SummonCycleState.PrefabOrder[value.SelectedIndex]) { return; } ZNetView component = created.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return; } Cursor cursor = orderedSummonsFeature.GetCursor(value.Caster); if (!cursor.State.Commit(value.SelectedIndex)) { orderedSummonsFeature.warn("Ordered cycle changed unexpectedly during spawn; cursor was not advanced."); return; } cursor.Saved.Value = cursor.State.NextIndex; try { orderedSummonsFeature.config.Save(); } catch (Exception ex) { orderedSummonsFeature.warn("Cycle advanced for this session, but could not save: " + ex.Message); } } catch (Exception ex2) { orderedSummonsFeature.warn("Could not record successful ordered spawn: " + ex2.Message); } } protected override void OnTick() { Prune(); } private void Prune() { expired.Clear(); foreach (KeyValuePair<SpawnAbility, Ticket> ticket in tickets) { if (!Object.op_Implicit((Object)(object)ticket.Key)) { expired.Add(ticket.Key); } } foreach (SpawnAbility item in expired) { tickets.Remove(item); } } protected override void OnStop() { if (harmony != null) { harmony.UnpatchSelf(); } tickets.Clear(); if (instance == this) { instance = null; } } private static IEnumerable<CodeInstruction> PatchSpawn(IEnumerable<CodeInstruction> instructions, MethodBase original, ILGenerator generator) { //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Expected O, but got Unknown //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Expected O, but got Unknown //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Expected O, but got Unknown //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Expected O, but got Unknown //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Expected O, but got Unknown //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Expected O, but got Unknown //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Expected O, but got Unknown //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Expected O, but got Unknown //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Expected O, but got Unknown //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Expected O, but got Unknown //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Expected O, but got Unknown //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_051a: Expected O, but got Unknown //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_0553: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); FieldInfo fieldInfo = AccessTools.Field(original.DeclaringType, "<>4__this"); FieldInfo fieldInfo2 = AccessTools.Field(original.DeclaringType, "<targetPosition>5__5"); int num = -1; int num2 = -1; int num3 = -1; object obj = null; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; for (int i = 1; i + 1 < list.Count; i++) { MethodInfo methodInfo = list[i].operand as MethodInfo; FieldInfo fieldInfo3 = list[i].operand as FieldInfo; if (list[i].opcode == OpCodes.Ldelem_Ref && CodeInstructionExtensions.Calls(list[i - 1], AccessTools.Method(typeof(Random), "Range", new Type[2] { typeof(int), typeof(int) }, (Type[])null)) && list[i + 1].opcode == OpCodes.Stfld && ((FieldInfo)list[i + 1].operand).Name == "<prefab>5__9") { num = i; num4++; } if (list[i].opcode == OpCodes.Call && methodInfo != null && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments()[0] == typeof(GameObject) && methodInfo.GetParameters().Length == 3) { num2 = i; num5++; } if (fieldInfo3 != null && fieldInfo3.DeclaringType == typeof(SpawnAbility) && fieldInfo3.Name == "m_preSpawnEffects" && i >= 2 && (list[i - 2].opcode == OpCodes.Br || list[i - 2].opcode == OpCodes.Br_S)) { obj = list[i - 2].operand; num7++; } if (fieldInfo3 != null && fieldInfo3.DeclaringType == typeof(SpawnAbility) && fieldInfo3.Name == "m_spawnDelay" && i >= 3 && list[i - 2].opcode == OpCodes.Pop && list[i - 3].operand is MethodInfo && ((MethodInfo)list[i - 3].operand).DeclaringType == typeof(EffectList) && ((MethodInfo)list[i - 3].operand).Name == "Create") { num3 = i - 2; num6++; } } if (fieldInfo == null || fieldInfo2 == null || num4 != 1 || num5 != 1 || num6 != 1 || num7 != 1 || num >= num2 || num2 >= num3 || !(obj is Label) || list[num2 + 1].opcode != OpCodes.Stloc_2 || list[num2].labels.Count != 0 || list[num2].blocks.Count != 0) { throw new InvalidOperationException("Spirit spawn structure changed; ordered feature not patched."); } Label label = generator.DefineLabel(); list[num2 + 1].labels.Add(label); List<CodeInstruction> list2 = new List<CodeInstruction>(); for (int j = 0; j < list.Count; j++) { if (j == num2) { list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo)); list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo2)); list[j].operand = AccessTools.Method(typeof(OrderedSummonsFeature), "Create", (Type[])null, (Type[])null); } list2.Add(list[j]); if (j == num) { list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(OrderedSummonsFeature), "Select", (Type[])null, (Type[])null))); } if (j == num2) { list2.Add(new CodeInstruction(OpCodes.Dup, (object)null)); list2.Add(new CodeInstruction(OpCodes.Brtrue, (object)label)); list2.Add(new CodeInstruction(OpCodes.Pop, (object)null)); list2.Add(new CodeInstruction(OpCodes.Br, obj)); } if (j == num3) { list2.Add(new CodeInstruction(OpCodes.Ldloc_2, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(OrderedSummonsFeature), "Commit", (Type[])null, (Type[])null))); } } return list2; } } [BepInPlugin("benowy.qol", "BenowyQol", "0.3.1")] [BepInIncompatibility("local.spiritcaller.passthrough")] [BepInIncompatibility("local.food.fullduration")] [DefaultExecutionOrder(-10000)] public sealed class Plugin : BaseUnityPlugin { public const string Id = "benowy.qol"; private readonly List<QolFeature> features = new List<QolFeature>(); private ConfigEntry<KeyCode> menuKey; private SettingsMenu menu; private InputGuard input; private bool ready; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Menu", "Hotkey", (KeyCode)289, "Keyboard key for the BenowyQol menu. Also changeable in-game. Default F8."); if ((int)menuKey.Value == 0 || (int)menuKey.Value == 27) { menuKey.Value = (KeyCode)289; } features.Add(new SpiritCollisionFeature(((BaseUnityPlugin)this).Config)); features.Add(new FullFoodFeature(((BaseUnityPlugin)this).Config)); features.Add(new MinimapClockFeature(((BaseUnityPlugin)this).Config)); features.Add(new OrderedSummonsFeature(((BaseUnityPlugin)this).Config, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); })); foreach (QolFeature feature in features) { try { feature.Initialize(); } catch (Exception ex) { feature.Fail(ex); ((BaseUnityPlugin)this).Logger.LogError((object)(feature.Title + ": " + ex)); } } try { input = new InputGuard(); input.Install(); menu = new SettingsMenu(features, menuKey, SaveSettings, input); } catch (Exception ex2) { if (input != null) { input.Dispose(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Menu input protection could not initialize; menu disabled. Features remain configurable in benowy.qol.cfg. " + ex2)); } ready = true; SaveSettings(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"BenowyQol ready. F8 by default opens settings in-game. Collision requires matching settings on every client and dedicated server; food is personal."); } private string SaveSettings() { try { ((BaseUnityPlugin)this).Config.Save(); return "Saved. Food changes apply on the next normal food tick."; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Settings active but could not save: " + ex.Message)); return "Active, but could not save settings: " + ex.Message; } } private void Update() { if (ready && menu != null) { menu.Update(); } } private void FixedUpdate() { if (!ready) { return; } foreach (QolFeature feature in features) { try { feature.Tick(); } catch (Exception ex) { feature.Fail(ex); ((BaseUnityPlugin)this).Logger.LogError((object)(feature.Title + " stopped safely: " + ex)); } } } private void OnGUI() { if (ready && menu != null) { menu.Draw(); } } private void OnDisable() { ready = false; if (menu != null) { menu.Dispose(); } if (input != null) { input.Dispose(); } foreach (QolFeature feature in features) { feature.Dispose(); } } private void OnDestroy() { OnDisable(); } } internal sealed class SettingsMenu : IDisposable { private readonly List<QolFeature> features; private readonly ConfigEntry<KeyCode> hotkey; private readonly Func<string> save; private readonly InputGuard input; private readonly UiShield shield = new UiShield(); private bool open; private bool capturing; private Player menuPlayer; private string status = "Changes save automatically. The world keeps running."; private Rect window; private Vector2 scroll; private GUIStyle windowStyle; private GUIStyle labelStyle; private GUIStyle titleStyle; private GUIStyle buttonStyle; private Texture2D background; public SettingsMenu(List<QolFeature> features, ConfigEntry<KeyCode> hotkey, Func<string> save, InputGuard input) { this.features = features; this.hotkey = hotkey; this.save = save; this.input = input; } public void Update() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_017d: Unknown result type (might be due to invalid IL or missing references) input.Update(); shield.SetActive(input.Blocking); Player localPlayer = Player.m_localPlayer; if (open && (!Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)localPlayer != (Object)(object)menuPlayer || ((Character)localPlayer).IsDead())) { Close(); } else { if (capturing) { return; } if (open && input.KeyDown((KeyCode)27)) { Close(); } else if (input.KeyDown(hotkey.Value)) { if (open) { Close(); } else if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && !Minimap.IsOpen() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus())) { open = true; menuPlayer = localPlayer; window = new Rect((float)(Screen.width - Math.Min(640, Screen.width - 24)) / 2f, Math.Max(12f, (float)(Screen.height - 480) / 2f), (float)Math.Min(640, Screen.width - 24), (float)Math.Min(480, Screen.height - 24)); input.SetOpen(value: true, hotkey.Value); shield.SetActive(value: true); } } } } private void Close() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) open = false; capturing = false; input.SetOpen(value: false, hotkey.Value); } public void Draw() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0192: 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_01b3: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_004d: 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) if (!open) { return; } EnsureStyles(); Event current = Event.current; if (capturing && (int)current.type == 4 && (int)current.keyCode != 0) { if ((int)current.keyCode == 27) { capturing = false; status = "Key change cancelled."; } else if (ZInput.IsKeyCodeValid(current.keyCode)) { hotkey.Value = current.keyCode; capturing = false; status = save(); } current.Use(); } Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.5f); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture); GUI.color = color; ((Rect)(ref window)).width = Math.Min(640, Screen.width - 24); ((Rect)(ref window)).height = Math.Min(480, Screen.height - 24); ((Rect)(ref window)).x = Mathf.Clamp(((Rect)(ref window)).x, 0f, Math.Max(0f, (float)Screen.width - ((Rect)(ref window)).width)); ((Rect)(ref window)).y = Mathf.Clamp(((Rect)(ref window)).y, 0f, Math.Max(0f, (float)Screen.height - ((Rect)(ref window)).height)); window = GUI.Window(194732, window, new WindowFunction(DrawWindow), "BenowyQol", windowStyle); } private void DrawWindow(int id) { //IL_002c: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_019d: 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_02a4: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginArea(new Rect(18f, 36f, ((Rect)(ref window)).width - 36f, ((Rect)(ref window)).height - 50f)); scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Choose what to enable", titleStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); foreach (QolFeature feature in features) { GUILayout.Space(12f); bool enabled = GUI.enabled; GUI.enabled = feature.Available; if (GUILayout.Button((feature.Enabled ? "ON " : "OFF ") + feature.Title, buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(38f) })) { try { feature.SetEnabled(!feature.Enabled); status = save(); } catch (Exception ex) { feature.Fail(ex); status = "Could not change this feature: " + ex.Message; } } GUI.enabled = enabled; GUILayout.Label(feature.Description, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (!feature.Available) { GUILayout.Label(feature.Status, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } GUILayout.Space(18f); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button(capturing ? "Press a key (Esc cancels)" : string.Concat("Menu key: ", hotkey.Value, " / Change"), buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(34f) })) { capturing = !capturing; } if (GUILayout.Button("Close", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(100f), GUILayout.MinHeight(34f) })) { Close(); } GUILayout.EndHorizontal(); GUILayout.Space(10f); GUILayout.Label(status, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(string.Concat("Close with ", hotkey.Value, " or Esc. This menu does not pause the world."), labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndScrollView(); GUILayout.EndArea(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref window)).width, 30f)); } private void EnsureStyles() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00cd: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown if (windowStyle == null) { background = new Texture2D(1, 1); background.SetPixel(0, 0, new Color(0.08f, 0.1f, 0.13f, 0.98f)); background.Apply(); GUIStyle val = new GUIStyle(GUI.skin.window); val.fontSize = 22; windowStyle = val; windowStyle.normal.background = background; windowStyle.normal.textColor = Color.white; windowStyle.onNormal.background = background; windowStyle.onNormal.textColor = Color.white; GUIStyle val2 = new GUIStyle(GUI.skin.label); val2.fontSize = 15; val2.wordWrap = true; labelStyle = val2; labelStyle.normal.textColor = new Color(0.9f, 0.92f, 0.95f); GUIStyle val3 = new GUIStyle(labelStyle); val3.fontSize = 19; val3.fontStyle = (FontStyle)1; titleStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.button); val4.fontSize = 17; val4.wordWrap = true; buttonStyle = val4; } } public void Dispose() { if (open) { Close(); } if (Object.op_Implicit((Object)(object)background)) { Object.Destroy((Object)(object)background); } shield.Dispose(); } } internal sealed class SpiritCollisionFeature : QolFeature { private sealed class Pair { public Collider A; public Collider B; public bool PreviouslyIgnored; } private sealed class Bodies { public Collider Root; public Rigidbody Body; public float RefreshAt; public readonly List<Collider> Colliders = new List<Collider>(); } private struct Node { public Character Character; public bool Spirit; } private static readonly HashSet<int> SpiritPrefabs = new HashSet<int> { StringExtensionMethods.GetStableHashCode("Boar_spiritcaller"), StringExtensionMethods.GetStableHashCode("Wolf_spiritcaller"), StringExtensionMethods.GetStableHashCode("Moose_spiritcaller"), StringExtensionMethods.GetStableHashCode("Bjorn_spiritcaller") }; private readonly Dictionary<ulong, Pair> pairs = new Dictionary<ulong, Pair>(); private readonly HashSet<ulong> seen = new HashSet<ulong>(); private readonly List<ulong> removedPairs = new List<ulong>(); private readonly Dictionary<Character, Bodies> bodyCache = new Dictionary<Character, Bodies>(); private readonly HashSet<Character> live = new HashSet<Character>(); private readonly List<Character> removedCharacters = new List<Character>(); private readonly List<Node> characters = new List<Node>(); public SpiritCollisionFeature(ConfigFile config) : base(config, "FriendlySpiritCollisions", "Friendly Spirit Caller collisions", "Anyone's four Spirit Caller summons pass through friendly characters. Every client and dedicated server must use matching settings; PvP-enabled players retain collision.") { } protected override void OnTick() { UpdatePairs(); } protected override void OnToggle(bool next) { if (!next) { Clear(); } } protected override void OnStop() { Clear(); } private void UpdatePairs() { seen.Clear(); live.Clear(); characters.Clear(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (Object.op_Implicit((Object)(object)allCharacter) && ((Component)allCharacter).gameObject.activeInHierarchy && !allCharacter.IsDead()) { ZNetView component = ((Component)allCharacter).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { live.Add(allCharacter); characters.Add(new Node { Character = allCharacter, Spirit = SpiritPrefabs.Contains(component.GetZDO().GetPrefab()) }); } } } for (int i = 0; i < characters.Count; i++) { Node node = characters[i]; if (!node.Spirit) { continue; } for (int j = 0; j < characters.Count; j++) { Node node2 = characters[j]; if (i == j || (node2.Spirit && j < i) || !Friendly(node.Character, node2.Character)) { continue; } List<Collider> bodies = GetBodies(node.Character); List<Collider> bodies2 = GetBodies(node2.Character); foreach (Collider item in bodies) { foreach (Collider item2 in bodies2) { if (ActiveBody(item, node.Character) && ActiveBody(item2, node2.Character) && (Object)(object)item != (Object)(object)item2) { AddPair(item, item2); } } } } } removedPairs.Clear(); foreach (KeyValuePair<ulong, Pair> pair in pairs) { if (!seen.Contains(pair.Key)) { removedPairs.Add(pair.Key); } } foreach (ulong removedPair in removedPairs) { Restore(pairs[removedPair]); pairs.Remove(removedPair); } removedCharacters.Clear(); foreach (KeyValuePair<Character, Bodies> item3 in bodyCache) { if (!live.Contains(item3.Key)) { removedCharacters.Add(item3.Key); } } foreach (Character removedCharacter in removedCharacters) { bodyCache.Remove(removedCharacter); } } private static bool Friendly(Character a, Character b) { if ((a.IsPlayer() && a.IsPVPEnabled()) || (b.IsPlayer() && b.IsPVPEnabled())) { return false; } if (!BaseAI.IsEnemy(a, b)) { return !BaseAI.IsEnemy(b, a); } return false; } private List<Collider> GetBodies(Character character) { if (!bodyCache.TryGetValue(character, out var value)) { value = new Bodies(); bodyCache.Add(character, value); } Collider collider = (Collider)(object)character.GetCollider(); Rigidbody val = (Object.op_Implicit((Object)(object)collider) ? collider.attachedRigidbody : null); if ((Object)(object)value.Root != (Object)(object)collider || (Object)(object)value.Body != (Object)(object)val || Time.time >= value.RefreshAt) { value.Root = collider; value.Body = val; value.RefreshAt = Time.time + 0.5f; value.Colliders.Clear(); if (Object.op_Implicit((Object)(object)collider)) { value.Colliders.Add(collider); } if (Object.op_Implicit((Object)(object)val)) { Collider[] componentsInChildren = ((Component)character).GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)(object)collider && (Object)(object)val2.attachedRigidbody == (Object)(object)val && (Object)(object)((Component)val2).GetComponentInParent<Character>() == (Object)(object)character) { value.Colliders.Add(val2); } } } } return value.Colliders; } private static bool ActiveBody(Collider collider, Character character) { if (!Object.op_Implicit((Object)(object)collider) || !collider.enabled || !((Component)collider).gameObject.activeInHierarchy || collider.isTrigger) { return false; } Collider collider2 = (Collider)(object)character.GetCollider(); if ((Object)(object)collider == (Object)(object)collider2) { return true; } if (Object.op_Implicit((Object)(object)collider2) && Object.op_Implicit((Object)(object)collider2.attachedRigidbody) && (Object)(object)collider.attachedRigidbody == (Object)(object)collider2.attachedRigidbody) { return (Object)(object)((Component)collider).GetComponentInParent<Character>() == (Object)(object)character; } return false; } private void AddPair(Collider a, Collider b) { int num = ((Object)a).GetInstanceID(); int num2 = ((Object)b).GetInstanceID(); if (num > num2) { Collider val = a; a = b; b = val; int num3 = num; num = num2; num2 = num3; } ulong num4 = ((ulong)(uint)num << 32) | (uint)num2; seen.Add(num4); if (pairs.TryGetValue(num4, out var value) && ((Object)(object)value.A != (Object)(object)a || (Object)(object)value.B != (Object)(object)b)) { Restore(value); pairs.Remove(num4); } if (!pairs.TryGetValue(num4, out value)) { Pair pair = new Pair(); pair.A = a; pair.B = b; pair.PreviouslyIgnored = Physics.GetIgnoreCollision(a, b); value = pair; pairs.Add(num4, value); } if (!Physics.GetIgnoreCollision(a, b)) { Physics.IgnoreCollision(a, b, true); } } private static void Restore(Pair pair) { if (Object.op_Implicit((Object)(object)pair.A) && Object.op_Implicit((Object)(object)pair.B) && !pair.PreviouslyIgnored) { Physics.IgnoreCollision(pair.A, pair.B, false); } } private void Clear() { foreach (Pair value in pairs.Values) { Restore(value); } pairs.Clear(); bodyCache.Clear(); seen.Clear(); live.Clear(); characters.Clear(); } } internal sealed class SummonCycleState { public static readonly string[] PrefabOrder = new string[4] { "Boar_spiritcaller", "Wolf_spiritcaller", "Bjorn_spiritcaller", "Moose_spiritcaller" }; public int NextIndex { get; private set; } public SummonCycleState(int savedIndex) { NextIndex = ((savedIndex >= 0 && savedIndex < 4) ? savedIndex : 0); } public bool Commit(int createdIndex) { if (createdIndex != NextIndex) { return false; } NextIndex = (NextIndex + 1) % 4; return true; } } internal sealed class ToggleState { private readonly Action<bool> transition; public bool Enabled { get; private set; } public ToggleState(bool initial, Action<bool> transition) { Enabled = initial; this.transition = transition; } public bool Set(bool next) { if (next == Enabled) { return false; } transition(next); Enabled = next; return true; } } internal sealed class UiShield { private GameObject overlay; private EventSystem eventSystem; private GameObject priorSelection; private bool active; public void SetActive(bool value) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if (value && !active) { if (!Object.op_Implicit((Object)(object)overlay)) { overlay = new GameObject("BenowyQol input shield", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)overlay); Canvas component = overlay.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 32767; GameObject val = new GameObject("Block underlying UI", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(overlay.transform, false); RectTransform component2 = val.GetComponent<RectTransform>(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; component2.offsetMin = Vector2.zero; component2.offsetMax = Vector2.zero; Image component3 = val.GetComponent<Image>(); ((Graphic)component3).color = new Color(0f, 0f, 0f, 0.001f); ((Graphic)component3).raycastTarget = true; } eventSystem = EventSystem.current; priorSelection = (Object.op_Implicit((Object)(object)eventSystem) ? eventSystem.currentSelectedGameObject : null); overlay.SetActive(true); } if (value && Object.op_Implicit((Object)(object)EventSystem.current)) { EventSystem.current.SetSelectedGameObject((GameObject)null); } if (!value && active) { if (Object.op_Implicit((Object)(object)overlay)) { overlay.SetActive(false); } if (Object.op_Implicit((Object)(object)eventSystem) && (Object)(object)EventSystem.current == (Object)(object)eventSystem && Object.op_Implicit((Object)(object)priorSelection) && priorSelection.activeInHierarchy) { eventSystem.SetSelectedGameObject(priorSelection); } eventSystem = null; priorSelection = null; } active = value; } public void Dispose() { SetActive(value: false); if (Object.op_Implicit((Object)(object)overlay)) { Object.Destroy((Object)(object)overlay); } } }