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 KingQOL v0.1.6
plugins\KingQOL.dll
Decompiled a month 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Entities; using Jotunn.Managers; using KingQOL.World; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("KingQOL")] [assembly: AssemblyProduct("KingQOL")] [assembly: ComVisible(false)] [assembly: Guid("0d393b53-beae-4804-84ba-2d485b81b0d5")] [assembly: AssemblyFileVersion("0.1.6")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.6.0")] namespace KingQOL { internal sealed class AutoDepositFeature : IKingFeature { private sealed class AutoDepositBehaviour : MonoBehaviour { private float _nextScan; private void Update() { if (_featureEnabled != null && _featureEnabled.Value && !(Time.time < _nextScan)) { _nextScan = Time.time + 0.5f; ScanNearLocalPlayer(); } } } [HarmonyPatch(typeof(Humanoid), "DropItem")] private static class Humanoid_DropItem_Patch { private static void Prefix(Humanoid __instance) { _recordingPlayerDrop = (Object)(object)__instance != (Object)null && ((Character)__instance).IsPlayer(); } private static void Postfix() { _recordingPlayerDrop = false; } } [HarmonyPatch(typeof(ItemDrop), "DropItem")] private static class ItemDrop_DropItem_Patch { private static void Postfix(ItemDrop __result) { if (_recordingPlayerDrop && (Object)(object)__result != (Object)null) { MarkPlayerDrop(__result); } } } [HarmonyPatch(typeof(ItemDrop), "OnPlayerDrop")] private static class ItemDrop_OnPlayerDrop_Patch { private static void Postfix(ItemDrop __instance) { MarkPlayerDrop(__instance); } } [HarmonyPatch(typeof(Humanoid), "Pickup")] private static class Humanoid_Pickup_Patch { private static void Postfix(Humanoid __instance, bool __result) { if (__result) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)localPlayer)) { _localPickupGraceUntil = Time.time + 2f; } } } } [HarmonyPatch(typeof(ItemDrop), "Awake")] private static class ItemDrop_Awake_Patch { private static void Postfix(ItemDrop __instance) { TryDepositDrop(__instance); } } private const string PlayerDropFlag = "KingQOL_PlayerDrop"; private const string DepositedFlag = "KingQOL_Deposited"; private const float PlayerDropTtlSeconds = 5f; private const float NearPlayerGraceSeconds = 2f; private const float NearPlayerIgnoreDistance = 1f; private const float ScanIntervalSeconds = 0.5f; private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _radius; private static ConfigEntry<bool> _onlyExistingStacks; private static readonly Dictionary<int, float> PlayerDropExpirations = new Dictionary<int, float>(); private static bool _recordingPlayerDrop; private static float _localPickupGraceUntil; public string Name => "AutoDeposit"; public void Init(ConfigFile config, Harmony harmony) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "AutoDeposit", true, "When on (default), ground item drops near you are automatically moved into the master-chest pool. Items you intentionally drop are never scooped up. When off, ground loot stays until you pick it up or another feature handles it. Requires Features.MasterChest and marked master chests. In multiplayer, only one peer deposits each drop (ownership claim), and chest contents sync so everyone sees the deposit."); _radius = config.Bind<float>("AutoDeposit", "Radius", 12f, "How far (in meters, horizontal) around you the mod looks for ground ItemDrops to scoop. Default is 12. Deposits always go into the master-chest pool — this radius does not limit which master chests receive items. Local client setting."); _onlyExistingStacks = config.Bind<bool>("AutoDeposit", "OnlyExistingStacks", true, "When true (default), ground items deposit only into master chests that already contain that item type. When false, any master chest with space can take the drop. Helps keep storage organized. Local preference; matching settings across clients keep base behavior consistent."); harmony.PatchAll(typeof(Humanoid_DropItem_Patch)); harmony.PatchAll(typeof(ItemDrop_DropItem_Patch)); harmony.PatchAll(typeof(ItemDrop_OnPlayerDrop_Patch)); harmony.PatchAll(typeof(Humanoid_Pickup_Patch)); harmony.PatchAll(typeof(ItemDrop_Awake_Patch)); GameObject val = new GameObject("KingQOL_AutoDeposit"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<AutoDepositBehaviour>(); } private static void MarkPlayerDrop(ItemDrop drop) { if ((Object)(object)drop == (Object)null) { return; } PlayerDropExpirations[((Object)drop).GetInstanceID()] = Time.time + 5f; ZNetView view = NetAccess.GetView((Component)(object)drop); if (NetAccess.IsReady(view)) { ZDO zDO = view.GetZDO(); if (zDO != null && (view.IsOwner() || NetAccess.TryClaim(view))) { zDO.Set("KingQOL_PlayerDrop", true); } } } private static bool IsPlayerDrop(ItemDrop drop) { if ((Object)(object)drop == (Object)null) { return false; } PruneExpiredPlayerDrops(); if (PlayerDropExpirations.ContainsKey(((Object)drop).GetInstanceID())) { return true; } ZNetView view = NetAccess.GetView((Component)(object)drop); if (!NetAccess.IsReady(view)) { return false; } ZDO zDO = view.GetZDO(); if (zDO != null) { return zDO.GetBool("KingQOL_PlayerDrop", false); } return false; } private static void PruneExpiredPlayerDrops() { if (PlayerDropExpirations.Count == 0) { return; } float time = Time.time; List<int> list = new List<int>(); foreach (KeyValuePair<int, float> playerDropExpiration in PlayerDropExpirations) { if (playerDropExpiration.Value <= time) { list.Add(playerDropExpiration.Key); } } foreach (int item in list) { PlayerDropExpirations.Remove(item); } } private static bool IsNearLocalPlayerGrace(ItemDrop drop) { //IL_002e: 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) if ((Object)(object)drop == (Object)null || Time.time >= _localPickupGraceUntil) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } return Vector3.Distance(((Component)localPlayer).transform.position, ((Component)drop).transform.position) <= 1f; } private static void TryDepositDrop(ItemDrop drop) { if (_featureEnabled == null || !_featureEnabled.Value || (Object)(object)drop == (Object)null || drop.m_itemData?.m_shared == null || IsPlayerDrop(drop) || IsNearLocalPlayerGrace(drop)) { return; } ZNetView view = NetAccess.GetView((Component)(object)drop); if (!NetAccess.IsReady(view)) { return; } ZDO zDO = view.GetZDO(); if (zDO == null || zDO.GetBool("KingQOL_Deposited", false) || (!view.IsOwner() && !NetAccess.TryClaim(view)) || zDO.GetBool("KingQOL_Deposited", false) || zDO.GetBool("KingQOL_PlayerDrop", false)) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ItemData itemData = drop.m_itemData; int stack = itemData.m_stack; if (stack > 0 && MasterChests.TryDeposit(itemData, stack, _onlyExistingStacks.Value)) { zDO.Set("KingQOL_Deposited", true); if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)drop).gameObject); } else if ((Object)(object)((Component)drop).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)drop).gameObject); } } } private static void ScanNearLocalPlayer() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (_featureEnabled == null || !_featureEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } foreach (ItemDrop groundItem in AreaScan.GetGroundItems(((Component)localPlayer).transform.position, _radius.Value)) { TryDepositDrop(groundItem); } } } internal sealed class AutoStackFeature : IKingFeature { private sealed class AutoStackBehaviour : MonoBehaviour { private void Update() { //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 (_featureEnabled != null && _featureEnabled.Value) { KeyboardShortcut value = _hotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { TryDeposit(); } } } } private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _radius; private static ConfigEntry<bool> _onlyExistingStacks; private static ConfigEntry<KeyboardShortcut> _hotkey; public string Name => "AutoStack"; public void Init(ConfigFile config, Harmony harmony) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "AutoStack", true, "When on (default), a hotkey moves matching stacks from your inventory into the shared master-chest pool. When off, the hotkey does nothing. You must have marked master chests (Features.MasterChest). Other players see items leave your inventory and appear in those chests once the network syncs. Each player triggers deposit only for themselves."); _radius = config.Bind<float>("AutoStack", "Radius", 15f, "Legacy unused setting kept for cfg compatibility. AutoStack no longer uses a nearby-chest radius; deposits always go into loaded master chests. Changing this value has no gameplay effect. Default is 15."); _onlyExistingStacks = config.Bind<bool>("AutoStack", "OnlyExistingStacks", true, "When true (default), items deposit only into master chests that already hold that item type, so new item types are not dumped into empty slots. When false, any master chest with free space can receive the stack. Local preference; other clients do not need the same value for the deposit itself, but similar settings keep base behavior consistent."); _hotkey = config.Bind<KeyboardShortcut>("AutoStack", "Hotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Keyboard shortcut to deposit matching inventory stacks into master chests. Default is F8. Rebind here or in Configuration Manager. Affects only the local player's inventory. Ignored while typing in chat, console, or text input."); GameObject val = new GameObject("KingQOL_AutoStack"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<AutoStackBehaviour>(); } private static bool IsTypingInTextField() { if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } return false; } private static void TryDeposit() { if (_featureEnabled != null && _featureEnabled.Value) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !IsTypingInTextField()) { _ = _radius; IList<Container> all = MasterChests.GetAll(); int num = CountPlayerStacks(localPlayer); int num2 = InventoryOps.DepositMatching(localPlayer, all, _onlyExistingStacks.Value); int num3 = Mathf.Max(0, num - CountPlayerStacks(localPlayer)); Logger.LogInfo((object)$"AutoStack: moved {num3} stack(s) ({num2} item(s)) into master chests."); } } } private static int CountPlayerStacks(Player player) { Inventory val = ((player != null) ? ((Humanoid)player).GetInventory() : null); if (val == null) { return 0; } int num = 0; foreach (ItemData allItem in val.GetAllItems()) { if (allItem != null && allItem.m_stack > 0) { num++; } } return num; } } internal sealed class ChestHoverFeature : IKingFeature { [HarmonyPatch(typeof(Container), "GetHoverText")] private static class Container_GetHoverText_Patch { private static void Postfix(Container __instance, ref string __result) { if (_featureEnabled == null || !_featureEnabled.Value || (Object)(object)__instance == (Object)null || IsTombstone(__instance)) { return; } int num = ((_maxLines != null) ? Math.Max(0, _maxLines.Value) : 8); if (num <= 0) { return; } float unscaledTime = Time.unscaledTime; if ((Object)(object)__instance == (Object)(object)_cachedContainer && num == _cachedMaxLines && unscaledTime < _cacheUntilUnscaled) { AppendCached(ref __result); return; } __instance.Load(); Inventory inventory = __instance.GetInventory(); int num2 = ((inventory != null) ? inventory.NrOfItems() : 0); if ((Object)(object)__instance == (Object)(object)_cachedContainer && num == _cachedMaxLines && num2 == _cachedItemCount) { _cacheUntilUnscaled = unscaledTime + 0.35f; AppendCached(ref __result); return; } _cachedContainer = __instance; _cachedMaxLines = num; _cachedItemCount = num2; _cachedIsMaster = MasterChests.IsMaster(__instance); _cachedListSuffix = ((inventory == null || num2 == 0) ? string.Empty : BuildListSuffix(inventory, num)); _cacheUntilUnscaled = unscaledTime + 0.35f; AppendCached(ref __result); } } private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<int> _maxLines; private static Container _cachedContainer; private static string _cachedListSuffix = string.Empty; private static bool _cachedIsMaster; private static int _cachedItemCount = -1; private static int _cachedMaxLines = -1; private static float _cacheUntilUnscaled; public string Name => "ChestHover"; public void Init(ConfigFile config, Harmony harmony) { _featureEnabled = config.Bind<bool>("Features", "ChestHover", true, "When on (default), looking at a chest appends a short read-only list of its contents to the hover text so you can glance without opening it. Empty chests and tombstones are skipped. When off, hover text stays vanilla (plus any master-chest status from Features.MasterChest). This is display-only on your client — it does not claim ownership or change chest contents. Other players do not need the same setting."); _maxLines = config.Bind<int>("ChestHover", "MaxLines", 8, "Maximum number of item lines added under the chest hover text. Default is 8. If the chest holds more types than this, remaining items are omitted from the preview. Local UI preference only."); harmony.PatchAll(typeof(Container_GetHoverText_Patch)); } private static bool IsTombstone(Container container) { if ((Object)(object)container == (Object)null) { return true; } if ((Object)(object)((Component)container).GetComponent<TombStone>() != (Object)null) { return true; } if (!string.IsNullOrEmpty(container.m_name) && container.m_name.IndexOf("tombstone", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if ((Object)(object)container.m_piece != (Object)null && !string.IsNullOrEmpty(container.m_piece.m_name) && container.m_piece.m_name.IndexOf("tombstone", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } private static string LocalizeName(string sharedName) { if (string.IsNullOrEmpty(sharedName)) { return string.Empty; } if (Localization.instance == null) { return sharedName; } return Localization.instance.Localize(sharedName); } private static string BuildListSuffix(Inventory inventory, int maxLines) { Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); List<string> list = new List<string>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared == null || allItem.m_stack <= 0) { continue; } string name = allItem.m_shared.m_name; if (!string.IsNullOrEmpty(name)) { if (!dictionary.ContainsKey(name)) { list.Add(name); dictionary[name] = 0; } dictionary[name] += allItem.m_stack; } } if (list.Count == 0) { return string.Empty; } list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(); int num = 0; for (int i = 0; i < list.Count; i++) { if (num >= maxLines) { stringBuilder.Append("\n..."); break; } string text = list[i]; stringBuilder.Append('\n'); stringBuilder.Append(LocalizeName(text)); stringBuilder.Append(" x"); stringBuilder.Append(dictionary[text]); num++; } return stringBuilder.ToString(); } private static void AppendCached(ref string result) { if (_cachedIsMaster && (result ?? string.Empty).IndexOf("Master chest", StringComparison.Ordinal) < 0) { result = (result ?? string.Empty) + "\n<color=orange>Master chest</color>"; } if (!string.IsNullOrEmpty(_cachedListSuffix)) { result = (result ?? string.Empty) + _cachedListSuffix; } } } internal sealed class ChestSearchFeature : IKingFeature { private sealed class AggregatedItem { public string SharedName; public string DisplayName; public int TotalCount; public int MaxStackSize; public int WorldLevel; public Container SourceChest; public ItemData SourceItem; } private sealed class ChestSearchBehaviour : MonoBehaviour { private bool _open; private bool _inputBlocked; private string _filter = string.Empty; private Vector2 _scroll; private readonly List<AggregatedItem> _items = new List<AggregatedItem>(); private readonly Dictionary<string, string> _qtyBySharedName = new Dictionary<string, string>(StringComparer.Ordinal); private Rect _windowRect = new Rect(80f, 80f, 420f, 480f); private CursorLockMode _prevLockState; private bool _prevCursorVisible; private bool _prevMouseCapture; private bool _savedMouseCapture; private void Update() { //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) if (_featureEnabled == null || !_featureEnabled.Value) { if (_open) { CloseWindow(); } return; } KeyboardShortcut value = _hotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !IsTypingInTextField()) { Toggle(); } if (_open && Input.GetKeyDown((KeyCode)27)) { CloseWindow(); } if (_open) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; if ((Object)(object)GameCamera.instance != (Object)null) { GameCamera.instance.m_mouseCapture = false; } } } private void OnDestroy() { if (_open || _inputBlocked) { RestoreInput(); } } private void Toggle() { if (_open) { CloseWindow(); } else { OpenWindow(); } } private void OpenWindow() { _open = true; LayoutCenteredWindow(); CaptureInput(); Refresh(); } private void CloseWindow() { _open = false; RestoreInput(); } private void LayoutCenteredWindow() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) float num = (float)Screen.width * 0.7f; float num2 = (float)Screen.height * 0.7f; _windowRect = new Rect(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2); } private void CaptureInput() { //IL_000a: 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) if (!_inputBlocked) { _prevLockState = Cursor.lockState; _prevCursorVisible = Cursor.visible; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; if ((Object)(object)GameCamera.instance != (Object)null) { _prevMouseCapture = GameCamera.instance.m_mouseCapture; _savedMouseCapture = true; GameCamera.instance.m_mouseCapture = false; } else { _savedMouseCapture = false; } GUIManager.BlockInput(true); _inputBlocked = true; } } private void RestoreInput() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (_inputBlocked) { GUIManager.BlockInput(false); if (_savedMouseCapture && (Object)(object)GameCamera.instance != (Object)null) { GameCamera.instance.m_mouseCapture = _prevMouseCapture; } _savedMouseCapture = false; Cursor.lockState = _prevLockState; Cursor.visible = _prevCursorVisible; _inputBlocked = false; } } private void Refresh() { _items.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Dictionary<string, AggregatedItem> dictionary = new Dictionary<string, AggregatedItem>(StringComparer.Ordinal); foreach (Container searchChest in GetSearchChests(localPlayer)) { if ((Object)(object)searchChest == (Object)null) { continue; } Inventory inventory = searchChest.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null && !string.IsNullOrEmpty(allItem.m_shared.m_name)) { string name = allItem.m_shared.m_name; if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = new AggregatedItem { SharedName = name, DisplayName = ((Localization.instance != null) ? Localization.instance.Localize(name) : name), TotalCount = 0, MaxStackSize = Mathf.Max(1, allItem.m_shared.m_maxStackSize), WorldLevel = allItem.m_worldLevel, SourceChest = searchChest, SourceItem = allItem }); _items.Add(value); } value.TotalCount += allItem.m_stack; value.MaxStackSize = Mathf.Max(1, allItem.m_shared.m_maxStackSize); value.WorldLevel = allItem.m_worldLevel; value.SourceChest = searchChest; value.SourceItem = allItem; } } } _items.Sort((AggregatedItem a, AggregatedItem b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase)); foreach (AggregatedItem item in _items) { if (!_qtyBySharedName.ContainsKey(item.SharedName)) { int num = Mathf.Clamp(item.MaxStackSize, 1, Mathf.Max(1, item.TotalCount)); _qtyBySharedName[item.SharedName] = num.ToString(); } } } private void OnGUI() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (_open && _featureEnabled != null && _featureEnabled.Value) { if (((Rect)(ref _windowRect)).width < (float)Screen.width * 0.5f || ((Rect)(ref _windowRect)).height < (float)Screen.height * 0.5f) { LayoutCenteredWindow(); } _windowRect = GUILayout.Window(((Object)this).GetInstanceID(), _windowRect, new WindowFunction(DrawWindow), "King QOL — Chest Search", Array.Empty<GUILayoutOption>()); } } private void DrawWindow(int id) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Filter", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); _filter = GUILayout.TextField(_filter ?? string.Empty, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { Refresh(); } if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { CloseWindow(); } GUILayout.EndHorizontal(); string text = (MasterChests.Enabled ? "Source: master chests" : $"Source: chests within {_radius.Value:0}m"); GUILayout.Label(text, Array.Empty<GUILayoutOption>()); _scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) }); string value = _filter?.Trim() ?? string.Empty; foreach (AggregatedItem item in _items) { if (item != null && (string.IsNullOrEmpty(value) || item.DisplayName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 || item.SharedName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label($"{item.DisplayName} x{item.TotalCount}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.Label("Qty", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }); if (!_qtyBySharedName.TryGetValue(item.SharedName, out var value2)) { value2 = Mathf.Clamp(item.MaxStackSize, 1, Mathf.Max(1, item.TotalCount)).ToString(); _qtyBySharedName[item.SharedName] = value2; } string text2 = GUILayout.TextField(value2 ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); _qtyBySharedName[item.SharedName] = text2; if (GUILayout.Button("Pull", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { PullQuantity(item, ParseQuantity(text2, item)); } GUILayout.EndHorizontal(); } } GUILayout.EndScrollView(); GUILayout.Label("Set Qty then Pull. Never takes more than chests hold or you can carry. Esc / hotkey closes.", Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); GUI.DragWindow(); } private static int ParseQuantity(string text, AggregatedItem entry) { if (entry == null) { return 1; } if (!int.TryParse(text?.Trim(), out var result) || result <= 0) { return Mathf.Clamp(entry.MaxStackSize, 1, Mathf.Max(1, entry.TotalCount)); } return result; } private void PullQuantity(AggregatedItem entry, int requested) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || entry == null || requested <= 0) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return; } List<Container> chests = new List<Container>(GetSearchChests(localPlayer)); int num = InventoryOps.CountItem(chests, entry.SharedName); if (num <= 0) { Refresh(); return; } int num2 = inventory.FindFreeStackSpace(entry.SharedName, (float)entry.WorldLevel); int num3 = inventory.GetEmptySlots() * Mathf.Max(1, entry.MaxStackSize); int num4 = num2 + num3; if (num4 <= 0) { Logger.LogInfo((object)("ChestSearch: inventory full, cannot pull " + entry.DisplayName + ".")); return; } int num5 = Mathf.Min(new int[3] { requested, num, num4 }); int num6 = num5; int num7 = 0; Container chest; ItemData item; while (num6 > 0 && TryFindStack(entry.SharedName, out chest, out item)) { int num8 = InventoryOps.MoveToPlayer(chest, item, localPlayer, num6); if (num8 <= 0) { break; } num7 += num8; num6 -= num8; } if (num7 <= 0) { Logger.LogInfo((object)("ChestSearch: could not pull " + entry.DisplayName + " (ownership or inventory full).")); } Refresh(); } private static bool TryFindStack(string sharedName, out Container chest, out ItemData item) { chest = null; item = null; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || string.IsNullOrEmpty(sharedName)) { return false; } foreach (Container searchChest in GetSearchChests(localPlayer)) { if ((Object)(object)searchChest == (Object)null) { continue; } Inventory inventory = searchChest.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null && allItem.m_stack > 0 && !(allItem.m_shared.m_name != sharedName)) { chest = searchChest; item = allItem; return true; } } } return false; } } private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _radius; private static ConfigEntry<KeyboardShortcut> _hotkey; public string Name => "ChestSearch"; public void Init(ConfigFile config, Harmony harmony) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "ChestSearch", true, "Enable chest search UI and pull-from-chest hotkey."); _radius = config.Bind<float>("ChestSearch", "Radius", 30f, "Horizontal radius around the local player to search chests (used when master chests are disabled)."); _hotkey = config.Bind<KeyboardShortcut>("ChestSearch", "Hotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Hotkey to open/close the chest search window (local UI)."); GameObject val = new GameObject("KingQOL_ChestSearch"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<ChestSearchBehaviour>(); } private static bool IsTypingInTextField() { if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } return false; } private static IEnumerable<Container> GetSearchChests(Player player) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (MasterChests.Enabled) { return MasterChests.GetAll(); } if ((Object)(object)player == (Object)null) { return Array.Empty<Container>(); } return AreaScan.GetChests(((Component)player).transform.position, _radius.Value); } } internal sealed class MasterChestFeature : IKingFeature { private sealed class MasterChestBehaviour : MonoBehaviour { private void Update() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (MasterChests.Enabled && Hotkey != null) { KeyboardShortcut value = Hotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { TryToggleHovered(); } } } } [HarmonyPatch(typeof(Container), "GetHoverText")] private static class Container_GetHoverText_Patch { private static void Postfix(Container __instance, ref string __result) { if (MasterChests.Enabled && !((Object)(object)__instance == (Object)null) && MasterChests.IsMaster(__instance)) { __result = (__result ?? string.Empty) + "\n<color=orange>Master chest</color>"; } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] private static class Smelter_OnAddOre_Patch { private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ref bool __result) { if (!MasterChests.Enabled || (Object)(object)__instance == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return true; } if (item != null) { return true; } if (PlayerHasSmelterOre(__instance, user.GetInventory())) { return true; } __result = TryFillSmelterOreFromMaster(__instance, user); return false; } } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] private static class Smelter_OnAddFuel_Patch { private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ref bool __result) { if (!MasterChests.Enabled || (Object)(object)__instance == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return true; } if (__instance.m_fuelItem?.m_itemData?.m_shared == null) { return true; } string name = __instance.m_fuelItem.m_itemData.m_shared.m_name; if (item != null && item.m_shared != null && item.m_shared.m_name != name) { return true; } Inventory inventory = user.GetInventory(); if (inventory != null && inventory.HaveItem(name, true)) { return true; } __result = TryFillSmelterFuelFromMaster(__instance, user); return false; } } [HarmonyPatch(typeof(Fireplace), "Interact")] private static class Fireplace_Interact_Patch { private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref bool __result) { if (!MasterChests.Enabled || (Object)(object)__instance == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return true; } if (!__instance.m_canRefill || __instance.m_infiniteFuel) { return true; } if (__instance.m_canTurnOff && !hold && !alt) { ZNetView nview = __instance.m_nview; if (NetAccess.IsReady(nview) && nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f) > 0f) { return true; } } if (__instance.m_fuelItem?.m_itemData?.m_shared == null) { return true; } string name = __instance.m_fuelItem.m_itemData.m_shared.m_name; Inventory inventory = user.GetInventory(); if (inventory != null && inventory.HaveItem(name, true)) { return true; } if (TryFillFireplaceFromMaster(__instance, user)) { __result = true; return false; } return true; } } public const string ConfigSection = "MasterChest"; private static ConfigEntry<KeyboardShortcut> Hotkey; public string Name => "MasterChest"; public void Init(ConfigFile config, Harmony harmony) { //IL_0021: 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_0080: Expected O, but got Unknown MasterChests.Bind(config); Hotkey = config.Bind<KeyboardShortcut>("MasterChest", "Hotkey", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Keyboard shortcut to mark or unmark the chest you are looking at as a master chest. Default is LeftAlt+E (hold Left Alt and press E). Rebind here or in Configuration Manager. The master flag is written to the chest ZDO and syncs to all clients — every player sees the same master set. Hover text shows master status when this feature is on. All loaded master chests share one pool (no radius) used by craft, build, repair, deposit, stack, and machine fill."); harmony.PatchAll(typeof(Container_GetHoverText_Patch)); harmony.PatchAll(typeof(Smelter_OnAddOre_Patch)); harmony.PatchAll(typeof(Smelter_OnAddFuel_Patch)); harmony.PatchAll(typeof(Fireplace_Interact_Patch)); GameObject val = new GameObject("KingQOL_MasterChest"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<MasterChestBehaviour>(); } private static bool IsTypingInTextField() { if (Console.IsVisible() || TextInput.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.HasFocus(); } return false; } private static void TryToggleHovered() { if (!MasterChests.Enabled || Hotkey == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || IsTypingInTextField()) { return; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Container componentInParent = hoverObject.GetComponentInParent<Container>(); if (!((Object)(object)componentInParent == (Object)null)) { bool flag = !MasterChests.IsMaster(componentInParent); if (!MasterChests.TrySetMaster(componentInParent, flag)) { ((Character)localPlayer).Message((MessageType)2, "Could not claim chest", 0, (Sprite)null, false); } else { ((Character)localPlayer).Message((MessageType)2, flag ? "Master chest on" : "Master chest off", 0, (Sprite)null, false); } } } private static bool TryFillSmelterOreFromMaster(Smelter smelter, Humanoid user) { ZNetView nview = smelter.m_nview; if (!NetAccess.IsReady(nview) || !NetAccess.TryClaim(nview)) { return false; } if (smelter.m_conversion == null) { return false; } int num = 0; while (smelter.GetQueueSize() < smelter.m_maxOre) { bool flag = false; foreach (ItemConversion item in smelter.m_conversion) { if ((Object)(object)item?.m_from == (Object)null) { continue; } string name = ((Object)item.m_from).name; if (smelter.IsItemAllowed(name)) { string name2 = item.m_from.m_itemData.m_shared.m_name; if (MasterChests.TryConsume(name2, 1)) { nview.InvokeRPC("RPC_AddOre", new object[1] { name }); num++; flag = true; break; } } } if (!flag) { break; } } if (num > 0) { ((Character)user).Message((MessageType)2, "Added from master chest", 0, (Sprite)null, false); } return num > 0; } private static bool TryFillSmelterFuelFromMaster(Smelter smelter, Humanoid user) { if (smelter.m_fuelItem?.m_itemData?.m_shared == null) { return false; } ZNetView nview = smelter.m_nview; if (!NetAccess.IsReady(nview) || !NetAccess.TryClaim(nview)) { return false; } string name = smelter.m_fuelItem.m_itemData.m_shared.m_name; int num = 0; while (smelter.GetFuel() < (float)smelter.m_maxFuel - 0.1f && MasterChests.TryConsume(name, 1)) { nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); num++; } if (num > 0) { ((Character)user).Message((MessageType)2, "$msg_added " + name, 0, (Sprite)null, false); } return num > 0; } private static bool TryFillFireplaceFromMaster(Fireplace fireplace, Humanoid user) { if (fireplace.m_fuelItem?.m_itemData?.m_shared == null) { return false; } ZNetView nview = fireplace.m_nview; if (!NetAccess.IsReady(nview) || !NetAccess.TryClaim(nview)) { return false; } string name = fireplace.m_fuelItem.m_itemData.m_shared.m_name; int num = 0; while (true) { float num2 = nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f); if ((float)Mathf.CeilToInt(num2) >= fireplace.m_maxFuel || !MasterChests.TryConsume(name, 1)) { break; } nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); num++; } if (num > 0) { ((Character)user).Message((MessageType)2, "$msg_fireadding", 0, (Sprite)null, false); } return num > 0; } private static bool PlayerHasSmelterOre(Smelter smelter, Inventory inventory) { if (smelter.m_conversion == null || inventory == null) { return false; } foreach (ItemConversion item in smelter.m_conversion) { if (item?.m_from?.m_itemData?.m_shared != null && inventory.HaveItem(item.m_from.m_itemData.m_shared.m_name, true)) { return true; } } return false; } } internal sealed class InstantLootFeature : IKingFeature { private enum NotificationAnchor { BottomRight, BottomLeft, TopRight, TopLeft } private sealed class InstantLootHost : MonoBehaviour { } [HarmonyPatch(typeof(Ragdoll), "Awake")] private static class Ragdoll_Awake_Patch { private static void Postfix(Ragdoll __instance, ZNetView ___m_nview, EffectList ___m_removeEffect) { if (IsEnabled && !((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)_host == (Object)null)) { ((MonoBehaviour)_host).StartCoroutine(DropNow(__instance, ___m_nview, ___m_removeEffect)); } } } [HarmonyPatch(typeof(Ragdoll), "DestroyNow")] private static class Ragdoll_DestroyNow_Patch { private static bool Prefix() { return !IsEnabled; } } [HarmonyPatch(typeof(ItemDrop), "Awake")] private static class ItemDrop_Awake_Patch { private static void Postfix(ItemDrop __instance) { if (IsEnabled && _spawningLoot && !(_autoPickupDelay.Value <= 0f) && __instance.m_autoPickup) { __instance.m_autoPickup = false; if ((Object)(object)_host != (Object)null) { ((MonoBehaviour)_host).StartCoroutine(EnableAutoPickupLater(__instance, _autoPickupDelay.Value)); } } } } [HarmonyPatch(typeof(Player), "AutoPickup")] private static class Player_AutoPickup_Patch { private const float MinIntervalSeconds = 0.25f; private static float _nextAllowedUnscaled; private static bool Prefix(Player __instance) { if (!IsEnabled || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextAllowedUnscaled) { return false; } _nextAllowedUnscaled = unscaledTime + 0.25f; __instance.m_autoPickupRange = _autoPickupRange.Value; return true; } } [HarmonyPatch(typeof(Character), "ShowPickupMessage")] private static class Character_ShowPickupMessage_Patch { private static bool Prefix(Character __instance, ItemData item, int amount) { if (!IsEnabled || !_notificationEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if ((Object)(object)PickupFeed.Instance != (Object)null) { PickupFeed.Instance.Add(item, amount); } return false; } } private sealed class PickupFeed : MonoBehaviour { private sealed class Line { public string Name; public int Amount; public Texture Icon; public Rect Uv; public float Age; public float Punch; public float Slide; } private const float FadeOutSeconds = 0.8f; private readonly List<Line> _lines = new List<Line>(); private Texture2D _pixel; private GUIStyle _nameStyle; private GUIStyle _amountStyle; private float _panelAlpha; private int _cachedFontSize = -1; public static PickupFeed Instance { get; private set; } private static float LineHeight => (float)Mathf.Max(8, _notificationFontSize.Value) + 9f; private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) Instance = this; _pixel = new Texture2D(1, 1, (TextureFormat)4, false); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); ((Object)_pixel).hideFlags = (HideFlags)61; } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } if ((Object)(object)_pixel != (Object)null) { Object.Destroy((Object)(object)_pixel); } } public void Add(ItemData item, int amount) { //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_022f: 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_00e0: Unknown result type (might be due to invalid IL or missing references) if (!_notificationEnabled.Value || item?.m_shared == null || amount <= 0) { return; } string text = item.m_shared.m_name; if (Localization.instance != null) { text = Localization.instance.Localize(text); } if (string.IsNullOrEmpty(text)) { text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "Item"); } Texture icon = null; Rect uv = default(Rect); ((Rect)(ref uv))..ctor(0f, 0f, 1f, 1f); Sprite[] icons = item.m_shared.m_icons; if (icons != null && icons.Length != 0) { Sprite val = icons[Mathf.Clamp(item.m_variant, 0, icons.Length - 1)]; if ((Object)(object)val != (Object)null && (Object)(object)val.texture != (Object)null) { icon = (Texture)(object)val.texture; Rect textureRect = val.textureRect; int width = ((Texture)val.texture).width; int height = ((Texture)val.texture).height; if ((float)width > 0f && (float)height > 0f && ((Rect)(ref textureRect)).width > 0f && ((Rect)(ref textureRect)).height > 0f) { ((Rect)(ref uv))..ctor(((Rect)(ref textureRect)).x / (float)width, ((Rect)(ref textureRect)).y / (float)height, ((Rect)(ref textureRect)).width / (float)width, ((Rect)(ref textureRect)).height / (float)height); } } } for (int i = 0; i < _lines.Count; i++) { if (!(_lines[i].Name != text)) { _lines[i].Amount += amount; _lines[i].Age = 0f; _lines[i].Punch = 1f; Line item2 = _lines[i]; _lines.RemoveAt(i); _lines.Add(item2); return; } } _lines.Add(new Line { Name = text, Amount = amount, Icon = icon, Uv = uv, Age = 0f, Punch = 1f, Slide = 0f }); int num = Mathf.Max(1, Mathf.FloorToInt(((float)Mathf.Max(40, _notificationHeight.Value) - 16f) / LineHeight)); while (_lines.Count > num) { _lines.RemoveAt(0); } } private void Update() { if (!_notificationEnabled.Value) { _lines.Clear(); _panelAlpha = 0f; return; } float unscaledDeltaTime = Time.unscaledDeltaTime; float num = Mathf.Max(0.5f, _notificationLinger.Value); for (int num2 = _lines.Count - 1; num2 >= 0; num2--) { Line line = _lines[num2]; line.Age += unscaledDeltaTime; line.Punch = Mathf.MoveTowards(line.Punch, 0f, unscaledDeltaTime * 4f); line.Slide = Mathf.MoveTowards(line.Slide, 1f, unscaledDeltaTime * 8f); if (line.Age >= num) { _lines.RemoveAt(num2); } } _panelAlpha = Mathf.MoveTowards(_panelAlpha, (_lines.Count > 0) ? 1f : 0f, unscaledDeltaTime * 5f); } private void OnGUI() { //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_00d6: 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_010e: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_02af: 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_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled || !_notificationEnabled.Value || _panelAlpha <= 0.01f || (Object)(object)Player.m_localPlayer == (Object)null || ((Object)(object)Hud.instance != (Object)null && Hud.IsUserHidden())) { return; } EnsureStyles(); int num = Mathf.Max(80, _notificationWidth.Value); int num2 = Mathf.Max(40, _notificationHeight.Value); GetWindowRect(num, num2, out var x, out var y); Rect val = default(Rect); ((Rect)(ref val))..ctor(x, y, (float)num, (float)num2); float num3 = Mathf.Clamp01(_notificationOpacity.Value) * _panelAlpha; bool flag = _notificationAnchor.Value == NotificationAnchor.BottomRight || _notificationAnchor.Value == NotificationAnchor.TopRight; Color color = GUI.color; GUI.color = new Color(0.04f, 0.05f, 0.06f, num3); GUI.DrawTexture(val, (Texture)(object)_pixel); GUI.color = new Color(0.82f, 0.68f, 0.32f, Mathf.Min(1f, num3 + 0.12f)); float num4 = (flag ? (((Rect)(ref val)).xMax - 3f) : ((Rect)(ref val)).x); GUI.DrawTexture(new Rect(num4, ((Rect)(ref val)).y, 3f, ((Rect)(ref val)).height), (Texture)(object)_pixel); GUI.color = new Color(1f, 1f, 1f, 0.1f * _panelAlpha); GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width, 1f), (Texture)(object)_pixel); float lineHeight = LineHeight; float num5 = Mathf.Max(0.5f, _notificationLinger.Value); GUI.BeginGroup(val); float num6 = ((Rect)(ref val)).height - 8f; Rect val2 = default(Rect); Rect val3 = default(Rect); Rect val4 = default(Rect); Rect val5 = default(Rect); for (int num7 = _lines.Count - 1; num7 >= 0; num7--) { Line line = _lines[num7]; num6 -= lineHeight; if (num6 < 6f) { break; } float num8 = 1f; if (line.Age > num5 - 0.8f) { num8 = Mathf.Clamp01((num5 - line.Age) / 0.8f); } num8 *= _panelAlpha; float num9 = (1f - line.Slide) * 36f; if (!flag) { num9 = 0f - num9; } float num10 = 1f + line.Punch * 0.08f; ((Rect)(ref val2))..ctor(10f + num9, num6, ((Rect)(ref val)).width - 18f, lineHeight); GUI.color = new Color(1f, 1f, 1f, num8); if ((Object)(object)line.Icon != (Object)null) { float num11 = (lineHeight - 6f) * num10; ((Rect)(ref val3))..ctor(((Rect)(ref val2)).x, ((Rect)(ref val2)).y + (lineHeight - num11) * 0.5f, num11, num11); GUI.DrawTextureWithTexCoords(val3, line.Icon, line.Uv); } float num12 = (((Object)(object)line.Icon != (Object)null) ? lineHeight : 4f); ((Rect)(ref val4))..ctor(((Rect)(ref val2)).x + num12, ((Rect)(ref val2)).y, ((Rect)(ref val2)).width - num12 - 52f, lineHeight); ((Rect)(ref val5))..ctor(((Rect)(ref val2)).x + ((Rect)(ref val2)).width - 52f, ((Rect)(ref val2)).y, 48f, lineHeight); _nameStyle.normal.textColor = new Color(0.95f, 0.92f, 0.82f, num8); _amountStyle.normal.textColor = new Color(0.92f, 0.78f, 0.38f, num8); GUI.Label(val4, line.Name, _nameStyle); GUI.Label(val5, "x" + line.Amount, _amountStyle); } GUI.EndGroup(); GUI.color = color; } private static void GetWindowRect(float width, float height, out float x, out float y) { int value = _notificationX.Value; int value2 = _notificationY.Value; switch (_notificationAnchor.Value) { case NotificationAnchor.BottomLeft: x = value; y = (float)Screen.height - height - (float)value2; break; case NotificationAnchor.TopRight: x = (float)Screen.width - width - (float)value; y = value2; break; case NotificationAnchor.TopLeft: x = value; y = value2; break; default: x = (float)Screen.width - width - (float)value; y = (float)Screen.height - height - (float)value2; break; } x = Mathf.Clamp(x, 0f, Mathf.Max(0f, (float)Screen.width - width)); y = Mathf.Clamp(y, 0f, Mathf.Max(0f, (float)Screen.height - height)); } private void EnsureStyles() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_006f: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown int num = Mathf.Clamp(_notificationFontSize.Value, 8, 48); if (_nameStyle == null || _cachedFontSize != num) { _cachedFontSize = num; _nameStyle = new GUIStyle(GUI.skin.label) { fontSize = num, fontStyle = (FontStyle)1, alignment = (TextAnchor)3, clipping = (TextClipping)1, wordWrap = false }; _amountStyle = new GUIStyle(GUI.skin.label) { fontSize = num, fontStyle = (FontStyle)1, alignment = (TextAnchor)5, clipping = (TextClipping)1, wordWrap = false }; } } } private const string Section = "InstantLoot"; private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _dropDelay; private static ConfigEntry<float> _destroyDelay; private static ConfigEntry<float> _autoPickupDelay; private static ConfigEntry<float> _autoPickupRange; private static ConfigEntry<bool> _notificationEnabled; private static ConfigEntry<NotificationAnchor> _notificationAnchor; private static ConfigEntry<int> _notificationX; private static ConfigEntry<int> _notificationY; private static ConfigEntry<int> _notificationWidth; private static ConfigEntry<int> _notificationHeight; private static ConfigEntry<float> _notificationOpacity; private static ConfigEntry<float> _notificationLinger; private static ConfigEntry<int> _notificationFontSize; private static readonly MethodInfo SpawnLootMethod = AccessTools.Method(typeof(Ragdoll), "SpawnLoot", new Type[1] { typeof(Vector3) }, (Type[])null); private static bool _spawningLoot; private static InstantLootHost _host; public string Name => "InstantLoot"; private static bool IsEnabled { get { if (_featureEnabled != null) { return _featureEnabled.Value; } return false; } } public void Init(ConfigFile config, Harmony harmony) { //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "InstantLoot", true, "When on (default), creature loot spawns almost immediately on death instead of waiting through the full death animation, and you can tune ragdoll lifetime, auto-pickup delay/range, and a stacked pickup notification feed. When off, death loot and pickup messages behave like vanilla. What you see: bodies drop loot quickly and may vanish sooner; loot can auto-vacuum from farther away. Multiplayer: loot spawn and ragdoll destroy run only on the ragdoll owner so peers do not duplicate drops. Timing and UI settings are per-client and do not need to match for sync safety the way StackSize does."); _dropDelay = config.Bind<float>("InstantLoot", "DropDelay", 0.01f, "Seconds after a ragdoll appears before its loot is spawned. Default is 0.01 (near-instant). A negative value skips spawning loot and only destroys the body. Requires Features.InstantLoot. Multiplayer: only the ragdoll ZNetView owner spawns loot. Local timing preference."); _destroyDelay = config.Bind<float>("InstantLoot", "DestroyDelay", 0.05f, "Seconds a ragdoll remains in the world before it is destroyed after loot handling. Default is 0.05. Higher values leave corpses visible longer; lower values clear bodies faster. Requires Features.InstantLoot. Multiplayer: only the ragdoll owner destroys it. Local timing preference."); _autoPickupDelay = config.Bind<float>("InstantLoot", "AutoPickupDelay", 0.01f, "Seconds before monster loot ItemDrops become eligible for auto-pickup after they spawn. Default is 0.01. Set to 0 to keep vanilla auto-pickup timing so piles stay longer before vacuuming. Manual use-key pickup always works. Local client setting."); _autoPickupRange = config.Bind<float>("InstantLoot", "AutoPickupRange", 10f, "How far (in meters) your local player auto-picks up eligible ground loot. Default is 10. Larger values scoop farther piles; smaller values feel closer to vanilla. Does not change other players' pickup range. Local client setting."); _notificationEnabled = config.Bind<bool>("InstantLoot", "NotificationEnabled", true, "When true (default), pickups show in a stacked loot feed window instead of vanilla one-at-a-time floating messages. When false, vanilla pickup messages return. Local UI only — other players do not see your feed and do not need this setting."); _notificationAnchor = config.Bind<NotificationAnchor>("InstantLoot", "NotificationAnchor", NotificationAnchor.BottomRight, "Screen corner the stacked loot window is measured from. Default is BottomRight. Combined with NotificationWindowX/Y to place the feed. Local UI preference."); _notificationX = config.Bind<int>("InstantLoot", "NotificationWindowX", 20, "Horizontal pixel offset of the loot feed from the chosen NotificationAnchor corner. Default is 20. Local UI preference."); _notificationY = config.Bind<int>("InstantLoot", "NotificationWindowY", 20, "Vertical pixel offset of the loot feed from the chosen NotificationAnchor corner. Default is 20. Local UI preference."); _notificationWidth = config.Bind<int>("InstantLoot", "NotificationWindowWidth", 250, "Width in pixels of the stacked loot pickup window. Default is 250. Local UI preference."); _notificationHeight = config.Bind<int>("InstantLoot", "NotificationWindowHeight", 120, "Height in pixels of the stacked loot pickup window. Default is 120. Local UI preference."); _notificationOpacity = config.Bind<float>("InstantLoot", "NotificationOpacity", 0.72f, "Background opacity of the loot feed window from 0 (invisible) to 1 (fully solid). Default is 0.72. Local UI preference."); _notificationLinger = config.Bind<float>("InstantLoot", "NotificationLinger", 8f, "Seconds each pickup line remains visible in the loot feed before fading out. Default is 8. Local UI preference."); _notificationFontSize = config.Bind<int>("InstantLoot", "NotificationFontSize", 15, "Font size for item names and amounts in the loot feed. Default is 15. Local UI preference."); GameObject val = new GameObject("KingQOL_InstantLoot"); Object.DontDestroyOnLoad((Object)(object)val); _host = val.AddComponent<InstantLootHost>(); val.AddComponent<PickupFeed>(); harmony.PatchAll(typeof(Ragdoll_Awake_Patch)); harmony.PatchAll(typeof(Ragdoll_DestroyNow_Patch)); harmony.PatchAll(typeof(ItemDrop_Awake_Patch)); harmony.PatchAll(typeof(Player_AutoPickup_Patch)); harmony.PatchAll(typeof(Character_ShowPickupMessage_Patch)); } private static IEnumerator DropNow(Ragdoll ragdoll, ZNetView nview, EffectList removeEffect) { float value = _dropDelay.Value; if (value < 0f) { if ((Object)(object)_host != (Object)null) { ((MonoBehaviour)_host).StartCoroutine(DestroyNow(ragdoll, nview, removeEffect)); } yield break; } if (value > 0f) { yield return (object)new WaitForSeconds(value); } if (!IsEnabled || (Object)(object)ragdoll == (Object)null || (Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner()) { yield break; } Vector3 val = ragdoll.GetAverageBodyPosition(); if ((Object)(object)ragdoll.m_lootSpawnJoint != (Object)null) { val = ragdoll.m_lootSpawnJoint.transform.position; } _spawningLoot = true; try { if (SpawnLootMethod != null) { SpawnLootMethod.Invoke(ragdoll, new object[1] { val }); } } finally { _spawningLoot = false; } if ((Object)(object)_host != (Object)null) { ((MonoBehaviour)_host).StartCoroutine(DestroyNow(ragdoll, nview, removeEffect)); } } private static IEnumerator DestroyNow(Ragdoll ragdoll, ZNetView nview, EffectList removeEffect) { float num = Mathf.Max(_destroyDelay.Value - Mathf.Max(_dropDelay.Value, 0f), 0f); if (num > 0f) { yield return (object)new WaitForSeconds(num); } if (IsEnabled && !((Object)(object)ragdoll == (Object)null) && !((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { Vector3 averageBodyPosition = ragdoll.GetAverageBodyPosition(); if (removeEffect != null) { removeEffect.Create(averageBodyPosition, Quaternion.identity, (Transform)null, 1f, -1, ZDOID.None); } if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)ragdoll).gameObject); } } } private static IEnumerator EnableAutoPickupLater(ItemDrop drop, float delay) { if (delay > 0f) { yield return (object)new WaitForSeconds(delay); } if ((Object)(object)drop != (Object)null) { drop.m_autoPickup = true; } } } internal sealed class AutoLootFeature : IKingFeature { [HarmonyPatch(typeof(Humanoid), "Pickup")] private static class Humanoid_Pickup_Patch { private static void Prefix(Humanoid __instance, GameObject go) { ClearPending(); if (_featureEnabled == null || !_featureEnabled.Value || _busy) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)localPlayer) && !((Object)(object)go == (Object)null)) { ItemDrop component = go.GetComponent<ItemDrop>(); if (component?.m_itemData?.m_shared != null) { _pendingSharedName = component.m_itemData.m_shared.m_name; _pendingPrefabKey = GetPrefabKey(component); _pendingInstanceId = ((Object)component).GetInstanceID(); } } } private static void Postfix(Humanoid __instance, bool __result) { string pendingSharedName = _pendingSharedName; string pendingPrefabKey = _pendingPrefabKey; int pendingInstanceId = _pendingInstanceId; ClearPending(); if (_featureEnabled == null || !_featureEnabled.Value || _busy || !__result || string.IsNullOrEmpty(pendingSharedName)) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)localPlayer) { return; } _busy = true; try { TryLootNearby(localPlayer, pendingSharedName, pendingPrefabKey, pendingInstanceId); } finally { _busy = false; } } } private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _radius; private static ConfigEntry<bool> _samePrefabOnly; private static bool _busy; private static string _pendingSharedName; private static string _pendingPrefabKey; private static int _pendingInstanceId; public string Name => "AutoLoot"; public void Init(ConfigFile config, Harmony harmony) { _featureEnabled = config.Bind<bool>("Features", "AutoLoot", true, "When on (default), after you successfully pick up a ground item, matching nearby ground drops are also picked up into your inventory in one go. When off, you only get the single item you targeted. What you see: piles of the same loot vacuum into you after one pickup. Local player only — does not pull from chests. Other clients do not need this toggle for your loot; removed drops still sync normally for everyone."); _radius = config.Bind<float>("AutoLoot", "Radius", 8f, "How far (in meters, horizontal) around you matching ground ItemDrops are collected after a pickup. Default is 8. Larger values scoop farther piles; smaller values keep loot more selective. Local client setting."); _samePrefabOnly = config.Bind<bool>("AutoLoot", "SamePrefabOnly", true, "When true (default), only ground drops that share both the same item name and the same prefab as the item you picked up are collected. When false, any nearby drop with the same item name can be looted even if the prefab differs. Local preference."); harmony.PatchAll(typeof(Humanoid_Pickup_Patch)); } private static void ClearPending() { _pendingSharedName = null; _pendingPrefabKey = null; _pendingInstanceId = 0; } private static void TryLootNearby(Player player, string sharedName, string prefabKey, int ignoreInstanceId) { //IL_0018: 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) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(sharedName)) { return; } Vector3 position = ((Component)player).transform.position; foreach (ItemDrop groundItem in AreaScan.GetGroundItems(position, _radius.Value)) { if (!((Object)(object)groundItem == (Object)null) && (ignoreInstanceId == 0 || ((Object)groundItem).GetInstanceID() != ignoreInstanceId) && IsEligibleMatch(groundItem, sharedName, prefabKey, player)) { groundItem.Pickup((Humanoid)(object)player); } } } private static bool IsEligibleMatch(ItemDrop drop, string sharedName, string prefabKey, Player localPlayer) { if (drop.m_itemData?.m_shared == null) { return false; } if (!drop.m_autoPickup) { return false; } if (drop.IsPiece()) { return false; } if (drop.InTar()) { return false; } ZNetView nview = drop.m_nview; if ((Object)(object)nview != (Object)null && !nview.IsValid()) { return false; } if ((Object)(object)drop.m_pickupRequester != (Object)null && (Object)(object)drop.m_pickupRequester != (Object)(object)localPlayer) { return false; } if (drop.m_itemData.m_shared.m_name != sharedName) { return false; } if (_samePrefabOnly.Value) { string prefabKey2 = GetPrefabKey(drop); if (string.IsNullOrEmpty(prefabKey) || string.IsNullOrEmpty(prefabKey2) || prefabKey != prefabKey2) { return false; } } return true; } private static string GetPrefabKey(ItemDrop drop) { if ((Object)(object)drop == (Object)null) { return null; } if ((Object)(object)drop.m_itemData?.m_dropPrefab != (Object)null) { return ((Object)drop.m_itemData.m_dropPrefab).name; } if ((Object)(object)drop.m_nview != (Object)null && drop.m_nview.IsValid()) { string prefabName = drop.m_nview.GetPrefabName(); if (!string.IsNullOrEmpty(prefabName)) { return prefabName; } } if (!((Object)(object)((Component)drop).gameObject != (Object)null)) { return null; } return ((Object)((Component)drop).gameObject).name.Replace("(Clone)", string.Empty); } } internal sealed class SortFeature : IKingFeature { private sealed class SortBehaviour : MonoBehaviour { private void Update() { //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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (_featureEnabled != null && _featureEnabled.Value) { KeyboardShortcut value = _inventoryHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { TrySortPlayerInventory(); } value = _chestHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { TrySortOpenChest(); } } } } private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<KeyboardShortcut> _inventoryHotkey; private static ConfigEntry<KeyboardShortcut> _chestHotkey; public string Name => "Sort"; public void Init(ConfigFile config, Harmony harmony) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "Sort", true, "When on (default), hotkeys reorder items in your personal inventory and in the chest you currently have open. When off, both sort hotkeys do nothing. Inventory sorts are local to you. Chest sorts sync over the network so other players see the new order after Save. Items are never dropped on the ground."); _inventoryHotkey = config.Bind<KeyboardShortcut>("Sort", "InventoryHotkey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Keyboard shortcut to sort your own inventory by item type and name. Default is F9. Rebind here or in Configuration Manager. Only affects the local player. Ignored while typing in chat, console, or text input."); _chestHotkey = config.Bind<KeyboardShortcut>("Sort", "ChestHotkey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Keyboard shortcut to sort the container you currently have open. Default is F10. Rebind here or in Configuration Manager. Requires an open chest UI; other players see the reordered contents once the chest syncs. Ignored while typing in chat, console, or text input."); GameObject val = new GameObject("KingQOL_Sort"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<SortBehaviour>(); } private static bool IsTypingInTextField() { if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } return false; } private static void TrySortPlayerInventory() { if (_featureEnabled != null && _featureEnabled.Value && !IsTypingInTextField()) { Player localPlayer = Player.m_localPlayer; Inventory val = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val != null) { SortInventory(val); } } } private static void TrySortOpenChest() { if (_featureEnabled == null || !_featureEnabled.Value || IsTypingInTextField()) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || !instance.IsContainerOpen()) { return; } Container currentContainer = instance.m_currentContainer; if (!((Object)(object)currentContainer == (Object)null) && NetAccess.TryClaim((Component)(object)currentContainer)) { currentContainer.Load(); Inventory inventory = currentContainer.GetInventory(); if (inventory != null) { SortInventory(inventory); currentContainer.Save(); } } } private static void SortInventory(Inventory inventory) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (inventory != null && inventory.NrOfItems() != 0) { MergeStacks(inventory); List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); list.Sort(CompareItems); int num = Math.Max(1, inventory.GetWidth()); for (int i = 0; i < list.Count; i++) { list[i].m_gridPos = new Vector2i(i % num, i / num); } inventory.Changed(false, false); } } private static void MergeStacks(Inventory inventory) { List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); foreach (ItemData item in list) { if (item?.m_shared == null || item.m_stack <= 0 || item.m_shared.m_maxStackSize <= 1 || !inventory.ContainsItem(item)) { continue; } while (inventory.ContainsItem(item) && item.m_stack > 0) { ItemData val = FindMergeTarget(inventory, item); if (val == null) { break; } int num = Math.Min(item.m_stack, val.GetSpaceLeftInStack()); if (num <= 0 || !inventory.MoveItemToThis(inventory, item, num, val.m_gridPos.x, val.m_gridPos.y)) { break; } } } } private static ItemData FindMergeTarget(Inventory inventory, ItemData source) { foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null && allItem != source && source.IsSameType(allItem) && allItem.GetSpaceLeftInStack() > 0) { return allItem; } } return null; } private static int CompareItems(ItemData a, ItemData b) { string strA = a?.m_shared?.m_name ?? string.Empty; string strB = b?.m_shared?.m_name ?? string.Empty; int num = string.Compare(strA, strB, StringComparison.Ordinal); if (num != 0) { return num; } return (a?.m_quality ?? 0).CompareTo(b?.m_quality ?? 0); } } internal sealed class StackSizeFeature : IKingFeature { [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_Patch { private static void Postfix(ObjectDB __instance) { ApplyToObjectDB(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB_Patch { private static void Postfix(ObjectDB __instance) { ApplyToObjectDB(__instance); } } [HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")] private static class ObjectDB_UpdateRegisters_Patch { private static void Postfix(ObjectDB __instance) { ApplyToObjectDB(__instance); } } private const int NoCapCeiling = 100000; private static readonly Dictionary<SharedData, int> OriginalMaxStacks = new Dictionary<SharedData, int>(); private static readonly Dictionary<SharedData, float> OriginalWeights = new Dictionary<SharedData, float>(); private static ConfigEntry<bool> _featureEnabled; private static ConfigEntry<float> _multiplier; private static ConfigEntry<int> _maxCap; private static ConfigEntry<float> _weightPercent; public string Name => "StackSize"; public void Init(ConfigFile config, Harmony harmony) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown _featureEnabled = config.Bind<bool>("Features", "StackSize", true, "When on (default), multiplies max stack sizes and scales item weight from each item's original ObjectDB data. When off, stacks and weight stay vanilla. What you see: larger (or smaller) stacks in inventory and chests, and weight that matches WeightPercent. Multiplayer: every client must use the same Features.StackSize, Multiplier, MaxCap, and WeightPercent values or stacks and encumbrance will desync between players."); _multiplier = config.Bind<float>("StackSize", "Multiplier", 10f, "Multiplies each stackable item's original max stack by this amount. Default is 10 (e.g. a vanilla stack of 20 becomes 200). Recommended range is roughly 1–100. Applied once from original data, not compounded on reload. All players must share the same Multiplier or stack splits and merges will disagree across clients."); _maxCap = config.Bind<int>("StackSize", "MaxCap", 0, "Optional hard ceiling applied after Multiplier. Default is 0, meaning no extra cap beyond an internal safety ceiling of 100000. Set a positive number (e.g. 999) to clamp huge stacks. All players must use the same MaxCap or stack limits will desync."); _weightPercent = config.Bind<float>("StackSize", "WeightPercent", 100f, new ConfigDescription("Item weight as a percent of vanilla (float, default 100). Acceptable values 1–100: 100 = full vanilla weight, 10 = items weigh 10% of vanilla, 1 = 1% of vanilla. Applied from each item's original shared weight so it does not compound on reload. All players need the same value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); harmony.PatchAll(typeof(ObjectDB_Awake_Patch)); harmony.PatchAll(typeof(ObjectDB_CopyOtherDB_Patch)); harmony.PatchAll(typeof(ObjectDB_UpdateRegisters_Patch)); } private static void ApplyToObjectDB(ObjectDB db) { if (_featureEnabled == null || !_featureEnabled.Value || (Object)(object)db == (Object)null || db.m_items == null) { return; } foreach (GameObject item in db.m_items) { if (!((Object)(object)item == (Object)null)) { ItemDrop component = item.GetComponent<ItemDrop>(); if (component?.m_itemData?.m_shared != null) { ApplyToShared(component.m_itemData.m_shared); } } } } private static void ApplyToShared(SharedData shared) { if (shared != null) { if (!OriginalWeights.TryGetValue(shared, out var value)) { value = shared.m_weight; OriginalWeights[shared] = value; } float num = Mathf.Clamp((_weightPercent != null) ? _weightPercent.Value : 100f, 1f, 100f); shared.m_weight = value * (num / 100f); if (!OriginalMaxStacks.TryGetValue(shared, out var value2)) { value2 = shared.m_maxStackSize; OriginalMaxStacks[shared] = value2; } if (value2 > 1) { int num2 = Mathf.RoundToInt((float)value2 * _multiplier.Value); int num3 = ((_maxCap.Value > 0) ? _maxCap.Value : 100000); shared.m_maxStackSize = Mathf.Clamp(num2, 1, num3); } } } } internal sealed class MapNodesFeature : IKingFeature { private sealed class MapNodesBehaviour : MonoBehaviour { private void Update() { if (_featureEnabled == null || !_featureEnabled.Value) { _mapWasOpen = false; return; } if (!IsLargeMapOpen()) { _mapWasOpen = false; return; } long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0); if (num != _loadedWorld) { _loadedWorld = num; Visited.Clear(); Nodes.Clear(); _nextScan = 0f; _mapWasOpen = false; if (num != 0L) { LoadVisited(num); } } if (num != 0L) { bool flag = !_mapWasOpen; _mapWasOpen = true; if (flag || !(Time.unscaledTime < _nextScan)) { _nextScan = Time.unscaledTime + 5f; RebuildNodes(); } } } private void OnGUI() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) if (_featureEnabled == null || !_featureEnabled.Value || !IsLargeMapOpen() || _loadedWorld == 0L) { _mouseOverPanel = false; return; } Minimap instance = Minimap.instance; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y); DrawMarkers(instance, val); _panelRect = GUILayout.Window(((Object)this).GetInstanceID(), _panelRect, new WindowFunction(DrawPanel), "Map nodes", Array.Empty<GUILayoutOption>()); _mouseOverPanel = ((Rect)(ref _panelRect)).Contains(val); } private static void DrawMarkers(Minimap map, Vector2 guiMouse) { //IL_0011: 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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_0069: 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_0086: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) RawImage mapImageLarge = map.m_mapImageLarge; if ((Object)(object)mapImageLarge == (Object)null) { return; } Color color = GUI.color; Rect val = default(Rect); foreach (Node node in Nodes) { if (node.Kind.Show.Value && map.IsExplored(node.Position) && map.IsPointVisible(node.Position, mapImageLarge) && TryWorldToGui(map, node.Position, out var gui)) { ((Rect)(ref val))..ctor(gui.x - 8f, gui.y - 8f, 16f, 16f); GUI.color = node.Kind.Color; GUI.DrawTexture(val, (Texture)(object)Pixel()); if (Visited.Contains(node.Key)) { GUI.color = Color.white; GUI.Label(val, "X", XStyle()); } } } GUI.color = color; } private static void DrawPanel(int id) { GUILayout.Label("Revealed map only. Click a marker to mark it visited.", Array.Empty<GUILayoutOption>()); foreach (Kind kind in Kinds) { kind.Show.Value = GUILayout.Toggle(kind.Show.Value, kind.Label, Array.Empty<GUILayoutOption>()); } GUI.DragWindow(); } } private sealed class Kind { public readonly string Id; public readonly string Label; public readonly Color Color; public readonly ConfigEntry<bool> Show; public readonly string[] ZdoPrefabs; public readonly Func<string, bool> MatchLocation; public Kind(string id, string label, Color color, ConfigEntry<bool> show, string[] zdoPrefabs, Func<string, bool> matchLocation) { //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) Id = id; Label = label; Color = color; Show = show; ZdoPrefabs = zdoPrefabs; MatchLocation = matchLocation; } } private sealed class Node { public readonly Kind Kind; public readonly Vector3 Position; public readonly string Key; public Node(Kind kind, Vector3 position) { //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_001b: Unknown result type (might be due to invalid IL or missing references) Kind = kind; Position = position; Key = MarkKey(kind.Id, position); } } [HarmonyPatch(typeof(Minimap), "OnMapLeftClick")] private static class MapClickPatch { private static bool Prefix() { return !TryConsumeClick(); } } private const float ScanInterval = 5f; private const float HitRadius = 14f; private const float MarkerSize = 16f; private static ConfigEntry<bool> _featureEnabled; private static readonly List<Kind> Kinds = new List<Kind>(); private static readonly List<Node> Nodes = new List<Node>(); private static readonly HashSet<string> Visited = new HashSet<string>(); private static string _configDirectory; private static long _loadedWorld; private static float _nextScan; private static bool _mapWasOpen; private static Rect _panelRect = new Rect(12f, 80f, 220f, 420f); private static bool _mouseOverPanel; private static Texture2D _pixel; private static GUIStyle _xStyle; public string Name => "MapNodes"; public void Init(ConfigFile config, Harmony harmony) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Expected O, but got Unknown _configDirectory = Path.GetDirectoryName(config.ConfigFilePath); _featureEnabled = config.Bind<bool>("Features", "MapNodes", true, "When on (default), the large map can show colored markers for ore deposits and dungeon/cave entrances that sit on terrain you have already explored (inside revealed fog). When off, no markers or filter panel appear. Markers are local to this client and this world — they are not shared map pins and do not sync to other players. Click a marker to mark it visited so it stops cluttering your map."); AddKind(config, "Copper", new Color(0.8f, 0.48f, 0.22f), new string[1] { "MineRock_Copper" }, null); AddKind(config, "Tin", new Color(0.78f, 0.8f, 0.84f), new string[1] { "MineRock_Tin" }, null); AddKind(config, "Iron", new Color(0.55f, 0.32f, 0.22f), new string[2] { "mudpile", "mudpile2" }, null); AddKind(config, "Silver", new Color(0.9f, 0.92f, 0.95f), new string[1] { "silvervein" }, null); AddKind(config, "Obsidian", new Color(0.28f, 0.22f, 0.38f), new string[1] { "MineRock_Obsidian" }, null); AddKind(config, "Flametal", new Color(0.92f, 0.38f, 0.12f), new string[1] { "MineRock_Flametal" }, null); AddKind(config, "Burial chambers", new Color(0.45f, 0.58f, 0.32f), null, IsBurialChamber); AddKind(config, "Troll caves", new Color(0.32f, 0.48f, 0.28f), null, (string name) => Has(name, "TrollCave")); AddKind(config, "Sunken crypts", new Color(0.28f, 0.46f, 0.4f), null, (string name) => Has(name, "SunkenCrypt")); AddKind(config, "Frost caves", new Color(0.62f, 0.78f, 0.92f), null, (string name) => Has(name, "MountainCave") || Has(name, "FrostCave")); AddKind(config, "Infested mines", new Color(0.48f, 0.3f, 0.58f), null, (string name) => Has(name, "InfestedMine")); harmony.PatchAll(typeof(MapClickPatch)); GameObject val = new GameObject("KingQOL_MapNodes"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<MapNodesBehaviour>(); } private static void AddKind(ConfigFile config, string label, Color color, string[] zdos, Func<string, bool> location) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) string text = label.Replace(" ", string.Empty); ConfigEntry<bool> show = config.Bind<bool>("MapNodes", "Show" + text, false, "When true, show " + label + " markers on the large map for deposits or locations already inside revealed fog. Default is false (hidden until you opt in). Requires Features.MapNodes. Markers are local to this client and world — other players do not see your markers or need matching Show* settings. Click a marker to mark it visited."); Kinds.Add(new Kind(text, label, color, show, zdos, location)); } private static bool IsBurialChamber(string name) { if (Has(name, "Crypt")) { return !Has(name, "Sunken"); } return false; } private static bool Has(string name, string token) { if (name != null) { return name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static void RebuildNodes() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) Nodes.Clear(); Minimap instance = Minimap.instance; ZoneSystem instance2 = ZoneSystem.instance; ZDOMan instance3 = ZDOMan.instance; if ((Object)(object)instance == (Object)null) { return; } if ((Object)(object)instance2 != (Object)null && instance2.m_locationInstances != null) { foreach (LocationInstance value in instance2.m_locationInstances.Values) { if (!value.m_placed || value.m_location == null || !instance.IsExplored(value.m_position)) { continue; } string arg = LocationPrefabName(value.m_location); foreach (Kind kind in Kinds) { if (kind.Show.Value && kind.MatchLocation != null && kind.MatchLocation(arg)) { Nodes.Add(new Node(kind, value.m_position)); break; } } } } if (instance3 == null) { return; } List<ZDO> list = new List<ZDO>(); foreach (Kind kind2 in Kinds) { if (kind2.ZdoPrefabs == null || !kind2.Show.Value) { continue; } string[] zdoPrefabs = kind2.ZdoPrefabs; foreach (string text in zdoPrefabs) { list.Clear(); int num = 0; while (instance3.GetAllZDOsWithPrefabIterative(text, list, ref num)) { } foreach (ZDO item in list) { if (item != null) { Vector3 position = item.GetPosition(); if (instance.IsExplored(position)) { Nodes.Add(new Node(kind2, position)); } } } } } } private static string LocationPrefabName(ZoneLocation location) { if (!string.IsNullOrEmpty(location.m_prefab.Name)) { return location.m_prefab.Name; } if (!string.IsNullOrEmpty(location.m_prefabName)) { return location.m_prefabName; } return location.m_name ?? string.Empty; } internal static bool TryConsumeClick() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00c9: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (_featureEnabled == null || !_featureEnabled.Value || !IsLargeMapOpen() || _loadedWorld == 0L) { return false; } if (_mouseOverPanel) { return true; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_mapImageLarge == (Object)null) { return false; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y); Node node = null; float num = 196f; foreach (Node node2 in Nodes) { if (node2.Kind.Show.Value && instance.IsExplored(node2.Position) && instance.IsPointVisible(node2.Position, instance.m_mapImageLarge) && TryWorldToGui(instance, node2.Position, out var gui)) { float num2 = gui.x - val.x; float num3 = gui.y - val.y; float num4 = num2 * num2 + num3 * num3; if (num4 <= num) { num = num4; node = node2; } } } if (node == null) { return false; } if (!Visited.Add(node.Key)) { Visited.Remove(node.Key); } SaveVisited(_loadedWorld); return true; } private static bool IsLargeMapOpen() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 Minimap instance = Minimap.instance; if ((Object)(object)instance != (Object)null && Minimap.IsOpen()) { return (int)instance.m_mode == 2; } return false; } private static bool TryWorldToGui(Minimap map, Vector3 world, out Vector2 gui) { //IL_0001: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) //IL_008a: 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) gui = default(Vector2); RawImage mapImageLarge = map.m_mapImageLarge; if ((Object)(object)mapImageLarge == (Object)null) { return false; } float num = default(float); float num2 = default(float); map.WorldToMapPoint(world, ref num, ref num2); Vector2 val = map.MapPointToLocalGuiPos(num, num2, mapImageLarge); Canvas canvas = ((Graphic)mapImageLarge).canvas; Camera val2 = null; if ((Object)(object)canvas != (Object)null && (int)canvas.renderMode != 0) { val2 = canvas.worldCamera; } Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val2, ((Transform)((Graphic)mapImageLarge).rectTransform).TransformPoint(Vector2.op_Implicit(val))); gui = new Vector2(val3.x, (float)Screen.height - val3.y); return true; } private static Texture2D Pixel() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_pixel != (Object)null) { return _pixel; } _pixel = new Texture2D(1, 1, (TextureFormat)4, false); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); return _pixel; } private static GUIStyle XStyle() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (_xStyle != null) { return _xStyle; } _xStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = (FontStyle)1, fontSize = 14 }; _xStyle.normal.textColor = new Color(0.85f, 0.12f, 0.12f); return _xStyle; } private static string MarksPath(long worldUid) { return Path.Combine(_configDirectory ?? string.Empty, "KingQOL-mapmarks-" + worldUid + ".txt"); } private static void LoadVisited(long worldUid) { Visited.Clear(); string path = MarksPath(worldUid); if (!File.Exists(path)) { return; } string[] array = File.ReadAllLines(path); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text)) { Visited.Add(text.Trim()); } } } private static void SaveVisited(long worldUid) { string path = MarksPath(worldUid); string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllLines(path, Visited); } private static string MarkKey(string kindId, Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(position.x * 2f); int num2 = Mathf.RoundToInt(position.z * 2f); return kindId + ":" + num + ":" + num2; } } internal static class FeatureToggles { public const string Section = "Features"; } internal interface IKingFeature { string Name { get; } void Init(ConfigFile config, Harmony harmony); } [BepInPlugin("com.whtbros.kingqol", "King QOL", "0.1.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class KingQOL : BaseUnityPlugin { public const string PluginGUID = "com.whtbros.kingqol"; public const string PluginName = "King QOL"; public const string PluginVersion = "0.1.6"; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony harmony = new Harmony("com.whtbros.kingqol"); foreach (Type item in from t in Assembly.GetExecutingAssembly().GetTypes() where typeof(IKingFeature).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract select t) { IKingFeature kingFeature = (IKingFeature)Activator.CreateInstance(item); kingFeature.Init(((BaseUnityPlugin)this).Config, harmony); Logger.LogInfo((object)("Feature loaded: " + kingFeature.Name)); } Logger.LogInfo((object)"King QOL loaded"); } } } namespace KingQOL.World { internal static class AreaScan { public static IEnumerable<Container> GetChests(Vector3 center, float radius) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) foreach (Container item in FindInRadius<Container>(WorldObjectCache.GetContainers(), center, radius)) { if (!((Object)(object)((Component)item).GetComponent<TombStone>() != (Object)null) && (string.IsNullOrEmpty(item.m_name) || item.m_name.IndexOf("tombstone", StringComparison.OrdinalIgnoreCase) < 0) && (!((Object)(object)item.m_piece != (Object)null) || string.IsNullOrEmpty(item.m_piece.m_name) || item.m_piece.m_name.IndexOf("tombstone", StringComparison.OrdinalIgnoreCase) < 0)) { item.Load(); Inventory invent