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 Quads Gear Slots v1.3.1
plugins/GearSlots.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DHack.Shared; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code).")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.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 GearSlots { internal static class Compat { private static readonly string[][] SlotMods = new string[5][] { new string[2] { "shudnal.ExtraSlots", "ExtraSlots" }, new string[2] { "randyknapp.mods.equipmentandquickslots", "Equipment and Quick Slots" }, new string[2] { "Azumatt.AzuExtendedPlayerInventory", "AzuExtendedPlayerInventory" }, new string[2] { "aedenthorn.ExtendedPlayerInventory", "Extended Player Inventory" }, new string[2] { "com.bruce.valheim.comfyquickslots", "ComfyQuickSlots" } }; private const string BetterArchery = "ishid4.mods.betterarchery"; private static bool _checked; private static string _reason; public static string StandDownFor { get { if (!_checked && (Object)(object)Player.m_localPlayer != (Object)null) { _checked = true; _reason = Find(); if (_reason != null) { Layout.ForgetNormalRows(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)(_reason + " is installed and keeps its own slots in the same inventory cells: the gear slots are off")); } } } return _reason; } } public static bool StandingDown => StandDownFor != null; private static string Find() { string[][] slotMods = SlotMods; foreach (string[] array in slotMods) { if (Chainloader.PluginInfos.ContainsKey(array[0])) { return array[1]; } } if (Chainloader.PluginInfos.TryGetValue("ishid4.mods.betterarchery", out var value)) { ConfigEntry<bool> val = null; if (!((Object)(object)value.Instance != (Object)null) || !value.Instance.Config.TryGetEntry<bool>("Quiver", "Enable Quiver", ref val) || val.Value) { return "BetterArchery (its quiver)"; } } return null; } } internal static class GameKeys { private static readonly HashSet<string> Essential = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Forward", "Backward", "Left", "Right", "Use", "Jump", "Inventory", "Tab", "Escape", "Map", "Chat", "Run", "Crouch", "Attack", "SecondaryAttack", "Block", "AltPlace", "LShift", "Console", "BuildMenu", "Remove", "MapZoomIn", "MapZoomOut", "Hotbar1", "Hotbar2", "Hotbar3", "Hotbar4", "Hotbar5", "Hotbar6", "Hotbar7", "Hotbar8", "TabRight", "ChatUp", "ChatDown" }; private unsafe static string PathOf(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected I4, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected I4, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Invalid comparison between Unknown and I4 //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected I4, but got Unknown if ((int)key >= 97 && (int)key <= 122) { return "<Keyboard>/" + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); } if ((int)key >= 48 && (int)key <= 57) { return "<Keyboard>/" + (key - 48); } if ((int)key >= 282 && (int)key <= 293) { return "<Keyboard>/" + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); } if ((int)key <= 279) { if ((int)key == 96) { return "<Keyboard>/backquote"; } if ((int)key == 127) { return "<Keyboard>/delete"; } switch (key - 277) { case 0: return "<Keyboard>/insert"; case 1: return "<Keyboard>/home"; case 2: return "<Keyboard>/end"; } } else { switch (key - 304) { default: if ((int)key != 326) { if ((int)key != 327) { break; } return "<Mouse>/forwardButton"; } return "<Mouse>/backButton"; case 4: return "<Keyboard>/leftAlt"; case 3: return "<Keyboard>/rightAlt"; case 2: return "<Keyboard>/leftCtrl"; case 0: return "<Keyboard>/leftShift"; case 1: break; } } return null; } public static List<string> Free(string owner, IEnumerable<KeyValuePair<KeyCode, string>> keys) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Invalid comparison between Unknown and I4 //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); ZInput instance = ZInput.instance; if (instance == null) { return list; } if (!(AccessTools.Field(typeof(ZInput), "m_buttons")?.GetValue(instance) is Dictionary<string, ButtonDef> dictionary)) { return list; } string text = "DHack.FreedGameKeys." + owner; HashSet<string> hashSet = new HashSet<string>(PlayerPrefs.GetString(text, "").Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries)); bool flag = false; foreach (KeyValuePair<KeyCode, string> key in keys) { string text2 = PathOf(key.Key); if (text2 == null) { continue; } foreach (ButtonDef item2 in dictionary.Values.ToList()) { if (item2 == null || !item2.Rebindable || (int)item2.Source == 180 || !string.Equals(item2.GetActionPath(true), text2, StringComparison.OrdinalIgnoreCase)) { continue; } if (Essential.Contains(item2.Name)) { Debug.LogWarning((object)$"[{owner}] {key.Key} ({key.Value}) is also the game's {item2.Name} key; that one is left as it is. Choose another key in the mod's settings."); continue; } string item = item2.Name + ":" + text2.ToLowerInvariant(); if (!hashSet.Contains(item)) { item2.Rebind(""); hashSet.Add(item); flag = true; list.Add(Translations.T("gearslots_key_unbound", owner, key.Key, key.Value, Nice(item2.Name))); } } } if (flag) { instance.Save(); PlayerPrefs.SetString(text, string.Join("|", hashSet.ToArray())); PlayerPrefs.Save(); foreach (string item3 in list) { Debug.Log((object)("[" + owner + "] " + item3)); } } return list; } public static List<string> GiveBack(string owner, IEnumerable<KeyCode> inUse) { List<string> list = new List<string>(); ZInput instance = ZInput.instance; if (instance == null) { return list; } if (!(AccessTools.Field(typeof(ZInput), "m_buttons")?.GetValue(instance) is Dictionary<string, ButtonDef> dictionary)) { return list; } string text = "DHack.FreedGameKeys." + owner; HashSet<string> hashSet = new HashSet<string>(PlayerPrefs.GetString(text, "").Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries)); HashSet<string> hashSet2 = new HashSet<string>(from p in inUse.Select(PathOf) where p != null select p.ToLowerInvariant()); bool flag = false; foreach (string item in hashSet.ToList()) { int num = item.IndexOf(':'); if (num <= 0) { continue; } string text2 = item.Substring(0, num); string text3 = item.Substring(num + 1); if (!hashSet2.Contains(text3)) { hashSet.Remove(item); flag = true; if (dictionary.TryGetValue(text2, out var value) && value != null && string.IsNullOrEmpty(value.GetActionPath(true))) { value.Rebind(text3); list.Add(Translations.T("gearslots_key_back", owner, Nice(text2), text3.Substring(text3.IndexOf('/') + 1).ToUpperInvariant())); } } } if (flag) { instance.Save(); PlayerPrefs.SetString(text, string.Join("|", hashSet.ToArray())); PlayerPrefs.Save(); foreach (string item2 in list) { Debug.Log((object)("[" + owner + "] " + item2)); } } return list; } private static string Nice(string name) { return name switch { "AutoPickup" => Localization.instance.Localize("$settings_autopickup"), "ToggleWalk" => Localization.instance.Localize("$settings_walk"), "AutoRun" => Localization.instance.Localize("$settings_autorun"), "OpenRadial" => Localization.instance.Localize("$settings_open_radial"), "TabLeft" => Translations.T("gearslots_action_tableft"), "OpenEmote" => Localization.instance.Localize("$settings_open_emote_wheel"), "GP" => Localization.instance.Localize("$settings_gp"), "Sit" => Localization.instance.Localize("$settings_sit"), _ => name, }; } } internal class Hotbar { private class Cell { public GameObject Go; public Image Icon; public GuiBar Durability; public TMP_Text Amount; public TMP_Text Binding; public GameObject Equipped; public GameObject Queued; public int StackShown = -1; } private readonly List<Cell> _cells = new List<Cell>(); private RectTransform _messageText; private RectTransform _messageIcon; private Vector2 _textHome; private Vector2 _iconHome; private bool _messagesMoved; public void Update(Player player, Inventory inv) { //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) HotkeyBar val = (((Object)(object)Hud.instance != (Object)null) ? ((Component)Hud.instance).GetComponentInChildren<HotkeyBar>(true) : null); if ((Object)(object)val == (Object)null || (Object)(object)val.m_elementPrefab == (Object)null) { Destroy(); return; } if (_cells.Count != 5 || (Object)(object)_cells[0].Go == (Object)null) { Build(val); } bool flag = InventoryGui.IsVisible() || !Plugin.Instance.ShowQuickBar; bool flag2 = false; for (int i = 0; i < _cells.Count; i++) { Cell cell = _cells[i]; Slot slot = Layout.QuickSlot(i); ItemData val2 = ((slot != null) ? Layout.ItemIn(inv, slot) : null); bool flag3 = Plugin.Instance.QuickKeyName(i).Length > 0; cell.Go.SetActive(!flag && val2 != null && flag3); if (flag || val2 == null || !flag3) { continue; } flag2 = true; cell.Binding.text = (ZInput.IsGamepadActive() ? "" : Plugin.Instance.QuickKeyName(i)); ((Component)cell.Icon).gameObject.SetActive(true); cell.Icon.sprite = val2.GetIcon(); bool flag4 = val2.m_shared.m_useDurability && val2.m_durability < val2.GetMaxDurability(); ((Component)cell.Durability).gameObject.SetActive(flag4); if (flag4) { if (val2.m_durability <= 0f) { cell.Durability.SetValue(1f); cell.Durability.SetColor((Color)((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : new Color(0f, 0f, 0f, 0f))); } else { cell.Durability.SetValue(val2.GetDurabilityPercentage()); cell.Durability.ResetColor(); } } cell.Equipped.SetActive(val2.m_equipped); cell.Queued.SetActive(player.IsEquipActionQueued(val2)); bool flag5 = val2.m_shared.m_maxStackSize > 1; ((Component)cell.Amount).gameObject.SetActive(flag5); if (flag5 && cell.StackShown != val2.m_stack) { cell.Amount.text = $"{val2.m_stack} / {val2.m_shared.m_maxStackSize}"; cell.StackShown = val2.m_stack; } } MoveMessages(flag2 ? (val.m_elementSpace + 6f) : 0f); } private void MoveMessages(float drop) { //IL_0052: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) MessageHud instance = MessageHud.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_messageText == (Object)null) && !((Object)(object)instance.m_messageIcon == (Object)null)) { if ((Object)(object)_messageText == (Object)null) { _messageText = instance.m_messageText.rectTransform; _textHome = _messageText.anchoredPosition; _messageIcon = ((Graphic)instance.m_messageIcon).rectTransform; _iconHome = _messageIcon.anchoredPosition; } if (!(drop <= 0f) || _messagesMoved) { _messageText.anchoredPosition = _textHome + new Vector2(0f, 0f - drop); _messageIcon.anchoredPosition = _iconHome + new Vector2(0f, 0f - drop); _messagesMoved = drop > 0f; } } } private void Build(HotkeyBar bar) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) Destroy(); for (int i = 0; i < 5; i++) { Cell cell = new Cell { Go = Object.Instantiate<GameObject>(bar.m_elementPrefab, ((Component)bar).transform) }; ((Object)cell.Go).name = "GearSlotsQuick" + (i + 1); cell.Go.transform.localPosition = new Vector3((float)i * bar.m_elementSpace, 0f - bar.m_elementSpace, 0f); Transform transform = cell.Go.transform; cell.Binding = ((Component)transform.Find("binding")).GetComponent<TMP_Text>(); cell.Icon = ((Component)transform.Find("icon")).GetComponent<Image>(); cell.Durability = ((Component)transform.Find("durability")).GetComponent<GuiBar>(); cell.Amount = ((Component)transform.Find("amount")).GetComponent<TMP_Text>(); cell.Equipped = ((Component)transform.Find("equiped")).gameObject; cell.Queued = ((Component)transform.Find("queued")).gameObject; Transform val = transform.Find("selected"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } _cells.Add(cell); } } public void Destroy() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_messageText != (Object)null && _messagesMoved) { _messageText.anchoredPosition = _textHome; _messageIcon.anchoredPosition = _iconHome; } _messagesMoved = false; _messageText = (_messageIcon = null); foreach (Cell cell in _cells) { if ((Object)(object)cell.Go != (Object)null) { Object.Destroy((Object)(object)cell.Go); } } _cells.Clear(); } } internal static class Panel { private static readonly Color Gold = new Color(0.85f, 0.68f, 0.3f, 1f); private static readonly Color Dim = new Color(1f, 1f, 1f, 0.38f); private static RectTransform _panel; private static TMP_Text _title; private static readonly Dictionary<Slot, TMP_Text> Labels = new Dictionary<Slot, TMP_Text>(); private static readonly FieldRef<InventoryGrid, List<InventoryElement>> ElementsField = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements"); private const float Pad = 10f; private const float TitleHeight = 24f; private static readonly Color TitleColor = new Color(1f, 0.86f, 0.55f, 1f); public static void Update(InventoryGrid grid) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_player == (Object)null) { return; } List<InventoryElement> list = ElementsField.Invoke(grid); Inventory inventory = grid.GetInventory(); int width = inventory.GetWidth(); int normalRows = Layout.NormalRows; if (list == null || list.Count < width * (normalRows + 2) || (Object)(object)list[0] == (Object)null) { return; } grid.m_gridRoot.SetSizeWithCurrentAnchors((Axis)1, (float)normalRows * grid.m_elementSpace); bool showPanel = Plugin.Instance.ShowPanel; EnsurePanel(instance, list[0]); ((Component)_panel).gameObject.SetActive(showPanel); if ((Object)(object)_title != (Object)null) { _title.text = Translations.T("gearslots_title"); } float elementSpace = grid.m_elementSpace; ? val; Rect rect; if (!((Object)(object)list[0].GetElementRectTransform() != (Object)null)) { val = new Vector2(elementSpace - 6f, elementSpace - 6f); } else { rect = list[0].GetElementRectTransform().rect; val = ((Rect)(ref rect)).size; } Vector2 val2 = (Vector2)val; if (val2.x < 8f) { ((Vector2)(ref val2))..ctor(elementSpace - 6f, elementSpace - 6f); } for (int i = 0; i < 2; i++) { for (int j = 0; j < width; j++) { InventoryElement val3 = list[(normalRows + i) * width + j]; if ((Object)(object)val3 != (Object)null && Layout.At(j, normalRows + i) == null) { ((Component)val3).gameObject.SetActive(false); } } } Slot[] all = Layout.All; Vector2 val7 = default(Vector2); foreach (Slot slot in all) { InventoryElement val4 = list[(normalRows + slot.Row) * width + slot.Col]; if ((Object)(object)val4 == (Object)null) { continue; } Transform transform = ((Component)val4).transform; RectTransform val5 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if ((Object)(object)((Transform)val5).parent != (Object)(object)_panel) { rect = val5.rect; Vector2 val6; if (!(((Rect)(ref rect)).size.x > 8f)) { val6 = val2; } else { rect = val5.rect; val6 = ((Rect)(ref rect)).size; } Vector2 sizeDelta = val6; ((Transform)val5).SetParent((Transform)(object)_panel, false); ((Vector2)(ref val7))..ctor(0f, 1f); val5.anchorMax = val7; val5.anchorMin = val7; val5.pivot = new Vector2(0f, 1f); val5.sizeDelta = sizeDelta; ((Transform)val5).localScale = Vector3.one; } ((Component)val4).gameObject.SetActive(showPanel); val5.anchoredPosition = new Vector2(10f + (float)slot.Col * elementSpace, 0f - (34f + (float)slot.Row * elementSpace)); Transform val8 = ((Component)val4).transform.Find("binding"); TMP_Text val9 = (((Object)(object)val8 != (Object)null) ? ((Component)val8).GetComponent<TMP_Text>() : null); if ((Object)(object)val9 != (Object)null && (((Behaviour)val9).enabled = slot.Quick >= 0)) { val9.text = Plugin.Instance.QuickKeyName(slot.Quick); } if (!Labels.TryGetValue(slot, out var value) || (Object)(object)value == (Object)null) { value = (Labels[slot] = MakeLabel((Transform)(object)val5, slot.Name, val4.m_amount)); value.fontSize = 11f; value.enableAutoSizing = true; value.fontSizeMin = 7f; value.fontSizeMax = 11f; value.alignment = (TextAlignmentOptions)1026; rect = val5.rect; AddSilhouette((Transform)(object)val5, slot, ((Rect)(ref rect)).size); } Transform val11 = ((Transform)val5).Find("GearSlotsIcon"); if ((Object)(object)val11 != (Object)null) { ((Component)val11).gameObject.SetActive(Layout.ItemIn(inventory, slot) == null); } if ((Object)(object)value.transform.parent != (Object)(object)val5) { value.transform.SetParent((Transform)(object)val5, false); } value.text = slot.Name; ((Behaviour)value).enabled = Layout.ItemIn(inventory, slot) == null; } float num = 20f + 7f * elementSpace + val2.x; float num2 = 44f + 1f * elementSpace + val2.y; _panel.sizeDelta = new Vector2(num, num2); Place(instance.m_player, num, num2); } private static void EnsurePanel(InventoryGui gui, InventoryElement sample) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0145: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panel != (Object)null) { return; } GameObject val = new GameObject("GearSlotsPanel", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Outline) }); _panel = val.GetComponent<RectTransform>(); ((Transform)_panel).SetParent((Transform)(object)gui.m_player, false); ((Transform)_panel).SetAsFirstSibling(); _panel.pivot = new Vector2(0f, 1f); Image component = val.GetComponent<Image>(); Image val2 = FindWoodPanel(gui.m_player); Outline component2 = val.GetComponent<Outline>(); if ((Object)(object)val2 != (Object)null) { component.sprite = val2.sprite; component.type = val2.type; ((Graphic)component).color = ((Graphic)val2).color; ((Graphic)component).material = ((Graphic)val2).material; component.pixelsPerUnitMultiplier = val2.pixelsPerUnitMultiplier; ((Behaviour)component2).enabled = false; } else { ((Graphic)component).color = new Color(0.07f, 0.055f, 0.045f, 0.92f); ((Shadow)component2).effectColor = new Color(Gold.r, Gold.g, Gold.b, 0.55f); ((Shadow)component2).effectDistance = new Vector2(1.5f, -1.5f); } TMP_Text val3 = Find<TMP_Text>(gui, "root/Crafting/topic"); _title = MakeLabel((Transform)(object)_panel, Translations.T("gearslots_title"), ((Object)(object)val3 != (Object)null) ? val3 : sample.m_amount); _title.fontSize = (((Object)(object)val3 != (Object)null) ? 20f : 17f); ((Graphic)_title).color = (((Object)(object)val3 != (Object)null) ? TitleColor : Gold); _title.alignment = (TextAlignmentOptions)257; RectTransform rectTransform = _title.rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(10f, 0f); rectTransform.offsetMax = new Vector2(-10f, -4f); Image val4 = Find<Image>(gui, "root/Crafting/BraidLineHorisontalMedium"); if ((Object)(object)val4 != (Object)null) { GameObject val5 = new GameObject("GearSlotsBraid", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val6 = (RectTransform)val5.transform; ((Transform)val6).SetParent((Transform)(object)_panel, false); ((Transform)val6).SetSiblingIndex(1); val6.anchorMin = new Vector2(0f, 1f); val6.anchorMax = new Vector2(1f, 1f); val6.pivot = new Vector2(0.5f, 0.5f); val6.offsetMin = new Vector2(10f, 0f); val6.offsetMax = new Vector2(-10f, 0f); Rect rect = ((Graphic)val4).rectTransform.rect; val6.sizeDelta = new Vector2(-20f, Mathf.Clamp(((Rect)(ref rect)).height, 6f, 12f)); val6.anchoredPosition = new Vector2(0f, -30f); Image component3 = val5.GetComponent<Image>(); component3.sprite = val4.sprite; component3.type = val4.type; ((Graphic)component3).material = ((Graphic)val4).material; ((Graphic)component3).color = ((Graphic)val4).color; component3.pixelsPerUnitMultiplier = val4.pixelsPerUnitMultiplier; component3.fillCenter = val4.fillCenter; ((Graphic)component3).raycastTarget = false; } else { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"The game's title line was not found where expected: the Gear panel's title is plain"); } } } private static T Find<T>(InventoryGui gui, string path) where T : Component { Transform val = ((Component)gui).transform.Find(path); if (!((Object)(object)val != (Object)null)) { return default(T); } return ((Component)val).GetComponent<T>(); } private static Image FindWoodPanel(RectTransform inventory) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) Image result = null; float num = 0f; Image[] componentsInChildren = ((Component)inventory).GetComponentsInChildren<Image>(true); foreach (Image val in componentsInChildren) { if (!((Object)(object)val.sprite == (Object)null) && !((Object)(object)((Component)val).transform == (Object)(object)_panel) && (!((Object)(object)_panel != (Object)null) || !((Component)val).transform.IsChildOf((Transform)(object)_panel)) && !((Object)(object)((Component)val).GetComponentInParent<InventoryElement>() != (Object)null)) { Rect rect = ((Graphic)val).rectTransform.rect; if (((Rect)(ref rect)).width * ((Rect)(ref rect)).height > num) { num = ((Rect)(ref rect)).width * ((Rect)(ref rect)).height; result = val; } } } return result; } private static Sprite IconOf(string prefab) { if (string.IsNullOrEmpty(prefab) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.m_itemData.GetIcon(); } private static void AddSilhouette(Transform parent, Slot slot, Vector2 size) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Sprite val = IconOf(slot.Icon); if (!((Object)(object)val == (Object)null)) { GameObject val2 = new GameObject("GearSlotsIcon", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(parent, false); val2.transform.SetAsFirstSibling(); Image component = val2.GetComponent<Image>(); component.sprite = val; ((Graphic)component).raycastTarget = false; component.preserveAspect = true; ((Graphic)component).color = new Color(0f, 0f, 0f, 0.35f); RectTransform rectTransform = ((Graphic)component).rectTransform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); rectTransform.anchorMax = val3; rectTransform.anchorMin = val3; rectTransform.sizeDelta = size * 0.62f; rectTransform.anchoredPosition = new Vector2(0f, 4f); } } private static TMP_Text MakeLabel(Transform parent, string text, TMP_Text font) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) GameObject val = new GameObject("GearSlotsLabel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); bool activeSelf = val.activeSelf; val.SetActive(false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = font.font; val.SetActive(activeSelf); ((TMP_Text)val2).fontSharedMaterial = font.fontSharedMaterial; ((TMP_Text)val2).text = text; ((TMP_Text)val2).fontSize = 12f; ((Graphic)val2).color = Dim; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).enableWordWrapping = false; RectTransform rectTransform = ((TMP_Text)val2).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; Vector2 offsetMin = (rectTransform.offsetMax = Vector2.zero); rectTransform.offsetMin = offsetMin; return (TMP_Text)(object)val2; } private static float ReservedBelow() { object data = AppDomain.CurrentDomain.GetData("DHack.QoL.UnderInventoryHeight"); if (data is float) { return (float)data; } return 0f; } private static void Place(RectTransform inventory, float width, float height) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00db: Unknown result type (might be due to invalid IL or missing references) RectTransform panel = _panel; Vector2 anchorMin = (_panel.anchorMax = inventory.pivot); panel.anchorMin = anchorMin; Rect rect = inventory.rect; Vector3[] array = (Vector3[])(object)new Vector3[4]; inventory.GetWorldCorners(array); float num = ((((Transform)inventory).lossyScale.x > 0f) ? ((Transform)inventory).lossyScale.x : 1f); Vector2 val = ((array[0].x - (width + Plugin.Instance.PanelGap) * num >= 0f) ? new Vector2(((Rect)(ref rect)).xMin - width - Plugin.Instance.PanelGap, ((Rect)(ref rect)).yMax) : new Vector2(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMin - Plugin.Instance.PanelGap - ReservedBelow())); _panel.anchoredPosition = val + Plugin.Instance.PanelOffset; } public static void Dispose(bool restoreCells) { InventoryGui instance = InventoryGui.instance; if (restoreCells && (Object)(object)instance != (Object)null && (Object)(object)instance.m_playerGrid != (Object)null && (Object)(object)_panel != (Object)null) { InventoryGrid playerGrid = instance.m_playerGrid; foreach (InventoryElement item in ElementsField.Invoke(playerGrid)) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).transform.parent == (Object)(object)_panel) { ((Component)item).transform.SetParent((Transform)(object)playerGrid.m_gridRoot, false); ((Component)item).gameObject.SetActive(true); } } AccessTools.Field(typeof(InventoryGrid), "m_width").SetValue(playerGrid, -1); } if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)((Component)_panel).gameObject); } _panel = null; _title = null; Labels.Clear(); } } internal static class Patches { [HarmonyPatch(typeof(Player), "Load")] private static class PlayerLoad { [HarmonyPriority(800)] private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if (Compat.StandingDown) { var (moved, left) = Layout.EmptyGearRows(__instance); Plugin.Instance?.StoodDown(moved, left); } else { Place(__instance, Layout.WorkOutBase(__instance)); } } } } [HarmonyPatch(typeof(Player), "OnSpawned")] private static class OnSpawned { [HarmonyPriority(0)] private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !Compat.StandingDown) { if ((Object)(object)__instance != (Object)(object)_placed) { Place(__instance, ((Humanoid)__instance).GetInventory().GetHeight()); } if ((Object)(object)InventoryGui.instance != (Object)null) { InventoryGui.instance.SetInventorySize(Layout.NormalRows); } } } } [HarmonyPatch(typeof(Player), "SetInventorySize")] private static class SetInventorySize { internal static bool Resizing; internal static int OldBase; [HarmonyPriority(800)] private static void Prefix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !Compat.StandingDown) { Resizing = true; OldBase = Layout.NormalRows; } } [HarmonyPriority(0)] private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !Compat.StandingDown) { Extend(((Humanoid)__instance).GetInventory()); } } [HarmonyFinalizer] private static void Finalizer() { Resizing = false; } } [HarmonyPatch(typeof(Humanoid), "DropInvalidItems")] private static class DropInvalidItems { [HarmonyPriority(800)] private static void Prefix(Humanoid __instance) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if (!SetInventorySize.Resizing || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Player val = (Player)__instance; Inventory inventory = ((Humanoid)val).GetInventory(); int oldBase = SetInventorySize.OldBase; int height = inventory.GetHeight(); List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_gridPos.y >= oldBase && allItem.m_gridPos.y < oldBase + 2) { list.Add(allItem); } } foreach (ItemData item in list) { item.m_gridPos.y += height - oldBase; } Layout.RememberNormalRows(height); Layout.SaveBase(val, height); inventory.SetHeight(height + 2); foreach (ItemData allItem2 in inventory.GetAllItems()) { if (!list.Contains(allItem2) && allItem2.m_gridPos.y >= height) { Vector2i val2 = Layout.FindFreeNormalCell(inventory, topFirst: false); allItem2.m_gridPos = (Vector2i)((val2.x >= 0) ? val2 : new Vector2i(-1, -1)); } } } } [HarmonyPatch(typeof(Inventory), "FindEmptySlot")] private static class FindEmptySlot { private static void Postfix(Inventory __instance, bool topFirst, ref Vector2i __result) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (Layout.IsPlayerInventory(__instance) && __result.y >= Layout.NormalRows) { __result = Layout.FindFreeNormalCell(__instance, topFirst); } } } [HarmonyPatch(typeof(Inventory), "HaveEmptySlot")] private static class HaveEmptySlot { private static void Postfix(Inventory __instance, ref bool __result) { if (Layout.IsPlayerInventory(__instance)) { __result = Layout.NormalItemCount(__instance) < __instance.GetWidth() * Layout.NormalRows; } } } [HarmonyPatch(typeof(Inventory), "GetEmptySlots")] private static class GetEmptySlots { private static void Postfix(Inventory __instance, ref int __result) { if (Layout.IsPlayerInventory(__instance)) { __result = __instance.GetWidth() * Layout.NormalRows - Layout.NormalItemCount(__instance); } } } [HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[] { typeof(ItemData), typeof(int) })] private static class CanAddItem { private static void Postfix(Inventory __instance, ItemData item, int stack, ref bool __result) { if (__result && Layout.IsPlayerInventory(__instance)) { if (stack <= 0) { stack = item.m_stack; } int num = __instance.GetWidth() * Layout.NormalRows - Layout.NormalItemCount(__instance); int num2 = (int)AccessTools.Method(typeof(Inventory), "FindFreeStackSpace", (Type[])null, (Type[])null).Invoke(__instance, new object[2] { item.m_shared.m_name, item.m_worldLevel }); __result = num2 + num * item.m_shared.m_maxStackSize >= stack; } } } [HarmonyPatch(typeof(InventoryGrid), "DropItem")] private static class DropItem { private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, Vector2i pos, ref bool __result) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) Inventory inventory = __instance.GetInventory(); if (Layout.IsPlayerInventory(inventory)) { Slot slot = Layout.At(pos.x, pos.y); if (slot != null && !Layout.Fits(slot, item)) { return Refuse(item, slot, out __result); } } if (Layout.IsPlayerInventory(fromInventory)) { Slot slot2 = Layout.At(item.m_gridPos.x, item.m_gridPos.y); ItemData itemAt = inventory.GetItemAt(pos.x, pos.y); if (slot2 != null && itemAt != null && itemAt != item && !Layout.Fits(slot2, itemAt)) { return Refuse(itemAt, slot2, out __result); } } return true; } private static bool Refuse(ItemData item, Slot slot, out bool result) { result = false; if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, Translations.T("gearslots_doesnt_fit", Localization.instance.Localize(item.m_shared.m_name), slot.Name), 0, (Sprite)null, false); } return false; } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] private static class UpdateGui { private static void Postfix(InventoryGrid __instance) { if (!((Object)(object)Plugin.Instance == (Object)null) && Layout.IsPlayerInventory(__instance.GetInventory())) { Panel.Update(__instance); } } } private static Player _placed; public static void Extend(Inventory inv) { if (inv != null && !Compat.StandingDown) { if (!(AppDomain.CurrentDomain.GetData("DHack.GearSlots.NormalRows") is int) && (Object)(object)Player.m_localPlayer != (Object)null) { Layout.RememberNormalRows(Layout.WorkOutBase(Player.m_localPlayer)); } int num = Layout.NormalRows + 2; if (inv.GetHeight() < num) { inv.SetHeight(num); } } } private static void Place(Player player, int gearBase) { Layout.RememberNormalRows(gearBase); Layout.SaveBase(player, gearBase); Inventory inventory = ((Humanoid)player).GetInventory(); inventory.SetHeight(Mathf.Max(inventory.GetHeight(), gearBase + 2)); _placed = player; } } [BepInPlugin("com.quad.gearslots", "GearSlots", "1.3.1")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.quad.gearslots"; public const string OldGuid = "com.dhack.gearslots"; public const string Name = "GearSlots"; public const string Version = "1.3.1"; internal static Plugin Instance; internal static ManualLogSource Log; private ConfigEntry<bool> _showPanel; private ConfigEntry<bool> _autoEat; private ConfigEntry<bool> _showMessages; private ConfigEntry<bool> _autoFill; private ConfigEntry<bool> _shieldFollows; private ConfigEntry<bool> _showQuickBar; private ConfigEntry<int> _eatBelow; private ConfigEntry<float> _panelGap; private ConfigEntry<float> _offsetX; private ConfigEntry<float> _offsetY; private ConfigEntry<KeyboardShortcut>[] _quickKeys; private Harmony _harmony; private readonly Hotbar _hotbar = new Hotbar(); private Inventory _watched; private readonly Dictionary<Slot, ItemData> _last = new Dictionary<Slot, ItemData>(); private float _nextEat; private float _nextFill; private bool _keysChecked; private readonly List<string> _keyNotes = new List<string>(); private bool _toldStandDown; private static readonly FieldRef<Humanoid, ItemData> LeftItem = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_leftItem"); private ItemData _lastWeapon; internal bool ShowQuickBar => _showQuickBar.Value; internal bool ShowPanel => _showPanel.Value; internal float PanelGap => _panelGap.Value; internal Vector2 PanelOffset => new Vector2(_offsetX.Value, _offsetY.Value); private void Awake() { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected O, but got Unknown Migration.FromOldGuid((BaseUnityPlugin)(object)this, "com.dhack.gearslots"); Translations.Load((BaseUnityPlugin)(object)this); Instance = this; Log = ((BaseUnityPlugin)this).Logger; _showPanel = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPanel", true, "Show the Gear panel next to your inventory. (Turn off and your gear slots hide; the items stay where they are.)"); _showMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMessages", true, "Short messages when something happens (auto-eat, a quick slot is empty)."); _autoEat = ((BaseUnityPlugin)this).Config.Bind<bool>("Food", "AutoEat", false, "Eat from your Food slots by yourself: when a food you have in a slot is not active (and you have a free food slot), or its effect has dropped below half. Off by default."); _eatBelow = ((BaseUnityPlugin)this).Config.Bind<int>("Food", "EatBelowPercent", 20, new ConfigDescription("Auto-eat a food you are already under only once its time left drops below this percent (the game allows it from 50). Lower saves food: a meal then lasts 80% of its time instead of 50%, and its effect weakens a little towards the end.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>())); _shieldFollows = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShieldFollowsWeapon", true, "When you switch to a one-handed weapon, put on the shield from your Shield slot too. (Two-handed weapons and bows take the shield off, as in the game.)"); _showQuickBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick slots", "ShowUnderHotbar", true, "Show what is in your Quick slots, with their keys, in a row under the hotbar (the 1-8 on screen) while the inventory is closed."); _autoFill = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoFill", true, "When you put on a piece of gear (or the game loads with it on), move it into its matching gear slot if that slot is empty."); _panelGap = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "Gap", 6f, "Space between the Gear panel and the inventory (UI pixels)."); _offsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "OffsetX", 0f, "Move the Gear panel right (negative = left)."); _offsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "OffsetY", 0f, "Move the Gear panel up (negative = down)."); KeyCode[] array = new KeyCode[5]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); KeyCode[] array2 = (KeyCode[])(object)array; _quickKeys = new ConfigEntry<KeyboardShortcut>[5]; for (int i = 0; i < 5; i++) { _quickKeys[i] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quick slots", "Key" + (i + 1), new KeyboardShortcut(array2[i], Array.Empty<KeyCode>()), "Press to use what is in quick slot " + (i + 1) + ": equips or unequips a weapon, tool or shield, or drinks a potion. Set to None to turn it off. If the game uses the same key for something (V: auto-pickup, X: sit, C: walk), the game's key is unbound once, so only this one works; bind it again in the game's Settings, Controls."); } ConfigEntry<KeyboardShortcut>[] quickKeys = _quickKeys; foreach (ConfigEntry<KeyboardShortcut> val in quickKeys) { val.SettingChanged += delegate { _keysChecked = false; }; } _harmony = new Harmony("com.quad.gearslots"); _harmony.PatchAll(); if ((Object)(object)Player.m_localPlayer != (Object)null) { Patches.Extend(((Humanoid)Player.m_localPlayer).GetInventory()); } AppDomain.CurrentDomain.SetData("DHack.GearSlots.IsGear", new Func<ItemData, bool>(IsInGearSlot)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"GearSlots 1.3.1 loaded"); if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString("[Mod]", "GearSlots v1.3.1 reloaded", (Type)1, false); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Panel.Dispose(restoreCells: true); _hotbar.Destroy(); Translations.Unload(); AppDomain.CurrentDomain.SetData("DHack.GearSlots.IsGear", null); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; Log = null; } } internal unsafe string QuickKeyName(int quick) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = _quickKeys[quick].Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; if ((int)mainKey != 0) { return ((object)(*(KeyCode*)(&mainKey))/*cast due to .constrained prefix*/).ToString(); } return ""; } private static bool IsInGearSlot(ItemData item) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (item != null && (Object)(object)Player.m_localPlayer != (Object)null && !Compat.StandingDown && Layout.InExtraRows(item.m_gridPos)) { return ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems().Contains(item); } return false; } private void FreeGameKeys() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) if (_keysChecked || ZInput.instance == null) { return; } _keysChecked = true; List<KeyValuePair<KeyCode, string>> list = new List<KeyValuePair<KeyCode, string>>(); for (int i = 0; i < _quickKeys.Length; i++) { KeyboardShortcut value = _quickKeys[i].Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && !((KeyboardShortcut)(ref value)).Modifiers.Any()) { list.Add(new KeyValuePair<KeyCode, string>(((KeyboardShortcut)(ref value)).MainKey, Translations.T("gearslots_quick_slot_n", i + 1))); } } _keyNotes.AddRange(GameKeys.Free("GearSlots", list)); _keyNotes.AddRange(GameKeys.GiveBack("GearSlots", list.Select((KeyValuePair<KeyCode, string> k) => k.Key))); FieldInfo fieldInfo = AccessTools.Field(typeof(Player), "m_enableAutoPickup"); if (fieldInfo != null && !(bool)fieldInfo.GetValue(null)) { ButtonDef buttonDef = ZInput.instance.GetButtonDef("AutoPickup"); if (string.IsNullOrEmpty((buttonDef != null) ? buttonDef.GetActionPath(true) : null)) { fieldInfo.SetValue(null, true); _keyNotes.Add(Translations.T("gearslots_autopickup_on", "GearSlots")); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto-pickup was off and its key is unbound: switched it back on"); } } } internal void StoodDown(int moved, int left) { if (!_toldStandDown) { _toldStandDown = true; string text = Translations.T("gearslots_standdown", "GearSlots", Compat.StandDownFor); if (moved > 0) { text = text + " " + Translations.T("gearslots_standdown_moved", moved); } if (left > 0) { text = text + " " + Translations.T("gearslots_standdown_left", left); } _keyNotes.Add(text); ((BaseUnityPlugin)this).Logger.LogInfo((object)text); _keyNotes.AddRange(GameKeys.GiveBack("GearSlots", (IEnumerable<KeyCode>)(object)new KeyCode[0])); } } private void Update() { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer != (Object)null && Compat.StandingDown) { StoodDown(0, 0); if (_keyNotes.Count <= 0 || !((Object)(object)Chat.instance != (Object)null)) { return; } foreach (string keyNote in _keyNotes) { ((Terminal)Chat.instance).AddString("[Mod]", keyNote, (Type)1, false); } _keyNotes.Clear(); return; } if ((Object)(object)Player.m_localPlayer != (Object)null) { FreeGameKeys(); } if (_keyNotes.Count > 0 && (Object)(object)Chat.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { foreach (string keyNote2 in _keyNotes) { ((Terminal)Chat.instance).AddString("[Mod]", keyNote2, (Type)1, false); } _keyNotes.Clear(); } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); Patches.Extend(inventory); _hotbar.Update(localPlayer, inventory); if (_autoFill.Value && Time.time >= _nextFill) { _nextFill = Time.time + 0.5f; FillSlotsWithWornGear(localPlayer, inventory); } WearWhatArrived(localPlayer, inventory); if (_shieldFollows.Value) { ShieldFollowsWeapon(localPlayer, inventory); } if (_autoEat.Value && Time.time >= _nextEat) { _nextEat = Time.time + 1f; AutoEat(localPlayer, inventory); } if (InventoryGui.IsVisible() || TypingOrMenuOpen()) { return; } for (int i = 0; i < 5; i++) { if (Pressed(_quickKeys[i].Value)) { UseQuick(localPlayer, inventory, i); } } } private void WearWhatArrived(Player player, Inventory inv) { bool flag = _watched != inv; _watched = inv; Slot[] all = Layout.All; foreach (Slot slot in all) { if (!Layout.IsEquipment(slot)) { continue; } ItemData val = Layout.ItemIn(inv, slot); _last.TryGetValue(slot, out var value); if (!flag && val != null && val != value && !((Humanoid)player).IsItemEquiped(val)) { if (slot.Kind == Kind.Shield && !OneHandFree(player)) { _last[slot] = val; continue; } ((Humanoid)player).EquipItem(val, true); } _last[slot] = val; } } private void FillSlotsWithWornGear(Player player, Inventory inv) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData item in inv.GetAllItems().ToList()) { if (item.m_gridPos.y < Layout.NormalRows && ((Humanoid)player).IsItemEquiped(item)) { Slot slot = Layout.All.FirstOrDefault((Slot s) => Layout.IsEquipment(s) && Layout.Fits(s, item) && Layout.ItemIn(inv, s) == null); if (slot != null) { item.m_gridPos = Layout.CellOf(slot); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Moved worn " + item.m_shared.m_name + " into the " + slot.Label + " slot")); } } } } private static bool OneHandFree(Player player) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); if (currentWeapon == null) { return true; } ItemType itemType = currentWeapon.m_shared.m_itemType; return (int)itemType == 3; } private void ShieldFollowsWeapon(Player player, Inventory inv) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); if (currentWeapon == _lastWeapon) { return; } _lastWeapon = currentWeapon; if (currentWeapon != null && (int)currentWeapon.m_shared.m_itemType == 3 && inv.ContainsItem(currentWeapon) && LeftItem.Invoke((Humanoid)(object)player) == null) { Slot s = Layout.All.First((Slot slot) => slot.Kind == Kind.Shield); ItemData val = Layout.ItemIn(inv, s); if (val != null && !((Humanoid)player).IsItemEquiped(val)) { ((Humanoid)player).EquipItem(val, true); } } } private void UseQuick(Player player, Inventory inv, int quick) { Slot s = Layout.All.First((Slot slot) => slot.Quick == quick); ItemData val = Layout.ItemIn(inv, s); if (val == null) { Tell(player, Translations.T("gearslots_quick_empty", quick + 1)); } else { ((Humanoid)player).UseItem(inv, val, true); } } private void AutoEat(Player player, Inventory inv) { List<Food> foods = player.GetFoods(); Slot[] all = Layout.All; foreach (Slot slot in all) { if (slot.Kind != Kind.Food) { continue; } ItemData item = Layout.ItemIn(inv, slot); if (item == null) { continue; } Food val = ((IEnumerable<Food>)foods).FirstOrDefault((Func<Food, bool>)((Food f) => f.m_item.m_shared.m_name == item.m_shared.m_name)); bool num; if (val == null) { num = foods.Count < 3; } else { if (!val.CanEatAgain()) { continue; } num = val.m_time < val.m_item.m_shared.m_foodBurnTime * (float)_eatBelow.Value / 100f; } if (num && player.CanEat(item, false)) { ((Humanoid)player).UseItem(inv, item, true); Tell(player, Translations.T("gearslots_ate", Localization.instance.Localize(item.m_shared.m_name))); break; } } } private static bool Pressed(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } return false; } private static bool TypingOrMenuOpen() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.InTextInput() && !Menu.IsVisible() && !Minimap.IsOpen()) { return StoreGui.IsVisible(); } return true; } private void Tell(Player player, string message) { if (_showMessages.Value) { ((Character)player).Message((MessageType)1, message, 0, (Sprite)null, false); } } } internal enum Kind { Head, Chest, Legs, Shoulder, Utility, Trinket, Ammo, Shield, Food, Quick } internal class Slot { public string Label; public Kind Kind; public int Col; public int Row; public int Quick; public string Icon; public string Name => Localization.instance.Localize(Label); } internal static class Layout { public const int ExtraRows = 2; public const int Columns = 8; private const string RowsKey = "DHack.GearSlots.NormalRows"; public static readonly Slot[] All = new Slot[16] { new Slot { Label = "$gearslots_slot_head", Kind = Kind.Head, Col = 0, Row = 0, Quick = -1, Icon = "HelmetLeather" }, new Slot { Label = "$gearslots_slot_chest", Kind = Kind.Chest, Col = 1, Row = 0, Quick = -1, Icon = "ArmorLeatherChest" }, new Slot { Label = "$gearslots_slot_legs", Kind = Kind.Legs, Col = 2, Row = 0, Quick = -1, Icon = "ArmorLeatherLegs" }, new Slot { Label = "$gearslots_slot_cape", Kind = Kind.Shoulder, Col = 3, Row = 0, Quick = -1, Icon = "CapeDeerHide" }, new Slot { Label = "$gearslots_slot_belt", Kind = Kind.Utility, Col = 4, Row = 0, Quick = -1, Icon = "BeltStrength" }, new Slot { Label = "$gearslots_slot_trinket", Kind = Kind.Trinket, Col = 5, Row = 0, Quick = -1 }, new Slot { Label = "$gearslots_slot_ammo", Kind = Kind.Ammo, Col = 6, Row = 0, Quick = -1, Icon = "ArrowWood" }, new Slot { Label = "$gearslots_slot_shield", Kind = Kind.Shield, Col = 7, Row = 0, Quick = -1, Icon = "ShieldWood" }, new Slot { Label = "$gearslots_slot_food", Kind = Kind.Food, Col = 0, Row = 1, Quick = -1, Icon = "CookedMeat" }, new Slot { Label = "$gearslots_slot_food", Kind = Kind.Food, Col = 1, Row = 1, Quick = -1, Icon = "CookedMeat" }, new Slot { Label = "$gearslots_slot_food", Kind = Kind.Food, Col = 2, Row = 1, Quick = -1, Icon = "CookedMeat" }, new Slot { Label = "$gearslots_slot_quick", Kind = Kind.Quick, Col = 3, Row = 1, Quick = 0 }, new Slot { Label = "$gearslots_slot_quick", Kind = Kind.Quick, Col = 4, Row = 1, Quick = 1 }, new Slot { Label = "$gearslots_slot_quick", Kind = Kind.Quick, Col = 5, Row = 1, Quick = 2 }, new Slot { Label = "$gearslots_slot_quick", Kind = Kind.Quick, Col = 6, Row = 1, Quick = 3 }, new Slot { Label = "$gearslots_slot_quick", Kind = Kind.Quick, Col = 7, Row = 1, Quick = 4 } }; public const int QuickCount = 5; private const string BaseKey = "DHack.GearSlots.Base"; public static int NormalRows { get { object data = AppDomain.CurrentDomain.GetData("DHack.GearSlots.NormalRows"); if (data is int) { return (int)data; } Inventory val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); if (val == null) { return 4; } return val.GetHeight(); } } public static void RememberNormalRows(int rows) { AppDomain.CurrentDomain.SetData("DHack.GearSlots.NormalRows", rows); } public static void ForgetNormalRows() { AppDomain.CurrentDomain.SetData("DHack.GearSlots.NormalRows", null); } public static void SaveBase(Player player, int gearBase) { player.m_customData["DHack.GearSlots.Base"] = gearBase.ToString(); } public static int WorkOutBase(Player player) { if (player.m_customData.TryGetValue("DHack.GearSlots.Base", out var value) && int.TryParse(value, out var result) && result >= 0) { return result; } string s = default(string); if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result2)) { return Mathf.Clamp(result2, 0, 9); } return ((Humanoid)player).GetInventory().GetHeight(); } public static (int moved, int left) EmptyGearRows(Player player) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if (!player.m_customData.TryGetValue("DHack.GearSlots.Base", out var value) || !int.TryParse(value, out var result)) { return (moved: 0, left: 0); } string s = default(string); int num = ((player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result2)) ? Mathf.Clamp(result2, 0, 9) : 4); num = Mathf.Min(num, result); Inventory inventory = ((Humanoid)player).GetInventory(); int num2 = 0; int num3 = 0; Vector2i val = default(Vector2i); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_gridPos.y < result || allItem.m_gridPos.y >= result + 2) { continue; } ((Vector2i)(ref val))..ctor(-1, -1); for (int i = 0; i < num; i++) { if (val.x >= 0) { break; } for (int j = 0; j < inventory.GetWidth(); j++) { if (inventory.GetItemAt(j, i) == null) { ((Vector2i)(ref val))..ctor(j, i); break; } } } if (val.x < 0) { num3++; continue; } allItem.m_gridPos = val; num2++; } if (num3 == 0) { player.m_customData.Remove("DHack.GearSlots.Base"); } return (moved: num2, left: num3); } public static Vector2i CellOf(Slot s) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector2i(s.Col, NormalRows + s.Row); } public static Slot At(int x, int y) { int num = y - NormalRows; if (num < 0 || num >= 2) { return null; } Slot[] all = All; foreach (Slot slot in all) { if (slot.Col == x && slot.Row == num) { return slot; } } return null; } public static bool InExtraRows(Vector2i pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return pos.y >= NormalRows; } public static bool Fits(Slot s, ItemData item) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Invalid comparison between Unknown and I4 //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 if (s == null || item == null) { return true; } SharedData shared = item.m_shared; switch (s.Kind) { case Kind.Head: return (int)shared.m_itemType == 6; case Kind.Chest: return (int)shared.m_itemType == 7; case Kind.Legs: return (int)shared.m_itemType == 11; case Kind.Shoulder: return (int)shared.m_itemType == 17; case Kind.Utility: return (int)shared.m_itemType == 18; case Kind.Trinket: return (int)shared.m_itemType == 24; case Kind.Shield: return (int)shared.m_itemType == 5; case Kind.Ammo: if ((int)shared.m_itemType != 9) { return (int)shared.m_itemType == 23; } return true; case Kind.Food: return IsFood(item); default: return !shared.m_questItem; } } public static bool IsFood(ItemData item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)item.m_shared.m_itemType == 2) { if (!(item.m_shared.m_food > 0f) && !(item.m_shared.m_foodStamina > 0f)) { return item.m_shared.m_foodEitr > 0f; } return true; } return false; } public static Slot QuickSlot(int quick) { Slot[] all = All; foreach (Slot slot in all) { if (slot.Quick == quick) { return slot; } } return null; } public static bool IsEquipment(Slot s) { if (s != null && s.Kind != Kind.Food) { return s.Kind != Kind.Quick; } return false; } public static ItemData ItemIn(Inventory inv, Slot s) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Vector2i val = CellOf(s); return inv.GetItemAt(val.x, val.y); } public static bool IsPlayerInventory(Inventory inv) { if (inv != null && (Object)(object)Player.m_localPlayer != (Object)null && inv == ((Humanoid)Player.m_localPlayer).GetInventory()) { return !Compat.StandingDown; } return false; } public static int NormalItemCount(Inventory inv) { int normalRows = NormalRows; int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (allItem.m_gridPos.y < normalRows) { num++; } } return num; } public static Vector2i FindFreeNormalCell(Inventory inv, bool topFirst) { //IL_004b: 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) int normalRows = NormalRows; int width = inv.GetWidth(); for (int i = 0; i < normalRows; i++) { int num = (topFirst ? i : (normalRows - 1 - i)); for (int j = 0; j < width; j++) { if (inv.GetItemAt(j, num) == null) { return new Vector2i(j, num); } } } return new Vector2i(-1, -1); } } } namespace DHack.Shared { internal static class Migration { private sealed class Notice : MonoBehaviour { public string Text; private float _next; private void Update() { if (!(Time.unscaledTime < _next) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)MessageHud.instance == (Object)null)) { ((Character)Player.m_localPlayer).Message((MessageType)2, Text, 0, (Sprite)null, false); _next = Time.unscaledTime + 60f; } } } public static void FromOldGuid(BaseUnityPlugin plugin, string oldGuid) { BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); string text = ((metadata != null) ? metadata.GUID : null); if (string.IsNullOrEmpty(oldGuid) || string.IsNullOrEmpty(text) || oldGuid == text) { return; } ManualLogSource val = Logger.CreateLogSource(text); try { bool flag = false; if (Directory.Exists(Paths.ConfigPath)) { string[] files = Directory.GetFiles(Paths.ConfigPath, oldGuid + ".*"); foreach (string text2 in files) { string fileName = Path.GetFileName(text2); if (!fileName.EndsWith(".cfg") && !fileName.EndsWith(".json") && !fileName.EndsWith(".txt")) { continue; } string text3 = Path.Combine(Paths.ConfigPath, text + fileName.Substring(oldGuid.Length)); if (!File.Exists(text3)) { File.Copy(text2, text3); val.LogInfo((object)("Settings moved over from " + fileName + " (the mod's id is now " + text + "; the old file is kept as a backup)")); if (fileName == oldGuid + ".cfg") { flag = true; } } } } if (flag) { plugin.Config.Reload(); } } catch (Exception ex) { val.LogWarning((object)("Couldn't move the settings over from " + oldGuid + ".cfg: " + ex.Message)); } finally { Logger.Sources.Remove((ILogSource)(object)val); } ((MonoBehaviour)plugin).StartCoroutine(StandDownIfTwin(plugin, oldGuid)); } private static IEnumerator StandDownIfTwin(BaseUnityPlugin plugin, string oldGuid) { yield return null; yield return null; if (!((Object)(object)plugin == (Object)null) && Chainloader.PluginInfos.TryGetValue(oldGuid, out var value) && !((Object)(object)value.Instance == (Object)null) && !((Object)(object)value.Instance == (Object)(object)plugin)) { BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); string text = ((metadata != null) ? metadata.Name : null) ?? oldGuid; string text2 = (string.IsNullOrEmpty(value.Location) ? "an older copy" : value.Location); string text3 = text + ": two copies are installed, an old one (" + text2 + ") and this one. Both would run and do everything twice, so this one stands down. Delete the old copy, then restart the game."; Debug.LogError((object)("[" + text + "] " + text3)); Object.Destroy((Object)(object)plugin); GameObject val = new GameObject("Migration_TwoCopies_" + text); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<Notice>().Text = text3; } } } internal static class Translations { public static readonly string[] Shipped = new string[9] { "English", "Russian", "German", "Chinese", "Portuguese_Brazilian", "Spanish", "French", "Polish", "Turkish" }; private static readonly Dictionary<string, Dictionary<string, string>> Languages = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); private static Dictionary<string, string> _english = new Dictionary<string, string>(); private static string _overrideDir; private static bool _hooked; private static readonly MethodInfo AddWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null); private static readonly FieldInfo Cache = AccessTools.Field(typeof(Localization), "m_cache"); public static void Load(BaseUnityPlugin plugin) { Languages.Clear(); Assembly assembly = ((object)plugin).GetType().Assembly; foreach (string item in from n in assembly.GetManifestResourceNames() where n.StartsWith("translations/") && n.EndsWith(".json") select n) { using StreamReader streamReader = new StreamReader(assembly.GetManifestResourceStream(item)); Languages[Path.GetFileNameWithoutExtension(item.Substring("translations/".Length))] = Parse(streamReader.ReadToEnd()); } _english = (Languages.TryGetValue("English", out var value) ? value : new Dictionary<string, string>()); _overrideDir = Path.Combine(Paths.ConfigPath, "translations", plugin.Info.Metadata.GUID); if (!_hooked) { Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(Apply)); _hooked = true; } Apply(); } public static void Unload() { if (_hooked) { Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(Apply)); _hooked = false; } } public static string T(string key, params object[] args) { string text = ((Localization.instance != null) ? Localization.instance.Localize("$" + key) : null); if (string.IsNullOrEmpty(text) || text == "[" + key + "]") { text = (_english.TryGetValue(key, out var value) ? value : key); } if (args == null || args.Length == 0) { return text; } try { return string.Format(text, args); } catch (FormatException) { string value2; return _english.TryGetValue(key, out value2) ? SafeFormat(value2, args) : text; } } private static string SafeFormat(string text, object[] args) { try { return string.Format(text, args); } catch (FormatException) { return text; } } private static void Apply() { Localization instance = Localization.instance; if (instance == null || AddWord == null) { return; } string selectedLanguage = instance.GetSelectedLanguage(); Dictionary<string, string> dictionary = new Dictionary<string, string>(_english); if (Languages.TryGetValue(selectedLanguage, out var value)) { foreach (KeyValuePair<string, string> item in value) { dictionary[item.Key] = item.Value; } } try { string path = Path.Combine(_overrideDir, selectedLanguage + ".json"); if (File.Exists(path)) { foreach (KeyValuePair<string, string> item2 in Parse(File.ReadAllText(path))) { dictionary[item2.Key] = item2.Value; } } } catch (Exception ex) { Debug.LogWarning((object)("Translations: couldn't read the player's " + selectedLanguage + " file: " + ex.Message)); } foreach (KeyValuePair<string, string> item3 in dictionary) { AddWord.Invoke(instance, new object[2] { item3.Key, item3.Value }); } object obj = Cache?.GetValue(instance); obj?.GetType().GetMethod("EvictAll")?.Invoke(obj, null); } private static Dictionary<string, string> Parse(string json) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (Match item in Regex.Matches(json, "\"((?:[^\"\\\\]|\\\\.)*)\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"")) { dictionary[Unescape(item.Groups[1].Value)] = Unescape(item.Groups[2].Value); } return dictionary; } private static string Unescape(string s) { return Regex.Replace(s, "\\\\(u[0-9a-fA-F]{4}|.)", delegate(Match m) { string value = m.Groups[1].Value; return value[0] switch { 'n' => "\n", 't' => "\t", 'u' => ((char)Convert.ToInt32(value.Substring(1), 16)).ToString(), _ => value, }; }); } } }