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 FoodTweaks v0.1.2
FoodTweaks.dll
Decompiled 9 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FoodTweaks.Extensions; using HarmonyLib; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Logging; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("FoodTweaks")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ToolTweaks")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.1.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = "")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.2.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 Logging { internal static class Log { internal enum InfoLevel { Low, Medium, High } private static ManualLogSource logSource; internal static ConfigEntry<InfoLevel> Verbosity { get; set; } internal static InfoLevel VerbosityLevel => Verbosity.Value; internal static bool IsVerbosityLow => Verbosity.Value >= InfoLevel.Low; internal static bool IsVerbosityMedium => Verbosity.Value >= InfoLevel.Medium; internal static bool IsVerbosityHigh => Verbosity.Value >= InfoLevel.High; internal static void Init(ManualLogSource logSource) { Log.logSource = logSource; } internal static void LogDebug(object data) { logSource.LogDebug(data); } internal static void LogError(object data) { logSource.LogError(data); } internal static void LogFatal(object data) { logSource.LogFatal(data); } internal static void LogMessage(object data) { logSource.LogMessage(data); } internal static void LogWarning(object data) { logSource.LogWarning(data); } internal static void LogInfo(object data, InfoLevel level = InfoLevel.Low) { if (Verbosity == null || VerbosityLevel >= level) { logSource.LogInfo(data); } } internal static void LogGameObject(GameObject prefab, bool includeChildren = false) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown LogInfo("***** " + ((Object)prefab).name + " *****"); Component[] components = prefab.GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } if (!includeChildren) { return; } LogInfo("***** " + ((Object)prefab).name + " (children) *****"); foreach (Transform item in prefab.transform) { Transform val = item; if (Object.op_Implicit((Object)(object)val)) { LogInfo(" - " + ((Object)val).name); components = ((Component)val).GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } } } } internal static void LogComponent(Component compo) { if (!Object.op_Implicit((Object)(object)compo)) { return; } try { LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---"); } catch (Exception ex) { LogError(ex.ToString()); LogWarning("Could not get type name for component!"); return; } try { foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType())) { try { LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}"); } catch (Exception ex2) { LogError(ex2.ToString()); LogWarning("Could not get property: " + declaredProperty.Name + " for component!"); } } } catch (Exception ex3) { LogError(ex3.ToString()); LogWarning("Could not get properties for component!"); } try { foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType())) { try { LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}"); } catch (Exception ex4) { LogError(ex4.ToString()); LogWarning("Could not get field: " + declaredField.Name + " for component!"); } } } catch (Exception ex5) { LogError(ex5.ToString()); LogWarning("Could not get fields for component!"); } } } } namespace FoodTweaks { [BepInPlugin("Searica.Valheim.FoodTweaks", "FoodTweaks", "0.1.2")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] internal sealed class FoodTweaks : BaseUnityPlugin { internal const string Author = "Searica"; public const string PluginName = "FoodTweaks"; public const string PluginGUID = "Searica.Valheim.FoodTweaks"; public const string PluginVersion = "0.1.2"; private const string MainSection = "Global"; internal static FoodTweaks Instance; private static ConfigFileWatcher ConfigWatcher; internal ConfigEntry<bool> EnableExtraStaminaRegen; internal ConfigEntry<bool> EnableExtraEitrRegen; internal ConfigEntry<float> ExtraStaminaRegenFromFood; internal ConfigEntry<float> ExtraEitrRegenFromFood; private static bool ShouldUpdatePlugin; public void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Instance = this; Log.Init(((BaseUnityPlugin)this).Logger); SetUpConfigEntries(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.FoodTweaks"); Game.isModded = true; ConfigWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L); ConfigWatcher.OnConfigFileReloaded += delegate { UpdatePlugin(shouldSave: false); }; SynchronizationManager.OnConfigurationWindowClosed += delegate { UpdatePlugin(shouldSave: true); }; SynchronizationManager.OnConfigurationSynchronized += delegate { UpdatePlugin(shouldSave: true); }; } public void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } internal void SetUpConfigEntries() { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; Log.Verbosity = ConfigFileExtensions.BindConfigInOrder<Log.InfoLevel>(((BaseUnityPlugin)this).Config, "Global", "Verbosity", Log.InfoLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow Down your game.", false, false, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); EnableExtraStaminaRegen = ConfigFileExtensions.BindConfigInOrder<bool>(((BaseUnityPlugin)this).Config, "Global", "EnableExtraStaminaRegen", true, "Whether to enable gaining extra stamina regen from food.", true, false, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ExtraStaminaRegenFromFood = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "ExtraStaminaRegenFromFood", 1f, "The percent increase in stamina regen per 10 points of stamina gained from food.", true, false, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); EnableExtraEitrRegen = ConfigFileExtensions.BindConfigInOrder<bool>(((BaseUnityPlugin)this).Config, "Global", "EnableExtraEitrRegen", true, "Whether to enable gaining extra eitr regen from food.", true, false, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ExtraEitrRegenFromFood = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "ExtraEitrRegenFromFood", 1f, "The percent increase in eitr per 10 points of eitr gained from food.", true, false, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); EnableExtraStaminaRegen.SettingChanged += SetUpdatePlugin; ExtraStaminaRegenFromFood.SettingChanged += SetUpdatePlugin; EnableExtraEitrRegen.SettingChanged += SetUpdatePlugin; ExtraEitrRegenFromFood.SettingChanged += SetUpdatePlugin; ((BaseUnityPlugin)this).Config.Save(); } private static void SetUpdatePlugin(object obj, EventArgs e) { ShouldUpdatePlugin = !ShouldUpdatePlugin | ShouldUpdatePlugin; } private static void UpdatePlugin(bool shouldSave) { if (ShouldUpdatePlugin) { ShouldUpdatePlugin = false; if (shouldSave) { ((BaseUnityPlugin)Instance).Config.Save(); } } } } [HarmonyPatch] internal static class FoodPatches { private static readonly MethodInfo ModifyStaminaRegenInfo = AccessTools.Method(typeof(SEMan), "ModifyStaminaRegen", (Type[])null, (Type[])null); private static readonly MethodInfo ModifyEitrRegenInfo = AccessTools.Method(typeof(SEMan), "ModifyEitrRegen", (Type[])null, (Type[])null); private static readonly FieldInfo SEManInfo = AccessTools.Field(typeof(Character), "m_seman"); private static float BaseStamina = float.NaN; private static float BaseEitr = 0f; private static float StaminaFromFood = 0f; private static float EitrFromFood = 0f; private static string[] tooltipTokens = new string[5] { "$se_staminaregen", "$item_food_regen", "$item_food_duration", "$item_food_eitr", "$item_food_stamina" }; [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "shudnal.StaminaExtended", "shudnal.EitrMagicExtended", "MidnightsFX.ImpactfulSkills" })] [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static void GetStatsFromFood(Player __instance, float stamina, float eitr) { if (Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { StaminaFromFood = stamina - __instance.m_baseStamina; EitrFromFood = eitr; } } [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "shudnal.MyLittleUI", "shudnal.StaminaExtended", "shudnal.EitrMagicExtended" })] [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static void ItemDrop_ItemData_GetTooltip_StaminaRegenTooltipForFoodRegen(ItemData item, ref string __result) { if (!FoodTweaks.Instance.EnableExtraStaminaRegen.Value && !FoodTweaks.Instance.EnableExtraEitrRegen.Value) { return; } string[] array; if (FoodTweaks.Instance.EnableExtraStaminaRegen.Value && IsFoodItemForExtraStaminaRegeneration(item, out var foodStamina)) { int num = -1; array = tooltipTokens; foreach (string value in array) { num = __result.IndexOf(value, StringComparison.InvariantCulture); if (num != -1) { break; } } if (num == -1) { return; } string text = $"\n$se_staminaregen: <color=#ffff80ff>{GetStaminaRegenerationValueFromStaminaPoints(foodStamina):P1}</color> ($item_current:<color=yellow>{GetStaminaMultiplier():P1}</color>)"; int num2 = __result.IndexOf("\n", num, StringComparison.InvariantCulture); if (num2 != -1) { __result = __result.Insert(num2, text); } else { __result += text; } } if (!FoodTweaks.Instance.EnableExtraEitrRegen.Value || !IsFoodItemForExtraEitrRegeneration(item, out var foodEitr)) { return; } int num3 = -1; array = tooltipTokens; foreach (string value2 in array) { num3 = __result.IndexOf(value2, StringComparison.InvariantCulture); if (num3 != -1) { break; } } if (num3 != -1) { string text2 = $"\n$se_eitrregen: <color=#9090ffff>{GetEitrRegenerationValueFromEitrPoints(foodEitr):P1}</color> ($item_current:<color=yellow>{GetEitrMultiplier():P1}</color>)"; int num4 = __result.IndexOf("\n", num3, StringComparison.InvariantCulture); if (num4 != -1) { __result = __result.Insert(num4, text2); } else { __result += text2; } } } [HarmonyPostfix] [HarmonyPatch(typeof(TextsDialog), "AddActiveEffects")] private static void TextsDialog_AddActiveEffects_SeasonTooltipWhenBuffDisabled(TextsDialog __instance) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { float staminaMultiplier = GetStaminaMultiplier(); if (staminaMultiplier >= 0.01f) { TextInfo obj = __instance.m_texts[0]; obj.m_text += Localization.instance.Localize($"\n$se_staminaregen ($item_food): <color=orange>{staminaMultiplier:P1}</color>"); } float eitrMultiplier = GetEitrMultiplier(); if (eitrMultiplier >= 0.01f) { TextInfo obj2 = __instance.m_texts[0]; obj2.m_text += Localization.instance.Localize($"\n$se_eitrregen ($item_food): <color=orange>{eitrMultiplier:P1}</color>"); } } } public static float GetStaminaMultiplier() { return GetStaminaRegenerationValueFromStaminaPoints(StaminaFromFood); } private static float GetStaminaRegenerationValueFromStaminaPoints(float points) { return Mathf.Max(0f, FoodTweaks.Instance.ExtraStaminaRegenFromFood.Value / 100f * (points / 10f)); } private static bool IsFoodItemForExtraStaminaRegeneration(ItemData item, out float foodStamina) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 foodStamina = 0f; if (!Player.m_localPlayerExists) { return false; } if ((int)item.m_shared.m_itemType == 2) { foodStamina = item.m_shared.m_foodStamina; } if (!(foodStamina > 0f)) { if ((Object)(object)item.m_shared.m_appendToolTip != (Object)null) { return IsFoodItemForExtraStaminaRegeneration(item.m_shared.m_appendToolTip.m_itemData, out foodStamina); } return false; } return true; } public static float GetEitrMultiplier() { return GetEitrRegenerationValueFromEitrPoints(EitrFromFood); } private static float GetEitrRegenerationValueFromEitrPoints(float points) { return Mathf.Max(0f, FoodTweaks.Instance.ExtraEitrRegenFromFood.Value / 100f) * (points / 10f); } private static bool IsFoodItemForExtraEitrRegeneration(ItemData item, out float foodEitr) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 foodEitr = 0f; if (!Player.m_localPlayerExists) { return false; } if ((int)item.m_shared.m_itemType == 2) { foodEitr = item.m_shared.m_foodEitr; } if (!(foodEitr > 0f)) { if ((Object)(object)item.m_shared.m_appendToolTip != (Object)null) { return IsFoodItemForExtraEitrRegeneration(item.m_shared.m_appendToolTip.m_itemData, out foodEitr); } return false; } return true; } [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] private static IEnumerable<CodeInstruction> UpdateRegenMultipliers(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); CodeMatch[] matches = (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruct) => CodeInstructionExtensions.IsLdloc(instruct, (LocalBuilder)null)), (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)ModifyStaminaRegenInfo, (string)null) }; CodeMatch[] matches2 = (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruct) => CodeInstructionExtensions.IsLdloc(instruct, (LocalBuilder)null)), (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)ModifyEitrRegenInfo, (string)null) }; for (int num = 0; num < 2; num++) { if (num == 0) { ApplyILPatch(val, matches, "Patching stamina regen", Transpilers.EmitDelegate<<>A{00000008}<Player, float>>((<>A{00000008}<Player, float>)UpdateStaminaMultipler_Delegate)); } else { ApplyILPatch(val, matches2, "Patching eitr regen", Transpilers.EmitDelegate<<>A{00000008}<Player, float>>((<>A{00000008}<Player, float>)UpdateEitrMultipler_Delegate)); } } return val.InstructionEnumeration(); } private static void ApplyILPatch(CodeMatcher matcher, CodeMatch[] matches, string message, CodeInstruction instruction) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (matcher.TryMatchStartForward(message, matches)) { CodeInstruction instruction2 = matcher.Instruction; matcher.Advance(matches.Length).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), instruction2 }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { instruction }); } } private static void UpdateStaminaMultipler_Delegate(Player player, ref float multiplier) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer)) { multiplier += GetStaminaMultiplier(); } } private static void UpdateEitrMultipler_Delegate(Player player, ref float multiplier) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer)) { multiplier += GetEitrMultiplier(); } } } } namespace FoodTweaks.Extensions { internal static class CopyExtensions { private static class FieldInfoCache { private const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; private static readonly Dictionary<Type, FieldInfo[]> dictionaryCache = new Dictionary<Type, FieldInfo[]>(); internal static FieldInfo[] GetFieldInfo(Type type) { if (dictionaryCache.TryGetValue(type, out var value)) { return value; } CacheTypeFieldInfo(type); return dictionaryCache[type]; } internal static void CacheTypeFieldInfo(Type type) { if (!dictionaryCache.ContainsKey(type)) { dictionaryCache.Add(type, type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty)); } } } public static void CopyFields<T>(this T target, T source) { if (target == null || source == null) { throw new Exception("Target or/and Source Objects are null"); } FieldInfo[] fieldInfo = FieldInfoCache.GetFieldInfo(source.GetType()); foreach (FieldInfo fieldInfo2 in fieldInfo) { if (!(fieldInfo2 == null) && fieldInfo2.IsInitOnly) { fieldInfo2.SetValue(target, fieldInfo2.GetValue(source)); } } } } internal static class EventExtensions { public static void SafeInvoke(this Action events) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action action = (Action)invocationList[i]; try { action(); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action<TArg1> action = (Action<TArg1>)invocationList[i]; try { action(arg1); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i]; try { action(arg1, arg2); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i]; try { eventHandler(sender, arg1); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}"); } } } } public static class GameObjectExtensions { public static bool HasAnyComponent(this GameObject gameObject, params Type[] components) { foreach (Type type in components) { if (Object.op_Implicit((Object)(object)gameObject.GetComponent(type))) { return true; } } return false; } public static bool HasAnyComponent(this GameObject gameObject, params string[] componentNames) { foreach (string text in componentNames) { if (Object.op_Implicit((Object)(object)gameObject.GetComponent(text))) { return true; } } return false; } public static bool HasAllComponents(this GameObject gameObject, params string[] componentNames) { foreach (string text in componentNames) { if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(text))) { return false; } } return true; } public static bool HasAllComponents(this GameObject gameObject, params Type[] components) { foreach (Type type in components) { if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(type))) { return false; } } return true; } public static bool HasAnyComponentInChildren(this GameObject gameObject, bool includeInactive = false, params Type[] components) { foreach (Type type in components) { if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren(type, includeInactive))) { return true; } } return false; } public static Transform FindDeepChild(this GameObject gameObject, string childName, IterativeSearchType searchType = (IterativeSearchType)1) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return gameObject.transform.FindDeepChild(childName, searchType); } } internal static class TypeExtensions { internal static List<T> GetAllPublicConstantValues<T>(this Type type) { return (from x in type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy) where x.IsLiteral && !x.IsInitOnly && x.FieldType == typeof(T) select (T)x.GetRawConstantValue()).ToList(); } internal static List<T> GetAllPublicStaticValues<T>(this Type type) { return (from x in type.GetFields(BindingFlags.Static | BindingFlags.Public) where x.FieldType == typeof(T) select (T)x.GetValue(null)).ToList(); } } internal static class GenericExtensions { internal static T Ref<T>(this T o) where T : Object { if (!Object.op_Implicit((Object)(object)o)) { return default(T); } return o; } } internal static class IEnumerableExtensions { internal static void Dispose(this IEnumerable<IDisposable> collection) { foreach (IDisposable item in collection) { if (item != null) { try { item.Dispose(); } catch (Exception) { Log.LogWarning("Could not dispose of item"); } } } } } internal static class ReflectionUtils { public const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; internal static MethodInfo GetMethod(Type type, string name, Type[] types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == name && HasMatchingParameterTypes(0, types, methodInfo.GetParameters())) { return methodInfo; } } return null; } internal static MethodInfo GetGenericMethod(Type type, string name, int genericParameterCount, Type[] types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (MethodInfo methodInfo in methods) { if (methodInfo.IsGenericMethod && methodInfo.ContainsGenericParameters && methodInfo.Name == name && HasMatchingParameterTypes(genericParameterCount, types, methodInfo.GetParameters())) { return methodInfo; } } return null; } private static bool HasMatchingParameterTypes(int genericParameterCount, Type[] types, ParameterInfo[] parameters) { if (parameters.Length < genericParameterCount || parameters.Length != types.Length) { return false; } int num = 0; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType.IsGenericParameter) { num++; } else if (types[i] != parameters[i].ParameterType) { return false; } } if (num != genericParameterCount) { return false; } return true; } } public static class StringExtensions { public static bool ContainsAny(this string str, params string[] substrings) { foreach (string value in substrings) { if (str.Contains(value)) { return true; } } return false; } public static bool EndsWithAny(this string str, params string[] suffixes) { foreach (string value in suffixes) { if (str.EndsWith(value)) { return true; } } return false; } public static bool StartsWithAny(this string str, params string[] prefixes) { foreach (string value in prefixes) { if (str.StartsWith(value)) { return true; } } return false; } public static string RemoveSuffix(this string s, string suffix) { if (s.EndsWith(suffix)) { return s.Substring(0, s.Length - suffix.Length); } return s; } public static string RemovePrefix(this string s, string prefix) { if (s.StartsWith(prefix)) { return s.Substring(prefix.Length, s.Length - prefix.Length); } return s; } public static string CapitalizeFirstLetter(this string s) { if (s.Length == 0) { return s; } if (s.Length == 1) { return $"{char.ToUpper(s[0])}"; } return char.ToUpper(s[0]) + s.Substring(1); } } public static class TransformExtensions { public static Transform FindDeepChild(this Transform transform, string childName, IterativeSearchType searchType = (IterativeSearchType)1) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Utils.FindChild(transform, childName, searchType); } } internal static class Utils { public static bool TryMatchStartForward(this CodeMatcher matcher, string failureMessage, params CodeMatch[] matches) { matcher.MatchStartForward(matches); if (matcher.IsInvalid) { Log.LogWarning(failureMessage + " Anchor instruction not found, it was likely consumed by another mod. Skipping this patch."); return false; } return true; } public static bool TryMatchEndForward(this CodeMatcher matcher, string failureMessage, params CodeMatch[] matches) { matcher.MatchEndForward(matches); if (matcher.IsInvalid) { Log.LogWarning(failureMessage + " Anchor instruction not found, it was likely consumed by another mod. Skipping this patch."); return false; } return true; } } }