Decompiled source of PEAK Tool Belt v2.0.0
tony4twentys-PEAK Tool Belt.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; using Zorro.Core.Serizalization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyTitle("PEAK Tool Belt")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PEAK Tool Belt")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("5790c129-81b9-40c2-bbe5-e13b4d2fbd84")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace PEAK_Tool_Belt { [BepInPlugin("tony4twentys.PEAK_Tool_Belt", "PEAK Tool Belt", "2.0.0")] [BepInProcess("PEAK.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "tony4twentys.PEAK_Tool_Belt"; public const string PluginName = "PEAK Tool Belt"; public const string PluginVersion = "2.0.0"; public const byte EventCode = 165; public const string EventMagic = "tony4twentys.PEAK_Tool_Belt"; public const int ProtocolVersion = 2; public ConfigEntry<KeyCode> OpenToolBelt; public ConfigEntry<KeyCode> MenuKey; public ConfigEntry<KeyCode> MenuModifier; public ConfigEntry<bool> RequireMenuModifier; public ConfigEntry<bool> ShowPauseMenuButton; public ConfigEntry<int> Columns; private Harmony _harmony; private bool _open; private int _selected = -1; private float _lastGrantTime; private string _sceneName = string.Empty; private bool _validScene; private CursorLockMode _prevLock; private bool _prevCursorVisible; private Vector2 _frozenLookValues; private bool _hasFrozenLook; private bool _loggedEmptyBelt; private float _canUseCachedAt = -1f; private bool _canUseCached; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } internal bool IsOpen => _open; internal int SelectedIndex => _selected; private void Awake() { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; OpenToolBelt = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "OpenToolBelt", (KeyCode)116, "Hold to open the tool belt. Hover a slot, then release to take that item."); MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)106, "Open the Tool Belt setup menu."); MenuModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuModifier", (KeyCode)306, "Modifier used with MenuKey when RequireMenuModifier is on. Default LeftControl (Ctrl+J)."); RequireMenuModifier = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireMenuModifier", true, "If on, the setup menu needs MenuModifier + MenuKey (Ctrl+J). If off, MenuKey alone opens it."); ShowPauseMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPauseMenuButton", false, "Show a Tool Belt button on the pause menu."); Columns = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Columns", 5, "Belt slots per row."); Columns.SettingChanged += OnColumnsChanged; _harmony = new Harmony("tony4twentys.PEAK_Tool_Belt"); _harmony.PatchAll(typeof(Plugin).Assembly); SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.activeSceneChanged += OnActiveSceneChanged; BeltStore.Initialize(); BeltPresetStore.Initialize(); ToolBeltItems.LoadLocal(); ToolBeltMenu.EnsureCreated(); ToolBeltNet.Ensure(); Scene activeScene = SceneManager.GetActiveScene(); CheckScene(((Scene)(ref activeScene)).name); ((MonoBehaviour)this).StartCoroutine(WaitForItemDatabase()); Log.LogInfo((object)("PEAK Tool Belt v2.0.0 loaded. Open the menu with " + FormatMenuHotkey() + ".")); } private IEnumerator WaitForItemDatabase() { float elapsed = 0f; while (!ToolBeltItems.DatabaseReady()) { elapsed += 0.25f; if (elapsed > 120f) { Log.LogError((object)"Item database never loaded. Tool belt cannot list items."); yield break; } yield return (object)new WaitForSeconds(0.25f); } ItemCatalog.TryRefresh(includeLoadedAssets: true); ToolBeltItems.RefreshResolved(); ToolBeltMenu.OnCatalogReady(); if (_open) { ToolBeltHud.Rebuild(_selected); } Log.LogInfo((object)("Loaded " + ItemCatalog.Count + " live items for the Tool Belt menu. Belt resolved " + ToolBeltItems.VisibleCount + " slot(s).")); ((MonoBehaviour)this).StartCoroutine(WatchForLateItems(60f)); } private IEnumerator WatchForLateItems(float seconds) { float elapsed = 0f; while (elapsed < seconds) { yield return (object)new WaitForSeconds(2f); elapsed += 2f; int count = ItemCatalog.Count; try { ItemCatalog.TryRefresh(includeLoadedAssets: true); } catch { } if (ItemCatalog.Count > count) { Log.LogInfo((object)("Found " + (ItemCatalog.Count - count) + " more item(s) after PEAKLib/mod load (" + ItemCatalog.Count + " total).")); ToolBeltItems.RefreshResolved(); ToolBeltMenu.OnCatalogReady(); if (_open) { ToolBeltHud.Rebuild(_selected); } } } } private void OnDestroy() { if (Columns != null) { Columns.SettingChanged -= OnColumnsChanged; } SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.activeSceneChanged -= OnActiveSceneChanged; try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } try { ToolBeltMenu.DestroyInstance(); } catch { } ToolBeltHud.DestroyHud(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (ToolBeltMenu.IsOpen || ToolBeltMenu.IsListeningForHotkey) { if (_open) { Close(grantHovered: false); } } else if (!_validScene) { if (_open) { Close(grantHovered: false); } } else if (!IsHeld(OpenToolBelt)) { if (_open) { Close(_selected >= 0); } } else if (!CanUseBeltCached() || ShouldForceClose()) { if (_open) { Close(grantHovered: false); } } else if (ToolBeltItems.VisibleCount <= 0) { if (!_loggedEmptyBelt) { Log.LogWarning((object)"Tool belt has no resolved items. Open the setup menu and check some, or Reset defaults."); _loggedEmptyBelt = true; } if (_open) { Close(grantHovered: false); } } else { _loggedEmptyBelt = false; if (!_open) { Open(); } } } private void LateUpdate() { if (_open) { HoldFrozenLook(); } } internal void Open() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (!_validScene || !CanUseBelt() || ToolBeltItems.VisibleCount <= 0) { return; } _open = true; _selected = -1; _prevLock = Cursor.lockState; _prevCursorVisible = Cursor.visible; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; CaptureFrozenLook(); try { MenuAccess.SetMenuWindowFlags(GUIManager.instance, blocking: true, showingCursor: true); } catch { } try { if (!ToolBeltHud.Show(_selected)) { Log.LogWarning((object)"Tool belt HUD did not appear. Vanilla inventory slots may not be ready."); Close(grantHovered: false); return; } } catch (Exception ex) { Log.LogError((object)("Tool belt HUD failed: " + ex)); Close(grantHovered: false); return; } Log.LogInfo((object)("Opened tool belt (" + ToolBeltItems.VisibleCount + " item(s)). Hold " + PrettyKey(GetOpenKey()) + ", hover a slot, then release.")); } internal void Close(bool grantHovered) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) int selected = _selected; if (_open) { _open = false; _hasFrozenLook = false; ToolBeltHud.Hide(); Cursor.lockState = _prevLock; Cursor.visible = _prevCursorVisible; try { MenuAccess.SetMenuWindowFlags(GUIManager.instance, blocking: false, showingCursor: false); } catch { } if (grantHovered && selected >= 0) { TryGrant(selected); } } } internal void SelectSlot(int index) { if (!_open) { return; } if (index < 0) { _selected = -1; ToolBeltHud.RefreshSelection(-1); return; } int visibleCount = ToolBeltItems.VisibleCount; if (visibleCount > 0) { _selected = (index % visibleCount + visibleCount) % visibleCount; ToolBeltHud.RefreshSelection(_selected); } } internal void GrantIndex(int index) { if (_open && TryGrant(index)) { if (ToolBeltItems.VisibleCount <= 0) { Close(grantHovered: false); return; } ClampSelection(); ToolBeltHud.Rebuild(_selected); } } private bool TryGrant(int index) { if (!CanUseBelt() || ShouldForceClose()) { return false; } if (Time.unscaledTime - _lastGrantTime < 0.35f) { return false; } if (!ToolBeltItems.TryGetVisible(index, out var entry)) { return false; } GrantResult grantResult = ToolBeltGrant.TryGive(entry); if (grantResult == GrantResult.Failed) { return false; } _lastGrantTime = Time.unscaledTime; _selected = index; if (!entry.Protected && (grantResult == GrantResult.Pocket || grantResult == GrantResult.Hand)) { ToolBeltItems.Consume(entry); } return true; } internal void Restock(string reason) { ToolBeltItems.Restock(); _selected = 0; if (_open) { ToolBeltHud.Rebuild(_selected); } else { ToolBeltHud.DestroyHud(); } Log.LogInfo((object)("Tool belt restocked (" + reason + ") with " + ToolBeltItems.VisibleCount + " item(s).")); } internal static bool CanUseBelt() { if ((Object)(object)Instance == (Object)null || !Instance._validScene) { return false; } if (!PhotonNetwork.InRoom) { return true; } if (PhotonNetwork.IsMasterClient) { return true; } return ToolBeltNet.HostModConfirmed; } private static bool CanUseBeltCached() { if ((Object)(object)Instance == (Object)null) { return false; } if (Time.unscaledTime - Instance._canUseCachedAt < 0.25f) { return Instance._canUseCached; } Instance._canUseCached = CanUseBelt(); Instance._canUseCachedAt = Time.unscaledTime; return Instance._canUseCached; } internal static bool IsGameplayBlocked() { try { if (GUIManager.InPauseMenu) { return true; } if (LoadingScreenHandler.loading) { return true; } } catch { } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && (localCharacter.data.dead || localCharacter.data.fullyPassedOut)) { return true; } return false; } internal static int ColumnCount() { int num = (((Object)(object)Instance != (Object)null && Instance.Columns != null) ? Instance.Columns.Value : 5); if (num < 1) { return 1; } if (num > 10) { return 10; } return num; } private void ClampSelection() { int visibleCount = ToolBeltItems.VisibleCount; if (visibleCount <= 0) { _selected = 0; } else if (_selected < 0 || _selected >= visibleCount) { _selected = 0; } } private bool ShouldForceClose() { return IsGameplayBlocked(); } private static bool IsHeld(ConfigEntry<KeyCode> entry) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (entry != null && (int)entry.Value != 0) { return Input.GetKey(entry.Value); } return false; } private void CaptureFrozenLook() { //IL_002c: 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) Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null) { _hasFrozenLook = false; return; } _frozenLookValues = localCharacter.data.lookValues; _hasFrozenLook = true; } private void HoldFrozenLook() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (_hasFrozenLook) { Character localCharacter = Character.localCharacter; if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.data == (Object)null)) { localCharacter.data.lookValues = _frozenLookValues; } } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { CheckScene(((Scene)(ref scene)).name); } private void OnActiveSceneChanged(Scene previous, Scene next) { CheckScene(((Scene)(ref next)).name); } private void CheckScene(string sceneName) { if (string.IsNullOrEmpty(sceneName)) { return; } string sceneName2 = _sceneName; bool validScene = _validScene; _sceneName = sceneName; _validScene = sceneName == "Airport" || sceneName.StartsWith("Level_", StringComparison.Ordinal); if (_validScene && (!validScene || !string.Equals(sceneName2, sceneName, StringComparison.Ordinal))) { Restock(sceneName); } else if (!_validScene && _open) { Close(grantHovered: false); } ToolBeltMenu.OnAfterSceneLoad(); if (_validScene) { int count = ItemCatalog.Count; try { ItemCatalog.TryRefresh(includeLoadedAssets: true); } catch { } if (ItemCatalog.Count > count) { Log.LogInfo((object)("Found " + (ItemCatalog.Count - count) + " more item(s) after scene load (" + ItemCatalog.Count + " total).")); } ToolBeltItems.RefreshResolved(); ToolBeltMenu.OnCatalogReady(); ((MonoBehaviour)this).StartCoroutine(WatchForLateItems(45f)); } } internal void OnBeltListChanged() { if (_open) { ToolBeltHud.Rebuild(_selected); } else { ToolBeltHud.DestroyHud(); } } internal bool IsMenuHotkeyDown() { //IL_0009: 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) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Invalid comparison between Unknown and I4 //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 if (ToolBeltMenu.IsListeningForHotkey) { return false; } KeyCode menuKey = GetMenuKey(); if ((int)menuKey == 0) { return false; } if (!GetRequireMenuModifier()) { return Input.GetKeyDown(menuKey); } KeyCode menuModifier = GetMenuModifier(); if ((int)menuModifier == 0) { return Input.GetKeyDown(menuKey); } bool flag = Input.GetKey(menuModifier); if ((int)menuModifier == 306 || (int)menuModifier == 305) { flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } else if ((int)menuModifier == 308 || (int)menuModifier == 307) { flag = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } else if ((int)menuModifier == 304 || (int)menuModifier == 303) { flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } if (flag) { return Input.GetKeyDown(menuKey); } return false; } private void OnColumnsChanged(object sender, EventArgs args) { if (_open) { ToolBeltHud.Rebuild(_selected); } } public static bool GetShowPauseMenuButton() { if ((Object)(object)Instance != (Object)null && Instance.ShowPauseMenuButton != null) { return Instance.ShowPauseMenuButton.Value; } return false; } public static void SetShowPauseMenuButton(bool enabled) { if (!((Object)(object)Instance == (Object)null) && Instance.ShowPauseMenuButton != null) { Instance.ShowPauseMenuButton.Value = enabled; ((BaseUnityPlugin)Instance).Config.Save(); } } public static KeyCode GetMenuKey() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance != (Object)null) || Instance.MenuKey == null) { return (KeyCode)106; } return Instance.MenuKey.Value; } public static KeyCode GetMenuModifier() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance != (Object)null) || Instance.MenuModifier == null) { return (KeyCode)306; } return Instance.MenuModifier.Value; } public static void SetMenuKey(KeyCode key) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance == (Object)null) && Instance.MenuKey != null && (int)key != 0) { Instance.MenuKey.Value = key; ((BaseUnityPlugin)Instance).Config.Save(); } } public static void SetMenuModifier(KeyCode key) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance == (Object)null) && Instance.MenuModifier != null) { Instance.MenuModifier.Value = key; ((BaseUnityPlugin)Instance).Config.Save(); } } public static bool GetRequireMenuModifier() { if (!((Object)(object)Instance == (Object)null) && Instance.RequireMenuModifier != null) { return Instance.RequireMenuModifier.Value; } return true; } public static void SetRequireMenuModifier(bool enabled) { if (!((Object)(object)Instance == (Object)null) && Instance.RequireMenuModifier != null) { Instance.RequireMenuModifier.Value = enabled; ((BaseUnityPlugin)Instance).Config.Save(); } } public static KeyCode GetOpenKey() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) return Get(((Object)(object)Instance != (Object)null) ? Instance.OpenToolBelt : null, (KeyCode)116); } public static void SetOpenKey(KeyCode key) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Set(((Object)(object)Instance != (Object)null) ? Instance.OpenToolBelt : null, key); } public static void SetColumns(int columns) { if (!((Object)(object)Instance == (Object)null) && Instance.Columns != null) { Instance.Columns.Value = Mathf.Clamp(columns, 1, 10); ((BaseUnityPlugin)Instance).Config.Save(); } } public static string FormatMenuHotkey() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) KeyCode menuKey = GetMenuKey(); if (!GetRequireMenuModifier()) { return PrettyKey(menuKey); } KeyCode menuModifier = GetMenuModifier(); if ((int)menuModifier == 0) { return PrettyKey(menuKey); } return PrettyKey(menuModifier) + " + " + PrettyKey(menuKey); } public unsafe static string PrettyKey(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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0009: 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_0065: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0067: 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_0093: Expected I4, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if ((int)key <= 32) { if ((int)key <= 8) { if ((int)key == 0) { return "None"; } if ((int)key == 8) { return "Backspace"; } } else { if ((int)key == 13) { return "Enter"; } if ((int)key == 27) { return "Esc"; } if ((int)key == 32) { return "Space"; } } } else if ((int)key <= 91) { if ((int)key == 45) { return "-"; } if ((int)key == 61) { return "="; } if ((int)key == 91) { return "["; } } else { if ((int)key == 93) { return "]"; } if ((int)key == 127) { return "Delete"; } switch (key - 303) { case 3: return "Left Ctrl"; case 2: return "Right Ctrl"; case 5: return "Left Alt"; case 4: return "Right Alt"; case 1: return "Left Shift"; case 0: return "Right Shift"; case 7: return "Left Cmd"; case 6: return "Right Cmd"; } } string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Alpha", StringComparison.Ordinal) && text.Length == 6) { return text.Substring(5); } if (text.StartsWith("Keypad", StringComparison.Ordinal)) { return "Num " + text.Substring("Keypad".Length); } return text; } private static KeyCode Get(ConfigEntry<KeyCode> entry, KeyCode fallback) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) return entry?.Value ?? fallback; } private static void Set(ConfigEntry<KeyCode> entry, KeyCode key) { //IL_0003: 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) if (entry != null && (int)key != 0 && !((Object)(object)Instance == (Object)null)) { entry.Value = key; ((BaseUnityPlugin)Instance).Config.Save(); } } } internal sealed class CatalogItem { public ushort Id; public string DisplayName; public string PrefabName; public Item Prefab; } internal static class ItemCatalog { private static readonly List<CatalogItem> _items = new List<CatalogItem>(); private static readonly Dictionary<int, CatalogItem> _byInstance = new Dictionary<int, CatalogItem>(); private static readonly HashSet<int> _seenInstances = new HashSet<int>(); private static readonly HashSet<string> _seenKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase); public static bool IsReady { get; private set; } public static int Count => _items.Count; public static IReadOnlyList<CatalogItem> Items => _items; public static bool TryRefresh() { return TryRefresh(includeLoadedAssets: false); } public static bool TryRefresh(bool includeLoadedAssets) { if (!TryGetDatabase(out var db) || (Object)(object)db == (Object)null) { return false; } List<Item> list = new List<Item>(); HashSet<int> seen = new HashSet<int>(); if (db.itemLookup != null) { foreach (KeyValuePair<ushort, Item> item2 in db.itemLookup) { Consider(list, seen, item2.Value); } } if (((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects != null) { for (int i = 0; i < ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects.Count; i++) { Consider(list, seen, ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects[i]); } } if (includeLoadedAssets) { CollectLoadedItems(list, seen); } if (list.Count == 0) { return IsReady; } int num = 0; for (int j = 0; j < list.Count; j++) { Item val = list[j]; if (!((Object)(object)val == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); string item = Key(val); if (_seenInstances.Add(instanceID) && _seenKeys.Add(item)) { CatalogItem catalogItem = new CatalogItem { Id = val.itemID, Prefab = val, PrefabName = SafePrefabName(val), DisplayName = SafeDisplayName(val) }; _items.Add(catalogItem); _byInstance[instanceID] = catalogItem; num++; } } } if (num > 0) { _items.Sort(Compare); } IsReady = _items.Count > 0; return IsReady; } public static bool TryResolve(ushort itemId, string prefabName, out CatalogItem item) { item = null; if (!string.IsNullOrEmpty(prefabName)) { for (int i = 0; i < _items.Count; i++) { CatalogItem catalogItem = _items[i]; if (catalogItem != null && string.Equals(catalogItem.PrefabName, prefabName, StringComparison.OrdinalIgnoreCase)) { item = catalogItem; return (Object)(object)catalogItem.Prefab != (Object)null; } } } if (itemId != 0) { for (int j = 0; j < _items.Count; j++) { CatalogItem catalogItem2 = _items[j]; if (catalogItem2 != null && catalogItem2.Id == itemId) { item = catalogItem2; return (Object)(object)catalogItem2.Prefab != (Object)null; } } Item val = default(Item); if (ItemDatabase.TryGetItem(itemId, ref val) && (Object)(object)val != (Object)null) { item = new CatalogItem { Id = val.itemID, Prefab = val, PrefabName = SafePrefabName(val), DisplayName = SafeDisplayName(val) }; return true; } } return false; } public static string GetName(ushort id, string prefabName) { if (TryResolve(id, prefabName, out var item) && item != null) { return item.DisplayName; } if (string.IsNullOrEmpty(prefabName)) { return "Item " + id; } return prefabName; } public static bool TryGetDatabase(out ItemDatabase db) { db = null; try { db = SingletonAsset<ItemDatabase>.Instance; } catch { try { db = SingletonAsset<ItemDatabase>.Instance; } catch { return false; } } return (Object)(object)db != (Object)null; } public static string SafePrefabName(Item item) { try { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && !string.IsNullOrEmpty(((Object)((Component)item).gameObject).name)) { string text = ((Object)((Component)item).gameObject).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num).Trim(); } return text; } if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(((Object)item).name)) { return ((Object)item).name; } } catch { } return "unknown"; } public static string SafeDisplayName(Item item) { try { if ((Object)(object)item != (Object)null) { try { string itemName = item.GetItemName((ItemInstanceData)null); if (!string.IsNullOrEmpty(itemName) && itemName.IndexOf("NAME_", StringComparison.OrdinalIgnoreCase) < 0) { return itemName; } } catch { } if (item.UIData != null && !string.IsNullOrEmpty(item.UIData.itemName)) { try { string name = item.GetName(); if (!string.IsNullOrEmpty(name) && name.IndexOf("NAME_", StringComparison.OrdinalIgnoreCase) < 0) { return name; } } catch { } return Prettify(item.UIData.itemName); } } } catch { } return Prettify(SafePrefabName(item)); } private static void CollectLoadedItems(List<Item> found, HashSet<int> seen) { try { Item[] array = Resources.FindObjectsOfTypeAll<Item>(); if (array != null) { for (int i = 0; i < array.Length; i++) { Consider(found, seen, array[i]); } } } catch { } try { List<Item> aLL_ACTIVE_ITEMS = Item.ALL_ACTIVE_ITEMS; if (aLL_ACTIVE_ITEMS != null) { for (int j = 0; j < aLL_ACTIVE_ITEMS.Count; j++) { Consider(found, seen, aLL_ACTIVE_ITEMS[j]); } } } catch { } try { List<Item> aLL_ITEMS = Item.ALL_ITEMS; if (aLL_ITEMS != null) { for (int k = 0; k < aLL_ITEMS.Count; k++) { Consider(found, seen, aLL_ITEMS[k]); } } } catch { } } private static void Consider(List<Item> found, HashSet<int> seen, Item item) { if (!((Object)(object)item == (Object)null) && !((Object)(object)((Component)item).gameObject == (Object)null)) { int instanceID = ((Object)item).GetInstanceID(); if (seen.Add(instanceID)) { found.Add(item); } } } private static string Key(Item item) { return SafePrefabName(item).ToLowerInvariant() + "|" + (((Object)(object)item != (Object)null) ? item.itemID : 0); } private static int Compare(CatalogItem a, CatalogItem b) { int num = string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); if (num == 0) { return string.Compare(a.PrefabName, b.PrefabName, StringComparison.OrdinalIgnoreCase); } return num; } private static string Prettify(string name) { if (string.IsNullOrEmpty(name)) { return "Unknown"; } StringBuilder stringBuilder = new StringBuilder(name.Length + 8); for (int i = 0; i < name.Length; i++) { char c = name[i]; if (c == '_' || c == '-') { stringBuilder.Append(' '); continue; } if (i > 0 && char.IsUpper(c) && !char.IsUpper(name[i - 1]) && name[i - 1] != ' ') { stringBuilder.Append(' '); } stringBuilder.Append(c); } return stringBuilder.ToString().Trim(); } } internal sealed class BeltPick { public ushort ItemId; public string PrefabName; public bool Protected; public int Count = 1; } [Serializable] internal sealed class SavedBeltFile { public int version = 2; public SavedBeltItem[] items = new SavedBeltItem[0]; } [Serializable] internal sealed class SavedBeltItem { public int id; public string prefab; public bool oneTime; public bool isProtected; public int count = 1; } internal static class BeltStore { internal const int FileVersion = 2; internal const int MinCount = 1; internal const int MaxCount = 99; internal static readonly BeltPick[] Defaults = new BeltPick[4] { Pick("Binoculars", 14, isProtected: true, 1), Pick("Bugle", 15, isProtected: true, 1), Pick("Compass", 23, isProtected: true, 1), Pick("Guidebook", 34, isProtected: true, 1) }; private static readonly List<BeltPick> _local = new List<BeltPick>(); private static readonly List<BeltPick> _host = new List<BeltPick>(); private static bool _useHost; private static bool _loaded; private static string _path; private static readonly string[] LegacyDefaultNames = new string[16] { "Binoculars", "Bugle", "Compass", "Conch", "Flare", "Frisbee", "Guidebook", "Lantern", "Megaphone", "Piton", "Passport", "RopeSpool", "SeagullFlag", "SportsDrink", "TrailMix", "TurtleFlag" }; public static bool HostControls => _useHost; public static int LocalCount => _local.Count; public static IReadOnlyList<BeltPick> Active { get { if (!_useHost) { return _local; } return _host; } } public static void Initialize() { if (!_loaded) { _path = Path.Combine(Paths.ConfigPath, "tony4twentys.PEAK_Tool_Belt.items.json"); if (!Load() || _local.Count == 0) { SeedDefaults(); Save(); } _loaded = true; Plugin.Log.LogInfo((object)("Belt list has " + _local.Count + " saved item(s).")); } } public static void ApplyHost(IList<BeltPick> picks) { _host.Clear(); CopyInto(_host, picks); _useHost = true; ToolBeltItems.RefreshResolved(); if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.OnBeltListChanged(); } } public static void ClearHost() { _useHost = false; _host.Clear(); ToolBeltItems.RefreshResolved(); if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.OnBeltListChanged(); } } public static bool IsOnBelt(ushort id, string prefabName) { return Find(Active, id, prefabName) != null; } public static bool IsProtected(ushort id, string prefabName) { return Find(Active, id, prefabName)?.Protected ?? false; } public static int GetCount(ushort id, string prefabName) { BeltPick beltPick = Find(Active, id, prefabName); if (beltPick == null) { return 1; } return ClampCount(beltPick.Count); } public static bool IsDefault(ushort id, string prefabName) { return Find(Defaults, id, prefabName) != null; } public static void SetOnBelt(CatalogItem item, bool on) { if (item == null || _useHost) { return; } BeltPick beltPick = Find(_local, item.Id, item.PrefabName); if (on) { if (beltPick == null) { _local.Add(new BeltPick { ItemId = item.Id, PrefabName = item.PrefabName, Protected = false, Count = 1 }); SortLocal(); } } else if (beltPick != null) { _local.Remove(beltPick); } PersistAndRefresh(); } public static void SetProtected(CatalogItem item, bool isProtected) { if (item == null || _useHost) { return; } BeltPick beltPick = Find(_local, item.Id, item.PrefabName); if (beltPick == null) { if (!isProtected) { return; } _local.Add(new BeltPick { ItemId = item.Id, PrefabName = item.PrefabName, Protected = true, Count = 1 }); SortLocal(); } else { beltPick.Protected = isProtected; } PersistAndRefresh(); } public static void SetCount(CatalogItem item, int count) { if (item != null && !_useHost) { count = ClampCount(count); BeltPick beltPick = Find(_local, item.Id, item.PrefabName); if (beltPick != null) { beltPick.Count = count; PersistAndRefresh(); } } } public static void ResetDefaults() { if (!_useHost) { SeedDefaults(); PersistAndRefresh(); } } public static void ClearAll() { if (!_useHost) { _local.Clear(); PersistAndRefresh(); } } public static List<BeltPick> SnapshotLocal() { return Clone(_local); } public static void ReplaceLocal(IList<BeltPick> picks) { if (!_useHost) { _local.Clear(); CopyInto(_local, picks); SortLocal(); PersistAndRefresh(); } } public static bool TryExport(string path, out string error) { error = null; try { if (string.IsNullOrEmpty(path)) { error = "No preset path."; return false; } File.WriteAllText(path, BuildJson(ToFile(_local))); return true; } catch (Exception ex) { error = "Could not save preset: " + ex.Message; return false; } } public static bool TryImport(string path, out List<BeltPick> picks, out string error) { picks = null; error = null; try { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { error = "Preset file is missing."; return false; } if (!TryParse(File.ReadAllText(path), out picks) || picks == null) { error = "Preset file is empty or invalid."; return false; } return true; } catch (Exception ex) { error = "Could not load preset: " + ex.Message; return false; } } public static int ClampCount(int count) { if (count < 1) { return 1; } if (count > 99) { return 99; } return count; } private static void PersistAndRefresh() { Save(); ToolBeltItems.RefreshResolved(); ToolBeltNet.OnLocalSettingChanged(); if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.OnBeltListChanged(); } } private static void SeedDefaults() { _local.Clear(); for (int i = 0; i < Defaults.Length; i++) { BeltPick beltPick = Defaults[i]; _local.Add(new BeltPick { ItemId = beltPick.ItemId, PrefabName = beltPick.PrefabName, Protected = beltPick.Protected, Count = ClampCount(beltPick.Count) }); } } private static bool Load() { try { if (string.IsNullOrEmpty(_path) || !File.Exists(_path)) { return false; } if (!TryParse(File.ReadAllText(_path), out var picks) || picks == null || picks.Count == 0) { return false; } _local.Clear(); CopyInto(_local, picks); SavedBeltFile savedBeltFile = JsonUtility.FromJson<SavedBeltFile>(File.ReadAllText(_path)); int num; if (savedBeltFile != null) { num = ((savedBeltFile.version < 2) ? 1 : 0); if (num != 0 && LooksLikeOriginalDefaultSet()) { SeedDefaults(); } } else { num = 0; } if (num != 0) { Save(); } return _local.Count > 0; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not load belt item list: " + ex.Message)); return false; } } private static bool TryParse(string json, out List<BeltPick> picks) { picks = new List<BeltPick>(); if (string.IsNullOrEmpty(json)) { return false; } SavedBeltFile savedBeltFile = JsonUtility.FromJson<SavedBeltFile>(json); if (savedBeltFile == null || savedBeltFile.items == null) { return false; } bool flag = savedBeltFile.version < 2; for (int i = 0; i < savedBeltFile.items.Length; i++) { SavedBeltItem savedBeltItem = savedBeltFile.items[i]; if (savedBeltItem != null) { picks.Add(new BeltPick { ItemId = (ushort)((savedBeltItem.id > 0 && savedBeltItem.id <= 65535) ? ((ushort)savedBeltItem.id) : 0), PrefabName = (savedBeltItem.prefab ?? string.Empty), Protected = (flag ? (!savedBeltItem.oneTime) : savedBeltItem.isProtected), Count = ClampCount(savedBeltItem.count) }); } } if (picks.Count <= 0) { return savedBeltFile.items.Length == 0; } return true; } private static SavedBeltFile ToFile(IList<BeltPick> picks) { int num = picks?.Count ?? 0; SavedBeltFile savedBeltFile = new SavedBeltFile { version = 2, items = new SavedBeltItem[num] }; for (int i = 0; i < num; i++) { BeltPick beltPick = picks[i]; savedBeltFile.items[i] = new SavedBeltItem { id = (beltPick?.ItemId ?? 0), prefab = ((beltPick != null && beltPick.PrefabName != null) ? beltPick.PrefabName : string.Empty), isProtected = (beltPick?.Protected ?? false), count = ((beltPick == null) ? 1 : ClampCount(beltPick.Count)) }; } return savedBeltFile; } private static void Save() { try { if (!string.IsNullOrEmpty(_path)) { File.WriteAllText(_path, BuildJson(ToFile(_local))); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not save belt item list: " + ex.Message)); } } private static string BuildJson(SavedBeltFile file) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"version\": " + 2 + ","); stringBuilder.AppendLine(" \"items\": ["); SavedBeltItem[] array = ((file != null && file.items != null) ? file.items : new SavedBeltItem[0]); for (int i = 0; i < array.Length; i++) { SavedBeltItem savedBeltItem = array[i] ?? new SavedBeltItem(); string value = (savedBeltItem.prefab ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\""); stringBuilder.Append(" {\"id\": "); stringBuilder.Append(savedBeltItem.id); stringBuilder.Append(", \"prefab\": \""); stringBuilder.Append(value); stringBuilder.Append("\", \"isProtected\": "); stringBuilder.Append(savedBeltItem.isProtected ? "true" : "false"); stringBuilder.Append(", \"count\": "); stringBuilder.Append(ClampCount(savedBeltItem.count)); stringBuilder.Append("}"); stringBuilder.AppendLine((i < array.Length - 1) ? "," : string.Empty); } stringBuilder.AppendLine(" ]"); stringBuilder.AppendLine("}"); return stringBuilder.ToString(); } private static BeltPick Find(IReadOnlyList<BeltPick> list, ushort id, string prefabName) { if (list == null) { return null; } if (!string.IsNullOrEmpty(prefabName)) { for (int i = 0; i < list.Count; i++) { if (list[i] != null && string.Equals(list[i].PrefabName, prefabName, StringComparison.OrdinalIgnoreCase)) { return list[i]; } } } if (id == 0) { return null; } for (int j = 0; j < list.Count; j++) { if (list[j] != null && list[j].ItemId == id) { return list[j]; } } return null; } private static bool LooksLikeOriginalDefaultSet() { if (_local.Count != LegacyDefaultNames.Length) { return false; } for (int i = 0; i < LegacyDefaultNames.Length; i++) { if (Find(_local, 0, LegacyDefaultNames[i]) == null) { return false; } } return true; } private static void SortLocal() { _local.Sort(delegate(BeltPick a, BeltPick b) { string strA = ((a != null) ? a.PrefabName : string.Empty); string strB = ((b != null) ? b.PrefabName : string.Empty); return string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); }); } private static void CopyInto(List<BeltPick> dest, IList<BeltPick> src) { if (src == null) { return; } for (int i = 0; i < src.Count; i++) { if (src[i] != null) { dest.Add(new BeltPick { ItemId = src[i].ItemId, PrefabName = (src[i].PrefabName ?? string.Empty), Protected = src[i].Protected, Count = ClampCount(src[i].Count) }); } } } private static List<BeltPick> Clone(List<BeltPick> src) { List<BeltPick> list = new List<BeltPick>(src.Count); CopyInto(list, src); return list; } private static BeltPick Pick(string prefab, ushort id, bool isProtected, int count) { return new BeltPick { PrefabName = prefab, ItemId = id, Protected = isProtected, Count = ClampCount(count) }; } } internal static class BeltPresetStore { public const string DefaultName = "default"; private static string _folder; public static string FolderPath { get { EnsureFolder(); return _folder; } } public static void Initialize() { EnsureFolder(); } public static List<string> ListNames() { List<string> list = new List<string>(); EnsureFolder(); if (string.IsNullOrEmpty(_folder) || !Directory.Exists(_folder)) { return list; } try { string[] files = Directory.GetFiles(_folder, "*.json"); for (int i = 0; i < files.Length; i++) { list.Add(Path.GetFileNameWithoutExtension(files[i])); } list.Sort(StringComparer.OrdinalIgnoreCase); int num = list.FindIndex(IsDefaultName); if (num > 0) { string item = list[num]; list.RemoveAt(num); list.Insert(0, item); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to list presets: " + ex.Message)); } return list; } public static bool Save(string name, out string error) { error = null; if (BeltStore.HostControls) { error = "The host controls the belt list in this lobby."; return false; } string text = Sanitize(name); if (string.IsNullOrEmpty(text)) { error = "Type a name for this preset first."; return false; } EnsureFolder(); if (string.IsNullOrEmpty(_folder)) { error = "Could not create the Presets folder next to the plugin."; return false; } if (!BeltStore.TryExport(Path.Combine(_folder, text + ".json"), out error)) { return false; } Plugin.Log.LogInfo((object)("Saved belt preset " + text + " (" + BeltStore.LocalCount + " item(s)).")); return true; } public static bool Load(string name, out string error) { error = null; if (BeltStore.HostControls) { error = "The host controls the belt list in this lobby."; return false; } string text = Sanitize(name); if (string.IsNullOrEmpty(text)) { error = "Pick a preset to load."; return false; } EnsureFolder(); if (!BeltStore.TryImport(Path.Combine(_folder ?? string.Empty, text + ".json"), out var picks, out error)) { return false; } BeltStore.ReplaceLocal(picks); Plugin.Log.LogInfo((object)("Loaded belt preset " + text + " (" + BeltStore.LocalCount + " item(s)).")); return true; } public static void SaveDefaultQuiet() { if (BeltStore.HostControls) { return; } try { EnsureFolder(); if (!string.IsNullOrEmpty(_folder)) { BeltStore.TryExport(Path.Combine(_folder, "default.json"), out var _); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to save default preset: " + ex.Message)); } } public static bool IsDefaultName(string name) { return string.Equals(Sanitize(name), "default", StringComparison.OrdinalIgnoreCase); } public static bool Delete(string name, out string error) { error = null; string text = Sanitize(name); if (string.IsNullOrEmpty(text)) { error = "Pick a preset to delete."; return false; } if (IsDefaultName(text)) { error = "The default preset is updated automatically when you close the menu."; return false; } EnsureFolder(); string path = Path.Combine(_folder ?? string.Empty, text + ".json"); if (!File.Exists(path)) { error = "No preset named \"" + text + "\"."; return false; } try { File.Delete(path); return true; } catch (Exception ex) { error = "Failed to delete preset: " + ex.Message; Plugin.Log.LogWarning((object)error); return false; } } public static string Sanitize(string name) { if (string.IsNullOrWhiteSpace(name)) { return string.Empty; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); char[] array = name.Trim().ToCharArray(); for (int i = 0; i < array.Length; i++) { char c = array[i]; bool flag = c < ' '; if (!flag) { for (int j = 0; j < invalidFileNameChars.Length; j++) { if (c == invalidFileNameChars[j]) { flag = true; break; } } } if (flag) { array[i] = '_'; } } string text = new string(array).Trim(); if (text.Length > 40) { text = text.Substring(0, 40).Trim(); } return text; } private static void EnsureFolder() { if (!string.IsNullOrEmpty(_folder) && Directory.Exists(_folder)) { return; } try { string location = typeof(Plugin).Assembly.Location; string text = (string.IsNullOrEmpty(location) ? null : Path.GetDirectoryName(location)); if (string.IsNullOrEmpty(text)) { text = Paths.PluginPath; } _folder = Path.Combine(text, "Presets"); Directory.CreateDirectory(_folder); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to create Presets folder: " + ex.Message)); } } } internal sealed class BeltEntry { public ushort ItemId; public string PrefabName; public string DisplayName; public bool Protected; public int SpawnLimit; public int Remaining; public Item Prefab; } internal static class ToolBeltItems { private struct RemainingSnap { public int Limit; public int Left; } private static readonly List<BeltEntry> _all = new List<BeltEntry>(); private static readonly List<BeltEntry> _visible = new List<BeltEntry>(); public static int VisibleCount => _visible.Count; public static IReadOnlyList<BeltEntry> Visible => _visible; public static bool DatabaseReady() { if (ItemCatalog.TryGetDatabase(out var db) && (Object)(object)db != (Object)null && ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects != null) { return ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects.Count > 0; } return false; } public static bool TryGetVisible(int index, out BeltEntry entry) { if (index >= 0 && index < _visible.Count) { entry = _visible[index]; return entry != null; } entry = null; return false; } public static void LoadLocal() { if (!BeltStore.HostControls) { RefreshResolved(); } } public static void RefreshResolved() { Rebuild(); } public static void Restock() { Rebuild(); for (int i = 0; i < _all.Count; i++) { BeltEntry beltEntry = _all[i]; if (beltEntry != null) { beltEntry.Remaining = (beltEntry.Protected ? 1 : beltEntry.SpawnLimit); } } RefreshVisible(); } public static void Consume(BeltEntry entry) { if (entry != null && !entry.Protected) { entry.Remaining = Mathf.Max(0, entry.Remaining - 1); RefreshVisible(); } } internal static string PrefabName(Item item) { return ItemCatalog.SafePrefabName(item); } internal static string DisplayName(Item item, string fallback) { string text = ItemCatalog.SafeDisplayName(item); if (!string.IsNullOrEmpty(text)) { return text; } return fallback; } private static void Rebuild() { Dictionary<string, RemainingSnap> dictionary = new Dictionary<string, RemainingSnap>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < _all.Count; i++) { BeltEntry beltEntry = _all[i]; if (beltEntry != null) { dictionary[Key(beltEntry.ItemId, beltEntry.PrefabName)] = new RemainingSnap { Limit = beltEntry.SpawnLimit, Left = beltEntry.Remaining }; } } _all.Clear(); IReadOnlyList<BeltPick> active = BeltStore.Active; for (int j = 0; j < active.Count; j++) { BeltPick beltPick = active[j]; if (beltPick != null && ItemCatalog.TryResolve(beltPick.ItemId, beltPick.PrefabName, out var item) && item != null && !((Object)(object)item.Prefab == (Object)null)) { int num = ((!beltPick.Protected) ? BeltStore.ClampCount(beltPick.Count) : 0); int remaining = (beltPick.Protected ? 1 : num); if (dictionary.TryGetValue(Key(item.Id, item.PrefabName), out var value)) { int num2 = Mathf.Max(0, value.Limit - value.Left); remaining = (beltPick.Protected ? 1 : Mathf.Max(0, num - num2)); } _all.Add(new BeltEntry { ItemId = item.Id, PrefabName = item.PrefabName, DisplayName = item.DisplayName, Protected = beltPick.Protected, SpawnLimit = num, Remaining = remaining, Prefab = item.Prefab }); } } RefreshVisible(); } private static void RefreshVisible() { _visible.Clear(); for (int i = 0; i < _all.Count; i++) { BeltEntry beltEntry = _all[i]; if (beltEntry != null && !((Object)(object)beltEntry.Prefab == (Object)null) && (beltEntry.Protected || beltEntry.Remaining > 0)) { _visible.Add(beltEntry); } } } private static string Key(ushort id, string prefab) { return (prefab ?? string.Empty).ToLowerInvariant() + "|" + id; } } internal enum GrantResult { Failed, EquippedExisting, Recalled, Pocket, Hand } internal static class ToolBeltGrant { public static GrantResult TryGive(BeltEntry entry) { try { if (entry == null || (Object)(object)entry.Prefab == (Object)null) { return GrantResult.Failed; } Character localCharacter = Character.localCharacter; Player val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.player : Player.localPlayer); if ((Object)(object)localCharacter == (Object)null || (Object)(object)val == (Object)null) { return GrantResult.Failed; } if (Plugin.IsGameplayBlocked()) { return GrantResult.Failed; } if (entry.Protected) { if ((Object)(object)ToolBeltMark.FindHeld(entry) != (Object)null) { return GrantResult.EquippedExisting; } int num = ToolBeltMark.FindOwnedSlot(val, entry); if (num >= 0) { Equip(localCharacter, (byte)num); return GrantResult.EquippedExisting; } if (ToolBeltMark.HasOwnedCopy(val, entry)) { return GrantResult.EquippedExisting; } Item val2 = ToolBeltMark.FindWorldCopy(entry); if ((Object)(object)val2 != (Object)null) { if (ToolBeltMark.CanPickup(val, entry)) { try { val2.Interact(localCharacter); return GrantResult.Recalled; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not pick up existing belt item: " + ex.Message)); } } if (!ToolBeltMark.TryDestroyWorld(val2) || !ToolBeltMark.CanPickup(val, entry)) { return GrantResult.Recalled; } } } int num2 = FindEmptyPocket(val); if (num2 >= 0 && TryPutInPocket(val, entry, num2)) { SyncInventory(val); Equip(localCharacter, (byte)num2); return GrantResult.Pocket; } if (TrySpawnInHand(localCharacter, entry)) { return GrantResult.Hand; } Plugin.Log.LogWarning((object)("Could not give '" + entry.DisplayName + "'.")); return GrantResult.Failed; } catch (Exception ex2) { Plugin.Log.LogError((object)("Tool belt grant failed: " + ex2)); return GrantResult.Failed; } } private static int FindEmptyPocket(Player player) { if ((Object)(object)player == (Object)null || player.itemSlots == null) { return -1; } for (int i = 0; i < player.itemSlots.Length; i++) { ItemSlot val = player.itemSlots[i]; if (val != null && val.IsEmpty()) { return i; } } return -1; } private static bool TryPutInPocket(Player player, BeltEntry entry, int slotIndex) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown if ((Object)(object)player == (Object)null || player.itemSlots == null || entry == null || (Object)(object)entry.Prefab == (Object)null) { return false; } if (slotIndex < 0 || slotIndex >= player.itemSlots.Length) { return false; } ItemSlot val = player.itemSlots[slotIndex]; if (val == null || !val.IsEmpty()) { return false; } ItemInstanceData val2 = new ItemInstanceData(Guid.NewGuid()); ItemInstanceDataHandler.AddInstanceData(val2); ToolBeltMark.Apply(val2, entry.Protected); val.SetItem(entry.Prefab, val2); return !val.IsEmpty(); } private static void Equip(Character character, byte slotId) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.items == (Object)null) { return; } try { character.refs.items.EquipSlot(Optionable<byte>.Some(slotId)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not equip slot " + slotId + ": " + ex.Message)); } } private static bool TrySpawnInHand(Character character, BeltEntry entry) { if ((Object)(object)character == (Object)null || entry == null || (Object)(object)entry.Prefab == (Object)null || character.refs == null || (Object)(object)character.refs.items == (Object)null) { return false; } string text = ToolBeltItems.PrefabName(entry.Prefab); if (string.IsNullOrEmpty(text)) { return false; } try { ToolBeltMark.ExpectSpawn(text, entry.Protected); character.refs.items.SpawnItemInHand(text); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("SpawnItemInHand failed for " + text + ": " + ex.Message)); return false; } } private static void SyncInventory(Player player) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) try { PhotonView val = null; if ((Object)(object)player != (Object)null) { try { val = player.view; } catch { } if ((Object)(object)val == (Object)null) { try { val = ((MonoBehaviourPun)player).photonView; } catch { } } } if (!((Object)(object)val == (Object)null)) { InventorySyncData val2 = default(InventorySyncData); ((InventorySyncData)(ref val2))..ctor(player.itemSlots, player.backpackSlot, player.tempFullSlot); val.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2] { IBinarySerializable.ToManagedArray<InventorySyncData>(val2), false }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Inventory sync failed: " + ex.Message)); } } } internal static class ToolBeltMark { [HarmonyPatch(typeof(Item), "Start")] private static class Patch_ItemStart { private static void Postfix(Item __instance) { if (!((Object)(object)__instance == (Object)null)) { RestoreRemembered(__instance); if (PendingMatches(__instance) || IsProtectedBeltItem(__instance)) { ScheduleDeferredTag(__instance); } } } } [HarmonyPatch(typeof(Item), "SetItemInstanceDataRPC")] private static class Patch_SetItemInstanceData { private static void Postfix(Item __instance) { if (!((Object)(object)__instance == (Object)null)) { RestoreRemembered(__instance); } } } [HarmonyPatch(typeof(Item), "OnStash")] private static class Patch_OnStash { private static void Prefix(Item __instance) { if (!((Object)(object)__instance == (Object)null) && IsProtectedBeltItem(__instance)) { Apply(__instance, isProtected: true); } } } [HarmonyPatch(typeof(Item), "OnDestroy")] private static class Patch_OnDestroy { private static void Prefix(Item __instance) { PhotonView val = ItemView(__instance); if ((Object)(object)val != (Object)null) { _flagByView.Remove(val.ViewID); } } } [HarmonyPatch(typeof(Item), "Interact")] private static class Patch_ItemInteract { private static void Postfix(Item __instance, Character interactor) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null) && !((Object)(object)interactor != (Object)(object)Character.localCharacter) && PendingMatches(__instance)) { Apply(__instance, _pendingProtected); ClearPending(); } } } [HarmonyPatch(typeof(CharacterItems), "DropItemRpc")] private static class Patch_DropItemRpc { private static bool Prefix(CharacterItems __instance, byte slotID, ItemInstanceData itemInstanceData) { try { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.character == (Object)null) { return true; } Item val = (((Object)(object)__instance.character.data != (Object)null) ? __instance.character.data.currentItem : null); ItemSlot val2 = (((Object)(object)__instance.character.player != (Object)null) ? __instance.character.player.GetItemSlot(slotID) : null); Item prefab = (((Object)(object)val != (Object)null) ? val : ((val2 != null) ? val2.prefab : null)); if (!IsProtectedBeltItem(val) && !IsProtectedBeltItem(prefab, itemInstanceData) && (val2 == null || !IsProtectedBeltItem(val2.prefab, val2.data))) { return true; } CancelHeldProtected(__instance, slotID); return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Protected belt drop swallow failed: " + ex.Message)); return true; } } } [HarmonyPatch(typeof(CharacterItems), "DropItemFromSlotRPC")] private static class Patch_DropItemFromSlotRpc { private static bool Prefix(CharacterItems __instance, byte slotID) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.character == (Object)null || (Object)(object)__instance.character.player == (Object)null) { return true; } ItemSlot itemSlot = __instance.character.player.GetItemSlot(slotID); if (itemSlot == null || itemSlot.IsEmpty() || !IsProtectedBeltItem(itemSlot.prefab, itemSlot.data)) { return true; } __instance.character.player.EmptySlot(Optionable<byte>.Some(slotID), true); if (__instance.character.refs != null && (Object)(object)__instance.character.refs.afflictions != (Object)null) { __instance.character.refs.afflictions.UpdateWeight(); } return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Protected belt slot-drop swallow failed: " + ex.Message)); return true; } } } internal static readonly DataEntryKey FlagKey = (DataEntryKey)165; internal static readonly DataEntryKey ActorKey = (DataEntryKey)166; internal const int FlagUnprotected = 1; internal const int FlagProtected = 2; private static string _pendingPrefab; private static bool _pendingProtected; private static float _pendingUntil; private static readonly Dictionary<int, int> _flagByView = new Dictionary<int, int>(); private static readonly HashSet<int> _tagInFlight = new HashSet<int>(); public static void ExpectSpawn(string prefabName, bool isProtected) { _pendingPrefab = prefabName ?? string.Empty; _pendingProtected = isProtected; _pendingUntil = Time.unscaledTime + 8f; } public static void Apply(Item item, bool isProtected) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (!((Object)(object)item == (Object)null)) { if (item.data == null) { item.data = new ItemInstanceData(Guid.NewGuid()); ItemInstanceDataHandler.AddInstanceData(item.data); } Apply(item.data, isProtected); RememberView(item, isProtected); CopyToHolderSlot(item); PushItemInstanceData(item); } } public static void Apply(ItemInstanceData data, bool isProtected) { //IL_0005: 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) if (data != null) { SetInt(data, FlagKey, (!isProtected) ? 1 : 2); SetInt(data, ActorKey, LocalActor()); } } public static bool IsProtectedBeltItem(Item item) { if ((Object)(object)item != (Object)null) { return ReadFlag(item.data) == 2; } return false; } public static bool IsProtectedBeltItem(Item prefab, ItemInstanceData data) { return ReadFlag(data) == 2; } public static bool IsBeltMarked(ItemInstanceData data) { int num = ReadFlag(data); if (num != 2) { return num == 1; } return true; } public static int FindOwnedSlot(Player player, BeltEntry entry) { if ((Object)(object)player == (Object)null || entry == null) { return -1; } int num = FindSlot(player.itemSlots, entry); if (num >= 0) { return num; } if (SlotMatches(player.tempFullSlot, entry)) { if (player.tempFullSlot == null) { return -1; } return player.tempFullSlot.itemSlotID; } return -1; } public static bool HasOwnedCopy(Player player, BeltEntry entry) { if ((Object)(object)FindHeld(entry) != (Object)null) { return true; } if (FindOwnedSlot(player, entry) >= 0) { return true; } return HasInBackpack(player, entry); } public static Item FindHeld(BeltEntry entry) { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && SameItem(localCharacter.data.currentItem, entry)) { return localCharacter.data.currentItem; } return FindLive(entry, held: true, ground: false); } public static Item FindWorldCopy(BeltEntry entry) { return FindLive(entry, held: false, ground: true); } public static bool CanPickup(Player player, BeltEntry entry) { if ((Object)(object)player == (Object)null || entry == null) { return false; } try { return player.HasEmptySlot(entry.ItemId); } catch { return FindEmptyPocketIndex(player) >= 0; } } public static int FindEmptyPocketIndex(Player player) { if ((Object)(object)player == (Object)null || player.itemSlots == null) { return -1; } for (int i = 0; i < player.itemSlots.Length; i++) { if (player.itemSlots[i] != null && player.itemSlots[i].IsEmpty()) { return i; } } return -1; } public static bool TryDestroyWorld(Item item) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { return false; } try { PhotonView val = ItemView(item); if ((Object)(object)val != (Object)null && (val.IsMine || PhotonNetwork.IsMasterClient)) { PhotonNetwork.Destroy(((Component)item).gameObject); return true; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not destroy leftover belt item: " + ex.Message)); } return false; } internal static bool SameItem(Item prefabOrInstance, BeltEntry entry) { if ((Object)(object)prefabOrInstance == (Object)null || entry == null) { return false; } if (entry.ItemId != 0 && prefabOrInstance.itemID == entry.ItemId) { return true; } if ((Object)(object)entry.Prefab != (Object)null && prefabOrInstance.itemID == entry.Prefab.itemID) { return true; } return string.Equals(ToolBeltItems.PrefabName(prefabOrInstance), entry.PrefabName, StringComparison.OrdinalIgnoreCase); } private static Item FindLive(BeltEntry entry, bool held, bool ground) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (entry == null) { return null; } Character localCharacter = Character.localCharacter; List<Item> aLL_ACTIVE_ITEMS = Item.ALL_ACTIVE_ITEMS; if (aLL_ACTIVE_ITEMS == null) { return null; } Item result = null; float num = 25f; Vector3 val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.Center : Vector3.zero); for (int i = 0; i < aLL_ACTIVE_ITEMS.Count; i++) { Item val2 = aLL_ACTIVE_ITEMS[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null || !SameItem(val2, entry)) { continue; } if (held) { if ((Object)(object)val2.holderCharacter == (Object)(object)localCharacter) { return val2; } } else { if (!ground || (int)val2.itemState != 0 || ((Object)(object)val2.holderCharacter != (Object)null && (Object)(object)val2.holderCharacter != (Object)(object)localCharacter)) { continue; } if ((Object)(object)val2.lastHolderCharacter == (Object)(object)localCharacter || IsBeltMarked(val2.data)) { return val2; } if (!((Object)(object)val2.lastHolderCharacter != (Object)null) && !((Object)(object)localCharacter == (Object)null)) { float num2 = Vector3.Distance(val2.transform.position, val); if (num2 < num) { result = val2; num = num2; } } } } return result; } private static int FindSlot(ItemSlot[] slots, BeltEntry entry) { if (slots == null) { return -1; } for (int i = 0; i < slots.Length; i++) { if (SlotMatches(slots[i], entry)) { return i; } } return -1; } private static bool HasInBackpack(Player player, BeltEntry entry) { if ((Object)(object)player == (Object)null || player.backpackSlot == null || ((ItemSlot)player.backpackSlot).IsEmpty() || ((ItemSlot)player.backpackSlot).data == null) { return false; } BackpackData val = default(BackpackData); if (!((ItemSlot)player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val) || val == null || val.itemSlots == null) { return false; } return FindSlot(val.itemSlots, entry) >= 0; } private static bool SlotMatches(ItemSlot slot, BeltEntry entry) { if (slot != null && !slot.IsEmpty() && (Object)(object)slot.prefab != (Object)null) { return SameItem(slot.prefab, entry); } return false; } private static void CopyToHolderSlot(Item item) { if ((Object)(object)item == (Object)null || item.data == null) { return; } Character holder = (((Object)(object)item.holderCharacter != (Object)null) ? item.holderCharacter : Character.localCharacter); ItemSlot val = FindSlotForItem(item, holder); if (val != null) { if (val.data == null) { val.data = item.data; } else { Apply(val.data, ReadFlag(item.data) == 2); } } } private static ItemSlot FindSlotForItem(Item item, Character holder) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || (Object)(object)holder == (Object)null || (Object)(object)holder.player == (Object)null) { return null; } if (item.data != null && item.data.guid != Guid.Empty) { ItemSlot val = FindSlotByGuid(holder, item.data.guid); if (val != null) { return val; } } if ((Object)(object)holder.data != (Object)null && (Object)(object)holder.data.currentItem == (Object)(object)item && holder.refs != null && (Object)(object)holder.refs.items != (Object)null) { Optionable<byte> currentSelectedSlot = holder.refs.items.currentSelectedSlot; if (currentSelectedSlot.IsSome) { return holder.player.GetItemSlot(currentSelectedSlot.Value); } } return null; } private static ItemSlot FindSlotByGuid(Character holder, Guid guid) { if ((Object)(object)holder == (Object)null || (Object)(object)holder.player == (Object)null || guid == Guid.Empty) { return null; } ItemSlot val = FindSlotByGuid(holder.player.itemSlots, guid); if (val != null) { return val; } if (SlotHasGuid(holder.player.tempFullSlot, guid)) { return holder.player.tempFullSlot; } if (holder.player.backpackSlot == null || ((ItemSlot)holder.player.backpackSlot).IsEmpty() || ((ItemSlot)holder.player.backpackSlot).data == null) { return null; } BackpackData val2 = default(BackpackData); if (!((ItemSlot)holder.player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val2) || val2 == null) { return null; } return FindSlotByGuid(val2.itemSlots, guid); } private static ItemSlot FindSlotByGuid(ItemSlot[] slots, Guid guid) { if (slots == null) { return null; } for (int i = 0; i < slots.Length; i++) { if (SlotHasGuid(slots[i], guid)) { return slots[i]; } } return null; } private static bool SlotHasGuid(ItemSlot slot, Guid guid) { if (slot != null && slot.data != null) { return slot.data.guid == guid; } return false; } private static void PushItemInstanceData(Item item) { if ((Object)(object)item == (Object)null || item.data == null) { return; } PhotonView val = ItemView(item); if ((Object)(object)val == (Object)null) { return; } try { if ((!PhotonNetwork.InRoom || val.IsMine || PhotonNetwork.IsMasterClient) && PhotonNetwork.InRoom) { val.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { item.data }); } } catch { } } private static void RememberView(Item item, bool isProtected) { PhotonView val = ItemView(item); if (!((Object)(object)val == (Object)null)) { _flagByView[val.ViewID] = ((!isProtected) ? 1 : 2); } } private static void RestoreRemembered(Item item) { PhotonView val = ItemView(item); if (!((Object)(object)val == (Object)null) && _flagByView.TryGetValue(val.ViewID, out var value)) { Apply(item, value == 2); } } private static PhotonView ItemView(Item item) { if ((Object)(object)item == (Object)null) { return null; } if ((Object)(object)((MonoBehaviourPun)item).photonView != (Object)null) { return ((MonoBehaviourPun)item).photonView; } return item.view; } private static int LocalActor() { try { if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) { return PhotonNetwork.LocalPlayer.ActorNumber; } } catch { } return 0; } private static int ReadFlag(ItemInstanceData data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (data == null) { return 0; } IntItemData val = default(IntItemData); if (data.TryGetDataEntry<IntItemData>(FlagKey, ref val) && val != null) { return val.Value; } return 0; } private static void SetInt(ItemInstanceData data, DataEntryKey key, int value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (data != null) { IntItemData val = default(IntItemData); if (data.TryGetDataEntry<IntItemData>(key, ref val) && val != null) { val.Value = value; return; } IntItemData val2 = new IntItemData(); ((DataEntryValue)val2).Init(); val2.Value = value; data.RegisterEntry<IntItemData>(key, val2); } } private static bool PendingMatches(Item item) { if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(_pendingPrefab) || Time.unscaledTime > _pendingUntil) { return false; } if (!string.Equals(ToolBeltItems.PrefabName(item), _pendingPrefab, StringComparison.OrdinalIgnoreCase) && !string.Equals(((Object)item).name, _pendingPrefab, StringComparison.OrdinalIgnoreCase)) { if (!string.IsNullOrEmpty(((Object)item).name)) { return ((Object)item).name.StartsWith(_pendingPrefab, StringComparison.OrdinalIgnoreCase); } return false; } return true; } private static void ClearPending() { _pendingPrefab = null; _pendingUntil = 0f; } private static void ScheduleDeferredTag(Item item) { if (!((Object)(object)item == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null)) { int instanceID = ((Object)item).GetInstanceID(); if (_tagInFlight.Add(instanceID)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(DeferredTag(item, instanceID)); } } } private static IEnumerator DeferredTag(Item item, int key) { yield return (object)new WaitForSeconds(0.2f); try { if (!((Object)(object)item == (Object)null) && (PendingMatches(item) || ReadFlag(item.data) != 0 || _flagByView.ContainsKey(((Object)(object)ItemView(item) != (Object)null) ? ItemView(item).ViewID : 0))) { bool isProtected = (PendingMatches(item) ? _pendingProtected : (ReadFlag(item.data) == 2 || IsProtectedBeltItem(item))); Apply(item, isProtected); if (PendingMatches(item)) { ClearPending(); } } } finally { _tagInFlight.Remove(key); } } private static void CancelHeldProtected(CharacterItems items, byte slotID) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) Character character = items.character; Item val = (((Object)(object)character.data != (Object)null) ? character.data.currentItem : null); items.UnAttachEquippedItem(); if ((Object)(object)val != (Object)null) { PhotonView val2 = ItemView(val); if ((Object)(object)val2 != (Object)null && (val2.IsMine || (val2.Controller != null && val2.Controller.IsMasterClient && PhotonNetwork.IsMasterClient))) { PhotonNetwork.Destroy(((Component)val).gameObject); } } if ((Object)(object)character.player != (Object)null) { character.player.EmptySlot(Optionable<byte>.Some(slotID), true); } items.pressedDrop = false; items.throwChargeLevel = 0f; if (character.refs != null && (Object)(object)character.refs.afflictions != (Object)null) { character.refs.afflictions.UpdateWeight(); } } } internal static class ToolBeltHud { private sealed class SlotView { public int Index; public InventoryItemUI Ui; public RectTransform Rect; public Vector2 BaseSize; public ItemSlot FakeSlot; public string DisplayName; public Image Fill; public Image Outline; public Image SelectedIcon; public TextMeshProUGUI NameText; } private static RectTransform _root; private static readonly List<SlotView> _slots = new List<SlotView>(); private static int _selected = -1; private static bool _loggedMissingHud; private static bool _loggedLayout; private static Vector2 _cachedSlotSize = new Vector2(72f, 72f); public static bool Show(int selected) { if (!EnsureRoot()) { return false; } ((Component)_root).gameObject.SetActive(true); Rebuild(selected); if ((Object)(object)_root != (Object)null) { return _slots.Count > 0; } return false; } public static void Hide() { if ((Object)(object)_root != (Object)null) { ((Component)_root).gameObject.SetActive(false); } _selected = -1; } public static void Rebuild(int selected) { //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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) if (!EnsureRoot()) { return; } ClearSlots(); InventoryItemUI donor = GetDonor(); if ((Object)(object)donor == (Object)null) { return; } IReadOnlyList<BeltEntry> visible = ToolBeltItems.Visible; int num = Plugin.ColumnCount(); int count = visible.Count; int num2 = ((count > 0) ? Mathf.CeilToInt((float)count / (float)num) : 0); Vector2 val = (_cachedSlotSize = DonorSize(donor)); float num3 = Mathf.Max(6f, val.x * 0.08f); float num4 = (float)num * val.x + (float)Mathf.Max(0, num - 1) * num3; float num5 = (float)num2 * val.y + (float)Mathf.Max(0, num2 - 1) * num3; _root.sizeDelta = new Vector2(num4, num5); for (int i = 0; i < count; i++) { int num6 = i / num; int num7 = i % num; float num8 = (0f - num4) * 0.5f + val.x * 0.5f + (float)num7 * (val.x + num3); float num9 = val.y * 0.5f + (float)(num2 - 1 - num6) * (val.y + num3); SlotView slotView = CreateSlot(donor, i, visible[i], new Vector2(num8, num9), val); if (slotView != null) { _slots.Add(slotView); } } PlaceAboveHotbar(donor, val); RefreshSelection(selected); LogLayout(donor, val, count); } public static void RefreshSelection(int selected) { _selected = selected; for (int i = 0; i < _slots.Count; i++) { ApplySelected(_slots[i], i == selected); } } public static void DestroyHud() { ClearSlots(); if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)((Component)_root).gameObject); _root = null; } } private static bool EnsureRoot() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00db: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root != (Object)null) { return true; } GUIManager instance = GUIManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.hudCanvas == (Object)null) { if (!_loggedMissingHud) { Plugin.Log.LogWarning((object)"Vanilla HUD is not ready yet."); _loggedMissingHud = true; } return false; } if ((Object)(object)GetDonor() == (Object)null) { if (!_loggedMissingHud) { Plugin.Log.LogWarning((object)"Vanilla inventory slots are not ready yet."); _loggedMissingHud = true; } return false; } GameObject val = new GameObject("ToolBeltHud", new Type[1] { typeof(RectTransform) }); _root = val.GetComponent<RectTransform>(); ((Transform)_root).SetParent(((Component)instance.hudCanvas).transform, false); _root.anchorMin = new Vector2(0.5f, 0f); _root.anchorMax = new Vector2(0.5f, 0f); _root.pivot = new Vector2(0.5f, 0f); _root.anchoredPosition = new Vector2(0f, 180f); ((Transform)_root).localScale = Vector3.one; ((Transform)_root).SetAsLastSibling(); val.SetActive(false); _loggedMissingHud = false; return true; } private static SlotView CreateSlot(InventoryItemUI donor, int index, BeltEntry entry, Vector2 anchored, Vector2 size) { //IL_0042: 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_006c: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(((Component)donor).gameObject, (Transform)(object)_root, false); ((Object)val).name = "ToolBeltSlot_" + index; val.SetActive(true); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0f); component.anchorMax = new Vector2(0.5f, 0f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = anchored; component.sizeDelta = size; ((Transform)component).localScale = Vector3.one; InventoryItemUI component2 = val.GetComponent<InventoryItemUI>(); if ((Object)(object)component2 == (Object)null) { Object.Destroy((Object)(object)val); return null; } component2.isBackpack = false; component2.isTemporarySlot = false; component2.rectTransform = component; component2.startingSizeDelta = size; if ((Object)(object)component2.backpackFilledSlotsObject != (Object)null) { component2.backpackFilledSlotsObject.SetActive(false); } if ((Object)(object)component2.fuelBar != (Object)null) { component2.fuelBar.SetActive(false); } StripVanillaLayout(val); StripHotbarChrome(val, component2); EnsureHitTarget(val); (val.GetComponent<ToolBeltSlotPointer>() ?? val.AddComponent<ToolBeltSlotPointer>()).Index = index; SlotView obj = new SlotView { Index = index, Ui = component2, Rect = component, BaseSize = size, FakeSlot = new ItemSlot((byte)0), DisplayName = ((entry != null) ? entry.DisplayName : string.Empty), Fill = component2.fill, Outline = component2.outline, SelectedIcon = component2.selectedSlotIcon, NameText = component2.nameText }; BindItem(obj, entry); ApplySelected(obj, selected: false); return obj; } private static void BindItem(SlotView view, BeltEntry entry) { if (view == null || (Object)(object)view.Ui == (Object)null) { return; } if (entry == null || (Object)(object)entry.Prefab == (Object)null) { view.Ui.Clear(); RestoreIdleChrome(view); return; } view.DisplayName = entry.DisplayName; if ((Object)(object)view.NameText != (Object)null) { ((TMP_Text)view.NameText).text = entry.DisplayName; } view.Ui._itemPrefab = entry.Prefab; view.Ui._itemData = null; try { view.FakeSlot.SetItem(entry.Prefab, (ItemInstanceData)null); } catch { view.FakeSlot.prefab = entry.Prefab; view.FakeSlot.data = null; } view.Ui.SetItem(view.FakeSlot); ForceIcon(view, entry); RestoreIdleChrome(view); } private static void ForceIcon(SlotView view, BeltEntry entry) { //IL_008c: 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) InventoryItemUI ui = view.Ui; if ((Object)(object)ui == (Object)null || entry == null || (Object)(object)entry.Prefab == (Object)null) { return; } Texture val = null; try { if (entry.Prefab.UIData != null) { val = (Texture)(object)entry.Prefab.UIData.GetIcon(); } } catch { } if ((Object)(object)ui.icon != (Object)null) { if ((Object)(object)val != (Object)null) { ui.icon.texture = val; } ((Behaviour)ui.icon).enabled = (Object)(object)ui.icon.texture != (Object)null; ((Graphic)ui.icon).color = Color.white; ((Component)ui.icon).transform.localScale = Vector3.one; ((Graphic)ui.icon).raycastTarget = false; } if ((Object)(object)view.NameText != (Object)null) { ((TMP_Text)view.NameText).text = entry.DisplayName; ((Component)view.NameText).gameObject.SetActive(true); ((Behaviour)view.NameText).enabled = false; ((TMP_Text)view.NameText).overflowMode = (TextOverflowModes)0; ((Graphic)view.NameText).raycastTarget = false; } } private static void RestoreIdleChrome(SlotView view) { if (view != null) { if ((Object)(object)view.Outline != (Object)null) { ((Behaviour)view.Outline).enabled = true; } if ((Object)(object)view.Fill != (Object)null) { ((Behaviour)view.Fill).enabled = false; } if ((Object)(object)view.SelectedIcon != (Object)null) { ((Behaviour)view.SelectedIcon).enabled = false; } } } private static void ApplySelected(SlotView view, bool selected) { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (view == null) { return; } if ((Object)(object)view.Outline != (Object)null) { ((Behaviour)view.Outline).enabled = true; } if ((Object)(object)view.Fill != (Object)null) { ((Behaviour)view.Fill).enabled = selected; } if ((Object)(object)view.SelectedIcon != (Object)null) { ((Behaviour)view.SelectedIcon).enabled = selected; } if ((Object)(object)view.NameText != (Object)null) { if (!string.IsNullOrEmpty(view.DisplayName)) { ((TMP_Text)view.NameText).text = view.DisplayName; } ((Component)view.NameText).gameObject.SetActive(true); ((Behaviour)view.NameText).enabled = selected && !string.IsNullOrEmpty(((TMP_Text)view.NameText).text); ((Graphic)view.NameText).raycastTarget = false; } if ((Object)(object)view.Rect != (Object)null) { view.Rect.sizeDelta = (selected ? (view.BaseSize * 1.2f) : view.BaseSize); if ((Object)(object)view.Ui != (Object)null) { view.Ui.startingSizeDelta = view.BaseSize; } } } private static void PlaceAboveHotbar(InventoryItemUI donor, Vector2 slotSize) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_00af: 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_00be: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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) //IL_00e0: 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) if ((Object)(object)_root == (Object)null) { return; } float num = Mathf.Max(24f, slotSize.y * 0.35f); float num2 = 180f; RectTransform val = (RectTransform)(((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.hudCanvas != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); Rect rect; if ((Object)(object)donor != (Object)null && (Object)(object)donor.rectTransform != (Object)null && (Object)(object)val != (Object)null) { Vector3[] array = (Vector3[])(object)new Vector3[4]; donor.rectTransform.GetWorldCorners(array); Camera val2 = CanvasCamera(val); Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val2, (array[1] + array[2]) * 0.5f); Vector2 val4 = default(Vector2); if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val, val3, val2, ref val4)) { float y = val4.y; rect = val.rect; num2 = y - ((Rect)(ref rect)).yMin + num; } } float num3 = 120f; float num4; if (!((Object)(object)val != (Object)null)) { num4 = 400f; } else { rect = val.rect; num4 = Mathf.Max(num3, ((Rect)(ref rect)).height - 80f); } float num5 = num4; num2 = Mathf.Clamp(num2, num3, num5); ((Transform)_root).localScale = Vector3.one; _root.anchoredPosition = new Vector2(0f, num2); } private static Camera CanvasCamera(RectTransform canvasRt) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) Canvas val = (((Object)(object)canvasRt != (Object)null) ? ((Component)canvasRt).GetComponent<Canvas>() : null); if ((Object)(object)val == (Object)null || (int)val.renderMode == 0) { return null; } if (!((Object)(object)val.worldCamera != (Object)null)) { return Camera.main; } return val.worldCamera; } private static void LogLayout(InventoryItemUI donor, Vector2 size, int count) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!_loggedLayout && !((Object)(object)_root == (Object)null)) { _loggedLayout = true; Plugin.Log.LogInfo((object)("Tool belt HUD: " + count + " slots, size=" + size.x.ToString("0") + "x" + size.y.ToString("0") + ", pos=" + ((object)_root.anchoredPosition/*cast due to .constrained prefix*/).ToString() + ", donor=" + (((Object)(object)donor != (Object)null) ? ((Object)donor).name : "none"))); } } private static InventoryItemUI GetDonor() { GUIManager instance = GUIManager.instance; if ((Object)(object)instance == (Object)null || instance.items == null) { return null; } for (int i = 0; i < instance.items.Length; i++) { if ((Object)(object)instance.items[i] != (Object)null) { return instance.items[i]; } } return instance.temporaryItem; } private static Vector2 DonorSize(InventoryItemUI donor) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0060: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) Vector2 result = (Vector2)((_cachedSlotSize.x >= 24f) ? _cachedSlotSize : new Vector2(72f, 72f)); if ((Object)(object)donor != (Object)null && (Object)(object)donor.rectTransform != (Object)null) { Rect rect = donor.rectTransform.rect; Vector2 size = ((Rect)(ref rect)).size; if (size.x >= 24f && size.x <= 160f && size.y >= 24f && size.y <= 160f) { result = size; } } return result; } private static void StripVanillaLayout(GameObject clone) { LayoutElement component = clone.GetComponent<LayoutElement>(); if ((Object)(object)component != (Object)null) { component.ignoreLayout = true; } } private static void StripHotbarChrome(GameObject clone, InventoryItemUI ui) { if ((Object)(object)clone == (Object)null) { return; } TextMeshProUGUI[] componentsInChildren = clone.GetComponentsInChildren<TextMeshProUGUI>(true); foreach (TextMeshProUGUI val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)ui.nameText)) { ((Behaviour)val).enabled = false; ((Component)val).gameObject.SetActive(false); } } for (int j = 0; j < clone.transform.childCount; j++) { Transform child = clone.transform.GetChild(j); if (!((Object)(object)child == (Object)null)) { string text = ((Object)child).name ?? string.Empty; if (text.IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("bind", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("prompt", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("hotkey", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("shortcut", StringComparison.OrdinalIgnoreCase) >= 0) { ((Component)child).gameObject.SetActive(false); } } } } private static void EnsureHitTarget(GameObject clone) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid