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 SlotLock v1.0.0
SlotLock.dll
Decompiled 7 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SlotLock")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ac116c7ad154ffac2a734a643bb1d5aec87d19a5")] [assembly: AssemblyProduct("SlotLock")] [assembly: AssemblyTitle("SlotLock")] [assembly: AssemblyVersion("1.0.0.0")] [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 SlotLock { internal static class LockedSlots { private const long NoProfile = long.MinValue; private static readonly HashSet<Vector2i> Explicit = new HashSet<Vector2i>(); private static long _loadedPlayerId = long.MinValue; private static string _path; internal static bool Empty { get { EnsureLoaded(); if (Explicit.Count == 0) { return !ModConfig.ProtectHotbarRow.Value; } return false; } } private static string Directory => Path.Combine(Paths.ConfigPath, "SlotLock"); internal static bool IsLocked(Vector2i pos) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) EnsureLoaded(); if (ModConfig.ProtectHotbarRow.Value && pos.y == 0) { return true; } return Explicit.Contains(pos); } internal static void Toggle(Vector2i pos) { //IL_001b: 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_0028: Unknown result type (might be due to invalid IL or missing references) EnsureLoaded(); if (_loadedPlayerId != long.MinValue) { bool flag; if (Explicit.Contains(pos)) { Explicit.Remove(pos); flag = false; } else { Explicit.Add(pos); flag = true; } Save(); SlotLockPlugin.Log.LogInfo((object)("Slot (" + pos.x + "," + pos.y + ") " + (flag ? "locked" : "unlocked") + ".")); } } private static void EnsureLoaded() { string name; long num = CurrentPlayerId(out name); if (num != _loadedPlayerId) { Explicit.Clear(); _loadedPlayerId = num; _path = null; if (num != long.MinValue) { _path = Path.Combine(Directory, Sanitize(name) + "_" + num.ToString(CultureInfo.InvariantCulture) + ".txt"); Load(); } } } private static long CurrentPlayerId(out string name) { name = null; try { Game instance = Game.instance; if ((Object)(object)instance == (Object)null) { return long.MinValue; } PlayerProfile playerProfile = instance.GetPlayerProfile(); if (playerProfile == null) { return long.MinValue; } name = playerProfile.GetName(); return playerProfile.GetPlayerID(); } catch (Exception) { return long.MinValue; } } private static void Load() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) try { if (!File.Exists(_path)) { return; } string[] array = File.ReadAllLines(_path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && text[0] != '#') { string[] array2 = text.Split(','); if (array2.Length == 2 && int.TryParse(array2[0].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { Explicit.Add(new Vector2i(result, result2)); } } } SlotLockPlugin.Log.LogInfo((object)("Loaded " + Explicit.Count + " locked slot(s) from " + Path.GetFileName(_path) + ".")); } catch (Exception ex) { SlotLockPlugin.Log.LogError((object)("Could not read locked slots from " + _path + ": " + ex.Message)); } } private static void Save() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (_path == null) { return; } try { System.IO.Directory.CreateDirectory(Directory); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# SlotLock - one \"x,y\" inventory grid position per line."); stringBuilder.AppendLine("# x is the column and y the row, both zero-based, row 0 being the hotbar."); foreach (Vector2i item in Explicit) { stringBuilder.Append(item.x.ToString(CultureInfo.InvariantCulture)).Append(',').AppendLine(item.y.ToString(CultureInfo.InvariantCulture)); } File.WriteAllText(_path, stringBuilder.ToString()); } catch (Exception ex) { SlotLockPlugin.Log.LogError((object)("Could not save locked slots to " + _path + ": " + ex.Message)); } } private static string Sanitize(string name) { if (string.IsNullOrEmpty(name)) { return "character"; } StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { stringBuilder.Append((Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0) ? '_' : c); } return stringBuilder.ToString(); } } internal static class ModConfig { internal static ConfigEntry<KeyCode> ToggleModifier; internal static ConfigEntry<bool> ShowOverlay; internal static ConfigEntry<Color> OverlayColor; internal static ConfigEntry<bool> ProtectHotbarRow; internal static ConfigEntry<float> OverlayThickness; internal static ConfigEntry<bool> VerboseLogging; internal static void Bind(ConfigFile cfg) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown ToggleModifier = cfg.Bind<KeyCode>("1 - Controls", "ToggleModifier", (KeyCode)308, "Hold this key and left-click an inventory slot to lock or unlock it."); ProtectHotbarRow = cfg.Bind<bool>("2 - Behaviour", "ProtectHotbarRow", false, "Treat the whole hotbar (the top row of your inventory) as locked, on top of any slots you lock by hand."); ShowOverlay = cfg.Bind<bool>("3 - Appearance", "ShowOverlay", true, "Draw a coloured frame over locked slots."); OverlayColor = cfg.Bind<Color>("3 - Appearance", "OverlayColor", new Color(1f, 0.78f, 0.23f, 0.85f), "Colour of that frame."); OverlayThickness = cfg.Bind<float>("3 - Appearance", "OverlayThickness", 3f, new ConfigDescription("Thickness of that frame, in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); VerboseLogging = cfg.Bind<bool>("4 - Debug", "VerboseLogging", false, "Log every item withheld from a quick-stack. Noisy; for troubleshooting only."); } } [BepInPlugin("introvertedcats.slotlock", "SlotLock", "1.0.0")] [BepInProcess("valheim.exe")] public class SlotLockPlugin : BaseUnityPlugin { private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); VerifyPatchTargets(); _harmony = new Harmony("introvertedcats.slotlock"); _harmony.PatchAll(typeof(SlotLockPlugin).Assembly); Log.LogInfo((object)"SlotLock 1.0.0 loaded."); } private static void VerifyPatchTargets() { Expect(typeof(Inventory), "StackAll", new Type[2] { typeof(Inventory), typeof(bool) }); Expect(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }); Expect(typeof(InventoryGrid), "OnLeftDown", new Type[1] { typeof(UIInputHandler) }); Expect(typeof(InventoryGrid), "UpdateGui", new Type[2] { typeof(Player), typeof(ItemData) }); } private static void Expect(Type type, string method, Type[] parameters) { if (AccessTools.Method(type, method, parameters, (Type[])null) == null) { Log.LogError((object)(type.Name + "." + method + " was not found. This build of SlotLock is out of date for this version of Valheim; that feature will not work.")); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PluginInfo { public const string Guid = "introvertedcats.slotlock"; public const string Name = "SlotLock"; public const string Version = "1.0.0"; } } namespace SlotLock.Patches { [HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")] internal static class InventoryGrid_OnLeftDown_Patch { private static bool Prefix(InventoryGrid __instance, UIInputHandler clickHandler) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)clickHandler == (Object)null) { return true; } if (!ZInput.GetKey(ModConfig.ToggleModifier.Value, false)) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } if (__instance.GetInventory() != ((Humanoid)localPlayer).GetInventory()) { return true; } InventoryElement component = ((Component)clickHandler).GetComponent<InventoryElement>(); if ((Object)(object)component == (Object)null) { return true; } LockedSlots.Toggle(component.Position); return false; } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGrid_UpdateGui_Patch { private const string OverlayName = "SlotLock_Indicator"; private static bool _loggedAttach; private static void Postfix(InventoryGrid __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || __instance.GetInventory() != ((Humanoid)localPlayer).GetInventory()) { return; } bool value = ModConfig.ShowOverlay.Value; Color value2 = ModConfig.OverlayColor.Value; int num = 0; InventoryElement[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<InventoryElement>(true); foreach (InventoryElement val in componentsInChildren) { GameObject orCreateOverlay = GetOrCreateOverlay(val); if ((Object)(object)orCreateOverlay == (Object)null) { continue; } num++; bool flag = value && LockedSlots.IsLocked(val.Position); if (orCreateOverlay.activeSelf != flag) { orCreateOverlay.SetActive(flag); } if (flag) { Image[] componentsInChildren2 = orCreateOverlay.GetComponentsInChildren<Image>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { ((Graphic)componentsInChildren2[j]).color = value2; } } } if (!_loggedAttach && num > 0) { _loggedAttach = true; SlotLockPlugin.Log.LogInfo((object)("Lock border attached to " + num + " inventory slot(s).")); } } private static GameObject GetOrCreateOverlay(InventoryElement element) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_0109: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown Transform val = ((Component)element).transform.Find("SlotLock_Indicator"); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject; } GameObject val2 = new GameObject("SlotLock_Indicator", new Type[1] { typeof(RectTransform) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(((Component)element).transform, false); val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; float value = ModConfig.OverlayThickness.Value; AddEdge(val3, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, value)); AddEdge(val3, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, value)); AddEdge(val3, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2(value, 0f)); AddEdge(val3, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(1f, 0.5f), new Vector2(value, 0f)); val2.transform.SetAsLastSibling(); val2.SetActive(false); return val2; } private static void AddEdge(RectTransform parent, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 size) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Edge", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent((Transform)(object)parent, false); val2.anchorMin = anchorMin; val2.anchorMax = anchorMax; val2.pivot = pivot; val2.anchoredPosition = Vector2.zero; val2.sizeDelta = size; Image component = val.GetComponent<Image>(); ((Graphic)component).raycastTarget = false; ((Behaviour)component).enabled = true; } } [HarmonyPatch(typeof(Inventory), "StackAll", new Type[] { typeof(Inventory), typeof(bool) })] internal static class Inventory_StackAll_Patch { private static readonly MethodInfo ChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); private static void NotifyChanged(Inventory inventory) { if (ChangedMethod != null) { ChangedMethod.Invoke(inventory, new object[2] { false, false }); } else { SlotLockPlugin.Log.LogWarning((object)"Inventory.Changed(bool, bool) not found; falling back to m_onChanged."); inventory.m_onChanged?.Invoke(); } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(Inventory fromInventory, out List<ItemData> __state) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) __state = null; Player localPlayer = Player.m_localPlayer; if (fromInventory == null || (Object)(object)localPlayer == (Object)null || fromInventory != ((Humanoid)localPlayer).GetInventory() || LockedSlots.Empty) { return; } List<ItemData> allItems = fromInventory.GetAllItems(); List<ItemData> list = null; for (int num = allItems.Count - 1; num >= 0; num--) { ItemData val = allItems[num]; if (val != null && LockedSlots.IsLocked(val.m_gridPos)) { if (list == null) { list = new List<ItemData>(); } list.Add(val); allItems.RemoveAt(num); } } __state = list; if (list != null && ModConfig.VerboseLogging.Value) { SlotLockPlugin.Log.LogInfo((object)("Withheld " + list.Count + " item(s) in locked slots from a quick-stack.")); } } [HarmonyFinalizer] private static void Finalizer(Inventory fromInventory, List<ItemData> __state) { if (__state == null || fromInventory == null) { return; } List<ItemData> allItems = fromInventory.GetAllItems(); for (int num = __state.Count - 1; num >= 0; num--) { ItemData val = __state[num]; if (val != null && !allItems.Contains(val)) { allItems.Add(val); } } NotifyChanged(fromInventory); } } }