Please disclose if your mod was created primarily 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 PutMeDown v1.2.0
PutMeDown.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 ComfyLib; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("PutMeDown")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PutMeDown")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("287bf250-ae87-4283-867b-9c9351e408fc")] [assembly: AssemblyFileVersion("1.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] namespace PutMeDown { public static class PluginConfig { private static readonly List<ToggleStringListConfigEntry> _itemsToIgnoreConfigs = new List<ToggleStringListConfigEntry>(); private static int _itemsToIgnoreConfigIndex = -1; private static ToggleStringListConfigEntry _itemsToIgnoreConfig = null; public static ConfigEntry<bool> IsModEnabled { get; private set; } public static ToggleStringListConfigEntry ItemsToIgnore { get; private set; } public static ConfigEntry<KeyboardShortcut> ItemsToIgnoreCycleShortcut { get; private set; } public static ToggleStringListConfigEntry ItemsToIgnoreAlt1 { get; private set; } public static ToggleStringListConfigEntry ItemsToIgnoreAlt2 { get; private set; } [ComfyConfig] public static void BindConfig(ConfigFile config) { IsModEnabled = config.BindInOrder("_Global", "isModEnabled", defaultValue: true, "Globally enable or disable this mod."); } [ComfyConfig(LateBind = true)] public static void BindAutoPickupConfig(ConfigFile config) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) _itemsToIgnoreConfigs.Clear(); _itemsToIgnoreConfigIndex = -1; ItemsToIgnore = new ToggleStringListConfigEntry(config, "AutoPickup", "itemsToIgnore", "Wood=0,Stone=0", "Items to ignore for auto-pickup behaviour (normal config).", GetItemDropSearchOptions); _itemsToIgnoreConfigs.Add(ItemsToIgnore); ItemsToIgnore.SettingChanged += OnItemsToIgnoreChanged; ItemsToIgnoreCycleShortcut = config.BindInOrder<KeyboardShortcut>("AutoPickup.Alt", "itemsToIgnoreCycleShortcut", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), "Shortcut to cycle through ItemsToIgnore normal and alternate configs."); ItemsToIgnoreAlt1 = new ToggleStringListConfigEntry(config, "AutoPickup.Alt", "itemsToIgnoreAlt1", "Wood=0,Stone=0", "Items to ignore for auto-pickup behaviour (alternate config 1).", GetItemDropSearchOptions); _itemsToIgnoreConfigs.Add(ItemsToIgnoreAlt1); ItemsToIgnoreAlt1.SettingChanged += OnItemsToIgnoreChanged; ItemsToIgnoreAlt2 = new ToggleStringListConfigEntry(config, "AutoPickup.Alt", "itemsToIgnoreAlt2", "Wood=0,Stone=0", "Items to ignore for auto-pickup behaviour (alternate config 2).", GetItemDropSearchOptions); _itemsToIgnoreConfigs.Add(ItemsToIgnoreAlt2); ItemsToIgnoreAlt2.SettingChanged += OnItemsToIgnoreChanged; CycleItemsToIgnoreConfig(); } public static void CycleItemsToIgnoreConfig() { _itemsToIgnoreConfigIndex++; if (_itemsToIgnoreConfigIndex < 0 || _itemsToIgnoreConfigIndex >= _itemsToIgnoreConfigs.Count) { _itemsToIgnoreConfigIndex = 0; } _itemsToIgnoreConfig = _itemsToIgnoreConfigs[_itemsToIgnoreConfigIndex]; AutoPickupController.SetItemsToIgnore(_itemsToIgnoreConfig.ToggledStringValues()); } private static void OnItemsToIgnoreChanged(object sender, IEnumerable<string> itemsToIgnore) { if (sender == _itemsToIgnoreConfig) { AutoPickupController.SetItemsToIgnore(itemsToIgnore); } } public static IEnumerable<ToggleStringListConfigEntry.SearchOption> GetItemDropSearchOptions() { ItemDrop val = default(ItemDrop); return from item in ObjectDB.m_instance.m_items where item.TryGetComponent<ItemDrop>(ref val) && val.m_autoPickup && val.m_itemData.m_shared.m_icons.Length != 0 && !string.IsNullOrEmpty(val.m_itemData.m_shared.m_description) select new ToggleStringListConfigEntry.SearchOption(((Object)item).name, Localization.m_instance.Localize(item.GetComponent<ItemDrop>().m_itemData.m_shared.m_name) + " (" + ((Object)item).name + ")"); } } public static class AutoPickupController { private static readonly HashSet<string> _itemsToIgnore = new HashSet<string>(); public static void SetItemsToIgnore(IEnumerable<string> itemsToIgnore) { _itemsToIgnore.Clear(); _itemsToIgnore.UnionWith(itemsToIgnore); PutMeDown.LogInfo(string.Format("Ignoring {0} items: {1}", _itemsToIgnore.Count, string.Join(", ", _itemsToIgnore))); } public static bool ShouldIgnoreItem(ItemDrop itemDrop) { return _itemsToIgnore.Contains(((Object)itemDrop.m_itemData.m_dropPrefab).name); } } [HarmonyPatch(typeof(Player))] internal static class PlayerPatch { [HarmonyTranspiler] [HarmonyPatch("AutoPickup")] private static IEnumerable<CodeInstruction> AutoPickupTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown CodeInstruction instruction; return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(ItemDrop), "m_autoPickup"), (string)null) }).ThrowIfInvalid("Could not patch Player.AutoPickup()! (m_autoPickup)").CopyInstruction(out instruction) .Advance(2) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { instruction, Transpilers.EmitDelegate<Func<bool, ItemDrop, bool>>((Func<bool, ItemDrop, bool>)AutoPickupDelegate) }) .InstructionEnumeration(); } private static CodeMatcher CopyInstruction(this CodeMatcher matcher, out CodeInstruction instruction) { instruction = matcher.Instruction; return matcher; } private static bool AutoPickupDelegate(bool autoPickup, ItemDrop itemDrop) { if (autoPickup && PluginConfig.IsModEnabled.Value && AutoPickupController.ShouldIgnoreItem(itemDrop)) { return false; } return autoPickup; } [HarmonyTranspiler] [HarmonyPatch("Update")] private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Player), "UpdateHover", (Type[])null, (Type[])null), (string)null) }).ThrowIfInvalid("Could not patch Player.Update()! (UpdateHover)").Advance(2) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldloc_1, (object)null), Transpilers.EmitDelegate<Action<bool>>((Action<bool>)UpdateHoverPostDelegate) }) .InstructionEnumeration(); } private static void UpdateHoverPostDelegate(bool takeInput) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (takeInput && PluginConfig.IsModEnabled.Value) { KeyboardShortcut value = PluginConfig.ItemsToIgnoreCycleShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { PluginConfig.CycleItemsToIgnoreConfig(); } } } } [BepInPlugin("redseiko.valheim.putmedown", "PutMeDown", "1.2.0")] public sealed class PutMeDown : BaseUnityPlugin { public const string PluginGuid = "redseiko.valheim.putmedown"; public const string PluginName = "PutMeDown"; public const string PluginVersion = "1.2.0"; private static ManualLogSource _logger; private Harmony _harmony; private void Awake() { _logger = ((BaseUnityPlugin)this).Logger; ComfyConfigUtils.BindConfig(((BaseUnityPlugin)this).Config); _harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "redseiko.valheim.putmedown"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } public static void LogInfo(object obj) { _logger.LogInfo((object)$"[{DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo)}] {obj}"); Chat.m_instance.AddMessage(obj); } } } namespace ComfyLib { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class ComfyConfigAttribute : Attribute { public bool LateBind { get; set; } } public static class ComfyConfigUtils { [HarmonyPatch] private static class ComfyConfigBinder { private static readonly Queue<Action> _lateBindQueue = new Queue<Action>(); private static bool _startupPatched = false; public static void Bind(ConfigFile config, MethodInfo method, ComfyConfigAttribute attribute) { if (!attribute.LateBind || _startupPatched) { method.Invoke(null, new object[1] { config }); return; } _lateBindQueue.Enqueue(delegate { method.Invoke(null, new object[1] { config }); }); } [HarmonyPatch(typeof(FejdStartup), "Start")] private static void Postfix() { while (_lateBindQueue.Count > 0) { _lateBindQueue.Dequeue()?.Invoke(); } _startupPatched = true; } } public static void BindConfig(ConfigFile config) { BindConfigs(config, Assembly.GetExecutingAssembly()); } private static void BindConfigs(ConfigFile config, Assembly assembly) { foreach (var (method, attribute) in GetBindConfigMethods(assembly)) { ComfyConfigBinder.Bind(config, method, attribute); } } private static IEnumerable<(MethodInfo, ComfyConfigAttribute)> GetBindConfigMethods(Assembly assembly) { return assembly.GetTypes().SelectMany((Type type) => type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)).SelectMany((MethodInfo method) => GetBindConfigMethod(method)); } private static IEnumerable<(MethodInfo, ComfyConfigAttribute)> GetBindConfigMethod(MethodInfo method) { ComfyConfigAttribute customAttribute = method.GetCustomAttribute<ComfyConfigAttribute>(inherit: false); if (customAttribute != null) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(ConfigFile)) { yield return (method, customAttribute); } } } } public sealed class ToggleStringListConfigEntry { public sealed class SearchOption { public string OptionValue = string.Empty; public string DisplayValue = string.Empty; public SearchOption(string optionValue) : this(optionValue, optionValue) { } public SearchOption(string optionValue, string displayValue) { OptionValue = optionValue; DisplayValue = displayValue; } } public sealed class AutoCompleteBox { private readonly Func<IEnumerable<SearchOption>> _searchOptionsFunc; private List<SearchOption> _options; private readonly List<SearchOption> _currentOptions; private string _value; private Vector2 _scrollPosition; public AutoCompleteBox(Func<IEnumerable<SearchOption>> searchOptionsFunc) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) _searchOptionsFunc = searchOptionsFunc; _options = null; _currentOptions = new List<SearchOption>(); _value = string.Empty; _scrollPosition = Vector2.zero; } public string DrawBox(string value) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (_value != value) { _value = value; _currentOptions.Clear(); if (!string.IsNullOrEmpty(value)) { if (_options == null) { _options = new List<SearchOption>(_searchOptionsFunc()); } _currentOptions.AddRange(_options.Where((SearchOption option) => option.DisplayValue.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) >= 0 || option.OptionValue.StartsWith(value, StringComparison.InvariantCultureIgnoreCase))); } _scrollPosition = Vector2.zero; } if (string.IsNullOrEmpty(_value)) { return string.Empty; } return DrawCurrentOptions(); } private string DrawCurrentOptions() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(120f) }); string result = string.Empty; foreach (SearchOption currentOption in _currentOptions) { if (GUILayout.Button(currentOption.DisplayValue, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(40f) })) { result = currentOption.OptionValue; } } GUILayout.EndScrollView(); return result; } } public readonly ConfigEntry<string> BaseConfigEntry; private readonly AutoCompleteBox _autoCompleteLabel; private static readonly char[] _valueSeparator = new char[1] { ',' }; private static readonly char[] _toggleSeperator = new char[1] { '=' }; private readonly List<string> _valuesCache = new List<string>(); private string _valueText = string.Empty; public event EventHandler<string[]> SettingChanged; public ToggleStringListConfigEntry(ConfigFile config, string section, string key, string defaultValue, string description, Func<IEnumerable<SearchOption>> autoCompleteFunc = null) { BaseConfigEntry = config.BindInOrder(section, key, defaultValue, description, Drawer, browsable: true, hideDefaultButton: false, hideSettingName: false); BaseConfigEntry.SettingChanged += OnBaseSettingChanged; if (autoCompleteFunc != null) { _autoCompleteLabel = new AutoCompleteBox(autoCompleteFunc); } } private void OnBaseSettingChanged(object sender, EventArgs eventArgs) { this.SettingChanged?.Invoke(this, ToggledStringValues()); } public string[] ToggledStringValues() { _valuesCache.Clear(); string[] array = BaseConfigEntry.Value.Split(_valueSeparator, StringSplitOptions.RemoveEmptyEntries); int i = 0; for (int num = array.Length; i < num; i++) { string[] array2 = array[i].Split(_toggleSeperator, 2, StringSplitOptions.RemoveEmptyEntries); if (array2.Length >= 2 && array2[1] == "1") { _valuesCache.Add(array2[0]); } } return _valuesCache.ToArray(); } public void Drawer(ConfigEntryBase configEntry) { GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); _valuesCache.Clear(); _valuesCache.AddRange(configEntry.BoxedValue.ToString().Split(_valueSeparator, StringSplitOptions.RemoveEmptyEntries)); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); bool flag = GUILayout.Button("Toggle On", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); bool flag2 = GUILayout.Button("Toggle Off", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.EndHorizontal(); bool flag3 = false; int num = -1; int i = 0; for (int count = _valuesCache.Count; i < count; i++) { string[] array = _valuesCache[i].Split(_toggleSeperator, 2, StringSplitOptions.RemoveEmptyEntries); bool flag4 = array.Length >= 2 && array[1] == "1"; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); bool flag5 = GUILayout.Toggle(flag4, array[0], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("−", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.MinWidth(40f), GUILayout.ExpandWidth(false) })) { num = i; } GUILayout.EndHorizontal(); if (flag) { flag5 = true; } else if (flag2) { flag5 = false; } if (flag5 != flag4) { flag3 = true; _valuesCache[i] = array[0] + (flag5 ? "=1" : "=0"); } } GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); _valueText = GUILayout.TextField(_valueText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.Space(3f); if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.MinWidth(40f), GUILayout.ExpandWidth(false) }) && !string.IsNullOrWhiteSpace(_valueText) && _valueText.IndexOf('=') < 0) { _valuesCache.Add(_valueText + "=1"); _valueText = string.Empty; flag3 = true; } GUILayout.EndHorizontal(); if (_autoCompleteLabel != null) { string text = _autoCompleteLabel.DrawBox(_valueText); if (!string.IsNullOrEmpty(text)) { _valuesCache.Add(text + "=1"); flag3 = true; } } GUILayout.EndVertical(); if (num >= 0) { _valuesCache.RemoveAt(num); flag3 = true; } if (flag3) { configEntry.BoxedValue = string.Join(",", _valuesCache); } } } public static class ConfigFileExtensions { internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public bool? HideDefaultButton; public int? Order; } private static readonly Dictionary<string, int> _sectionToSettingOrder = new Dictionary<string, int>(); private static int GetSettingOrder(string section) { if (!_sectionToSettingOrder.TryGetValue(section, out var value)) { value = 0; } _sectionToSettingOrder[section] = value - 1; return value; } public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, new object[1] { new ConfigurationManagerAttributes { Order = GetSettingOrder(section) } })); } public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, Action<ConfigEntryBase> customDrawer = null, bool browsable = true, bool hideDefaultButton = false, bool hideSettingName = false) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = browsable, CustomDrawer = customDrawer, HideDefaultButton = hideDefaultButton, Order = GetSettingOrder(section) } })); } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action settingChangedHandler) { configEntry.SettingChanged += delegate { settingChangedHandler(); }; } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<T> settingChangedHandler) { configEntry.SettingChanged += delegate(object _, EventArgs eventArgs) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) settingChangedHandler((T)((SettingChangedEventArgs)eventArgs).ChangedSetting.BoxedValue); }; } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<ConfigEntry<T>> settingChangedHandler) { configEntry.SettingChanged += delegate(object _, EventArgs eventArgs) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) settingChangedHandler((ConfigEntry<T>)((SettingChangedEventArgs)eventArgs).ChangedSetting.BoxedValue); }; } } public static class ChatExtensions { public static void AddMessage(this Chat chat, object obj) { if (Object.op_Implicit((Object)(object)chat)) { ((Terminal)chat).AddString($"{obj}"); chat.m_hideTimer = 0f; } } } public static class ObjectExtensions { public static T Ref<T>(this T unityObject) where T : Object { if (!Object.op_Implicit((Object)(object)unityObject)) { return default(T); } return unityObject; } } }