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 ToolTweaks v1.2.1
ToolTweaks.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using ToolTweaks.Configs; using ToolTweaks.Extensions; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ToolTweaks")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ToolTweaks")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.2.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.0")] [module: UnverifiableCode] namespace ToolTweaks { [BepInPlugin("Searica.Valheim.ToolTweaks", "ToolTweaks", "1.2.1")] [BepInDependency("com.jotunn.jotunn", "2.22.0")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] internal sealed class ToolTweaks : BaseUnityPlugin { internal const string Author = "Searica"; public const string PluginName = "ToolTweaks"; public const string PluginGUID = "Searica.Valheim.ToolTweaks"; public const string PluginVersion = "1.2.1"; private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 3); private static ConfigEntry<float> useDelay; private static ConfigEntry<float> staminaMult; private static ConfigEntry<float> durabiltyMult; private static bool ShouldUpdatePlugin = false; internal static float UseageDelay => useDelay.Value; internal static float StaminaMultiplier => staminaMult.Value; internal static float DurabilityMultiplier => durabiltyMult.Value; public void Awake() { Log.Init(((BaseUnityPlugin)this).Logger); ConfigManager.Init("Searica.Valheim.ToolTweaks", ((BaseUnityPlugin)this).Config); SetUpConfigEntries(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.ToolTweaks"); Game.isModded = true; ConfigManager.SetupWatcher(); ConfigManager.OnConfigFileReloaded += UpdatePlugin; SynchronizationManager.OnConfigurationWindowClosed += UpdatePlugin; SynchronizationManager.OnConfigurationSynchronized += delegate { UpdatePlugin(); }; } public void OnDestroy() { ConfigManager.Save(); } internal static void SetUpConfigEntries() { Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", LogLevel.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.", null, synced: false); useDelay = ConfigManager.BindConfig(MainSection, "Usage Delay", 0.25f, "Set the time delay between tool uses for both placement and removal. Vanilla default is 0.4s for placement and 0.25s for removal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f)); staminaMult = ConfigManager.BindConfig(MainSection, "Stamina Cost Multiplier", 0.5f, "Change the stamina cost for using tools. Setting to 0.5 means stamina costs are reduced to 50%. Setting to 2 means stamina costs are increased to 200%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f)); durabiltyMult = ConfigManager.BindConfig(MainSection, "Durability Drain Multiplier", 0.5f, "Change the amount of durability drained each time a tool is used. Setting to 0.5 means durability is drained 50% as much. Setting to 2 means durability drain is increased to 200%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f)); useDelay.SettingChanged += SetUpdatePlugin; staminaMult.SettingChanged += SetUpdatePlugin; durabiltyMult.SettingChanged += SetUpdatePlugin; ConfigManager.Save(); } private static void SetUpdatePlugin(object obj, EventArgs e) { ShouldUpdatePlugin = !ShouldUpdatePlugin | ShouldUpdatePlugin; } private static void UpdatePlugin() { if (ShouldUpdatePlugin) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { localPlayer.m_placeDelay = UseageDelay; localPlayer.m_removeDelay = UseageDelay; } ShouldUpdatePlugin = false; ConfigManager.Save(); } } } [HarmonyPatch(typeof(Player))] internal static class PlayerPatch { private static bool UsingBuildTool; [HarmonyPostfix] [HarmonyPatch("Awake")] private static void AwakePostfix(Player __instance) { if (Object.op_Implicit((Object)(object)__instance)) { __instance.m_placeDelay = ToolTweaks.UseageDelay; __instance.m_removeDelay = ToolTweaks.UseageDelay; } } [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyPatch("UpdatePlacement")] private static void UpdatePlacementPrefix(Player __instance, out float __state) { if (Object.op_Implicit((Object)(object)__instance) && ((Character)__instance).InPlaceMode() && !((Character)__instance).IsDead()) { ItemData rightItem = ((Humanoid)__instance).GetRightItem(); if (rightItem != null) { UsingBuildTool = true; __state = rightItem.m_shared.m_useDurabilityDrain; SharedData shared = rightItem.m_shared; shared.m_useDurabilityDrain *= ToolTweaks.DurabilityMultiplier; return; } } __state = -1f; } [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch("UpdatePlacement")] private static void UpdatePlacementPostfix(Player __instance, float __state) { if (UsingBuildTool) { if (Object.op_Implicit((Object)(object)__instance) && __state != -1f) { ((Humanoid)__instance).GetRightItem().m_shared.m_useDurabilityDrain = __state; } UsingBuildTool = false; } } [HarmonyPrefix] [HarmonyPatch("UseStamina")] private static void UseStaminaPrefix(Player __instance, ref float v) { if (UsingBuildTool && Object.op_Implicit((Object)(object)__instance) && IsWieldingTool(__instance)) { v *= ToolTweaks.StaminaMultiplier; } } private static bool IsWieldingTool(Player player) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)player)) { return (int)((Humanoid)player).GetRightItem().m_shared.m_itemType == 19; } return false; } } internal enum LogLevel { Low, Medium, High } internal static class Log { private static ManualLogSource logSource; internal static ConfigEntry<LogLevel> Verbosity { get; set; } internal static LogLevel VerbosityLevel => Verbosity.Value; internal static bool IsVerbosityLow => Verbosity.Value >= LogLevel.Low; internal static bool IsVerbosityMedium => Verbosity.Value >= LogLevel.Medium; internal static bool IsVerbosityHigh => Verbosity.Value >= LogLevel.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, LogLevel level = LogLevel.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; LogInfo(" - " + ((Object)((Component)val).gameObject).name); components = ((Component)val).gameObject.GetComponents<Component>(); for (int i = 0; i < components.Length; i++) { LogComponent(components[i]); } } } internal static void LogComponent(Component compo) { LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---"); PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (PropertyInfo propertyInfo in properties) { try { LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}"); } catch { LogWarning("Failed to get value for " + propertyInfo.Name); } } FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (FieldInfo fieldInfo in fields) { try { LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}"); } catch { LogWarning("Failed to get value for " + fieldInfo.Name); } } } } } namespace ToolTweaks.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 = 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 fi in type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy) where fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(T) select fi into x select (T)x.GetRawConstantValue()).ToList(); } internal static List<T> GetAllPublicStaticValues<T>(this Type type) { return (from fi in type.GetFields(BindingFlags.Static | BindingFlags.Public) where fi.FieldType == typeof(T) select fi into x 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 = 1) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Utils.FindChild(transform, childName, searchType); } } } namespace ToolTweaks.Configs { internal static class ConfigManager { private static string ConfigFileName; private static string ConfigFileFullPath; private static ConfigFile configFile; private static BaseUnityPlugin ConfigurationManager; private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager"; private static readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes { IsAdminOnly = true }; private static readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes { IsAdminOnly = false }; private const char ZWS = '\u200b'; internal static event Action OnConfigWindowClosed; internal static event Action OnConfigFileReloaded; private static void InvokeOnConfigWindowClosed() { ConfigManager.OnConfigWindowClosed?.SafeInvoke(); } private static void InvokeOnConfigFileReloaded() { ConfigManager.OnConfigFileReloaded?.SafeInvoke(); } internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown string extendedDescription = GetExtendedDescription(description, synced); return configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { synced ? AdminConfig : ClientConfig })); } internal static string SetStringPriority(string sectionName, int priority) { if (priority == 0) { return sectionName; } return new string('\u200b', priority) + sectionName; } internal static string GetExtendedDescription(string description, bool synchronizedSetting) { return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"); } internal static void Init(string GUID, ConfigFile config, bool saveOnConfigSet = false) { configFile = config; configFile.SaveOnConfigSet = saveOnConfigSet; ConfigFileName = GUID + ".cfg"; ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName; } private static bool DisableSaveOnConfigSet() { bool saveOnConfigSet = configFile.SaveOnConfigSet; configFile.SaveOnConfigSet = false; return saveOnConfigSet; } internal static void SaveOnConfigSet(bool value) { configFile.SaveOnConfigSet = value; } internal static void Save() { configFile.Save(); } internal static void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReloadConfigFile; fileSystemWatcher.Created += ReloadConfigFile; fileSystemWatcher.Renamed += ReloadConfigFile; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private static void ReloadConfigFile(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { Log.LogInfo("Reloading config file"); bool value = DisableSaveOnConfigSet(); configFile.Reload(); SaveOnConfigSet(value); InvokeOnConfigFileReloaded(); } catch { Log.LogError("There was an issue loading your " + ConfigFileName); Log.LogError("Please check your config entries for spelling and format!"); } } internal static void CheckForConfigManager() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType != 4 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance)) { ConfigurationManager = value.Instance; Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged"); EventInfo @event = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged"); if (@event != null) { Action<object, object> action = OnConfigManagerDisplayingWindowChanged; Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method); @event.AddEventHandler(ConfigurationManager, handler); } } } private static void OnConfigManagerDisplayingWindowChanged(object sender, object e) { if (!(bool)((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow").GetValue(ConfigurationManager, null)) { InvokeOnConfigWindowClosed(); } } } }