Decompiled source of SlotLock v1.0.0

SlotLock.dll

Decompiled 7 hours ago
using 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);
		}
	}
}