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 VikingQualityOfLife v2.1.2
BepInEx/plugins/ccorp/ccorp.dll
Decompiled 19 hours 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.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ccorp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+55ac085e598f45528b30b0721946a085c7dd2397")] [assembly: AssemblyProduct("ccorp")] [assembly: AssemblyTitle("ccorp")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ccorp { internal static class AdminSpawnMenu { private sealed class Entry { internal string Prefab; internal string Name; internal Sprite Icon; } private const int PageSize = 18; private static GameObject _root; private static GameObject _quantityRoot; private static RectTransform _rows; private static TMP_Text _status; private static TMP_Text _pageText; private static TMP_InputField _search; private static TMP_InputField _amount; private static TMP_FontAsset _font; private static readonly List<Entry> Catalog = new List<Entry>(); private static int _page; internal static bool HasQuantityPrompt => (Object)(object)_quantityRoot != (Object)null; internal static bool IsOpen { get { if ((Object)(object)_root != (Object)null) { return _root.activeSelf; } return false; } } internal static void Show() { try { BuildMenu(); } catch { Close(); throw; } } private static void BuildMenu() { //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_044e: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Expected O, but got Unknown //IL_0541: Unknown result type (might be due to invalid IL or missing references) //IL_056b: Unknown result type (might be due to invalid IL or missing references) //IL_0584: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_05f6: Unknown result type (might be due to invalid IL or missing references) //IL_0630: Unknown result type (might be due to invalid IL or missing references) //IL_063f: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Unknown result type (might be due to invalid IL or missing references) //IL_0672: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Hud.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } Close(); _font = ((TMP_Text)Hud.instance.m_hoverName).font; Catalog.Clear(); foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (val?.m_itemData?.m_shared != null) { ZNetScene instance = ZNetScene.instance; if (!((Object)(object)((instance != null) ? instance.GetPrefab(((Object)item).name) : null) == (Object)null) && AdminSpawnMenuInput.IsValid(((Object)item).name, 1)) { Catalog.Add(new Entry { Prefab = ((Object)item).name, Name = (string.IsNullOrEmpty(val.m_itemData.m_shared.m_name) ? ((Object)item).name : Localization.instance.Localize(val.m_itemData.m_shared.m_name)), Icon = PickupCatalogSafety.SelectIcon(val.m_itemData.m_shared.m_icons, val.m_itemData.m_variant) }); } } } Catalog.Sort((Entry a, Entry b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase)); _page = 0; _root = new GameObject("ccorp.AdminSpawnMenu", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); Canvas component = _root.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 100; CanvasScaler component2 = _root.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1280f, 720f); component2.matchWidthOrHeight = 0.5f; RectTransform obj = Box(_root.transform, "Shade", Vector2.zero, new Vector2(1280f, 720f), new Color(0f, 0f, 0f, 0.6f)); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.sizeDelta = Vector2.zero; RectTransform val2 = Box(_root.transform, "Panel", Vector2.zero, new Vector2(780f, 610f), new Color(0.1f, 0.075f, 0.045f, 0.99f)); Label((Transform)(object)val2, "Admin item spawn", new Vector2(0f, 264f), new Vector2(650f, 40f), 26f); Button((Transform)(object)val2, "Close", new Vector2(330f, 265f), new Vector2(92f, 32f), Close); _status = Label((Transform)(object)val2, "", new Vector2(0f, 224f), new Vector2(720f, 34f), 16f); RectTransform val3 = Box((Transform)(object)val2, "Search", new Vector2(0f, 180f), new Vector2(720f, 40f), new Color(0.18f, 0.16f, 0.12f)); _search = ((Component)val3).gameObject.AddComponent<TMP_InputField>(); RectTransform component3 = new GameObject("Viewport", new Type[2] { typeof(RectTransform), typeof(RectMask2D) }).GetComponent<RectTransform>(); ((Transform)component3).SetParent((Transform)(object)val3, false); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.offsetMin = new Vector2(12f, 4f); component3.offsetMax = new Vector2(-12f, -4f); TMP_Text val4 = Label((Transform)(object)component3, "", Vector2.zero, new Vector2(690f, 32f), 19f); val4.alignment = (TextAlignmentOptions)4097; val4.richText = false; TMP_Text val5 = Label((Transform)(object)component3, "Search item name or prefab...", Vector2.zero, new Vector2(690f, 32f), 19f); val5.alignment = (TextAlignmentOptions)4097; ((Graphic)val5).color = new Color(0.7f, 0.7f, 0.7f); _search.textViewport = component3; _search.textComponent = (TMP_Text)(TextMeshProUGUI)val4; _search.placeholder = (Graphic)(object)val5; _search.lineType = (LineType)0; _search.characterLimit = 100; ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate { _page = 0; Refresh(); }); _rows = new GameObject("Rows", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>(); ((Transform)_rows).SetParent((Transform)(object)val2, false); _rows.sizeDelta = new Vector2(730f, 380f); _rows.anchoredPosition = new Vector2(0f, -34f); Button((Transform)(object)val2, "< Previous", new Vector2(45f, -250f), new Vector2(130f, 36f), delegate { _page = Math.Max(0, _page - 1); Refresh(); }); Button((Transform)(object)val2, "Next >", new Vector2(205f, -250f), new Vector2(130f, 36f), delegate { _page++; Refresh(); }); _pageText = Label((Transform)(object)val2, "", new Vector2(325f, -250f), new Vector2(90f, 36f), 16f); Label((Transform)(object)val2, "Click an item, enter a quantity and spawn it. • F7 / Esc to close", new Vector2(0f, -285f), new Vector2(740f, 25f), 14f); Refresh(); GameCamera instance2 = GameCamera.instance; if (instance2 != null) { instance2.UpdateMouseCapture(); } _search.ActivateInputField(); } private static void Refresh() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root == (Object)null) { return; } foreach (Transform item in (Transform)_rows) { ((Component)item).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)item).gameObject); } string query = _search.text ?? ""; List<Entry> list = Catalog.Where((Entry e) => e.Name.IndexOf(query, StringComparison.CurrentCultureIgnoreCase) >= 0 || e.Prefab.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); int num = Math.Max(1, (list.Count + 18 - 1) / 18); _page = Math.Max(0, Math.Min(_page, num - 1)); _status.text = $"{list.Count} items • Server validates every spawn request"; _pageText.text = $"{_page + 1}/{num}"; Vector2 position = default(Vector2); for (int num2 = 0; num2 < Math.Min(18, list.Count - _page * 18); num2++) { Entry entry = list[_page * 18 + num2]; ((Vector2)(ref position))..ctor((float)((num2 % 2 == 0) ? (-182) : 182), (float)(166 - num2 / 2 * 41)); RectTransform obj = Button((Transform)(object)_rows, "", position, new Vector2(356f, 37f), delegate { AskQuantity(entry); }); ((Graphic)((Component)obj).GetComponent<Image>()).color = new Color(0.19f, 0.17f, 0.12f); RectTransform val2 = Box((Transform)(object)obj, "Icon", new Vector2(-155f, 0f), new Vector2(30f, 30f), Color.white); ((Component)val2).GetComponent<Image>().sprite = entry.Icon; if ((Object)(object)entry.Icon == (Object)null) { ((Graphic)((Component)val2).GetComponent<Image>()).color = Color.clear; } ((Component)val2).GetComponent<Image>().preserveAspect = true; ((Graphic)((Component)val2).GetComponent<Image>()).raycastTarget = false; TMP_Text obj2 = Label((Transform)(object)obj, entry.Name, new Vector2(15f, 0f), new Vector2(290f, 32f), 18f); obj2.alignment = (TextAlignmentOptions)4097; obj2.richText = false; obj2.enableAutoSizing = true; obj2.fontSizeMin = 12f; obj2.fontSizeMax = 18f; obj2.overflowMode = (TextOverflowModes)1; } if (list.Count == 0) { Label((Transform)(object)_rows, "No matching items.", Vector2.zero, new Vector2(600f, 40f), 20f); } } internal static void Close() { CancelQuantity(); if ((Object)(object)_search != (Object)null) { _search.DeactivateInputField(false); } if ((Object)(object)_root != (Object)null) { if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } _root.SetActive(false); Object.Destroy((Object)(object)_root); } _root = null; _rows = null; _search = null; _status = (_pageText = null); _font = null; Catalog.Clear(); GameCamera instance = GameCamera.instance; if (instance != null) { instance.UpdateMouseCapture(); } } private static void AskQuantity(Entry entry) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected O, but got Unknown //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) CancelQuantity(); _search.DeactivateInputField(false); RectTransform obj = Box(_root.transform, "QuantityShade", Vector2.zero, new Vector2(1280f, 720f), new Color(0f, 0f, 0f, 0.7f)); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.sizeDelta = Vector2.zero; _quantityRoot = ((Component)obj).gameObject; RectTransform parent = Box((Transform)(object)obj, "Quantity", Vector2.zero, new Vector2(470f, 260f), new Color(0.1f, 0.075f, 0.045f, 1f)); TMP_Text obj2 = Label((Transform)(object)parent, entry.Name, new Vector2(0f, 92f), new Vector2(440f, 35f), 23f); obj2.richText = false; obj2.overflowMode = (TextOverflowModes)1; TMP_Text obj3 = Label((Transform)(object)parent, entry.Prefab, new Vector2(0f, 59f), new Vector2(440f, 30f), 16f); obj3.richText = false; obj3.overflowMode = (TextOverflowModes)1; TMP_Text error = Label((Transform)(object)parent, "Quantity (positive whole number)", new Vector2(0f, 27f), new Vector2(440f, 30f), 16f); RectTransform val = Box((Transform)(object)parent, "Amount", new Vector2(0f, -10f), new Vector2(220f, 40f), new Color(0.18f, 0.16f, 0.12f)); _amount = ((Component)val).gameObject.AddComponent<TMP_InputField>(); RectTransform component = new GameObject("Viewport", new Type[2] { typeof(RectTransform), typeof(RectMask2D) }).GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)val, false); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = new Vector2(10f, 4f); component.offsetMax = new Vector2(-10f, -4f); TMP_Text val2 = Label((Transform)(object)component, "", Vector2.zero, new Vector2(190f, 32f), 20f); val2.richText = false; _amount.textViewport = component; _amount.textComponent = (TMP_Text)(TextMeshProUGUI)val2; _amount.lineType = (LineType)0; _amount.contentType = (ContentType)2; _amount.characterLimit = 10; _amount.text = "1"; bool submitted = false; Action spawn = delegate { if (!submitted && !((Object)(object)_amount == (Object)null)) { if (!AdminSpawnMenuInput.TryAmount(_amount.text, out var amount)) { error.text = "Enter a positive whole number."; _amount.ActivateInputField(); } else { submitted = true; if (!AdminSpawnMenuController.RequestSpawn(entry.Prefab, amount)) { submitted = false; if ((Object)(object)error != (Object)null) { error.text = "Could not send the request. Try again."; } } else { CancelQuantity(); if ((Object)(object)_status != (Object)null) { _status.text = $"Requested {entry.Prefab} x{amount}. Check the game's spawn confirmation."; } } } } }; Button((Transform)(object)parent, "Cancel", new Vector2(-105f, -83f), new Vector2(170f, 38f), CancelQuantity); Button((Transform)(object)parent, "Spawn", new Vector2(105f, -83f), new Vector2(170f, 38f), spawn); ((UnityEvent<string>)(object)_amount.onSubmit).AddListener((UnityAction<string>)delegate { spawn(); }); _amount.ActivateInputField(); } internal static void CancelQuantity() { if (!((Object)(object)_quantityRoot == (Object)null)) { if ((Object)(object)_amount != (Object)null) { _amount.DeactivateInputField(false); } if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } _quantityRoot.SetActive(false); Object.Destroy((Object)(object)_quantityRoot); _quantityRoot = null; _amount = null; } } private static RectTransform Box(Transform parent, string name, Vector2 position, Vector2 size, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0057: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent(parent, false); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); component.pivot = val2; Vector2 anchorMin = (component.anchorMax = val2); component.anchorMin = anchorMin; component.anchoredPosition = position; component.sizeDelta = size; ((Graphic)val.GetComponent<Image>()).color = color; return component; } private static TMP_Text Label(Transform parent, string text, Vector2 position, Vector2 size, float fontSize) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0099: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI component = new GameObject("Text", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }).GetComponent<TextMeshProUGUI>(); ((Transform)((TMP_Text)component).rectTransform).SetParent(parent, false); RectTransform rectTransform = ((TMP_Text)component).rectTransform; RectTransform rectTransform2 = ((TMP_Text)component).rectTransform; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); rectTransform2.anchorMax = val; rectTransform.anchorMin = val; ((TMP_Text)component).rectTransform.anchoredPosition = position; ((TMP_Text)component).rectTransform.sizeDelta = size; ((TMP_Text)component).font = _font; ((TMP_Text)component).fontSize = fontSize; ((TMP_Text)component).text = text; ((Graphic)component).color = Color.white; ((TMP_Text)component).alignment = (TextAlignmentOptions)514; ((TMP_Text)component).textWrappingMode = (TextWrappingModes)0; ((Graphic)component).raycastTarget = false; return (TMP_Text)(object)component; } private static RectTransform Button(Transform parent, string title, Vector2 position, Vector2 size, Action action) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Box(parent, "Button", position, size, new Color(0.3f, 0.24f, 0.13f)); Button obj = ((Component)val).gameObject.AddComponent<Button>(); ((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>(); ((UnityEvent)obj.onClick).AddListener((UnityAction)delegate { action(); }); if (!string.IsNullOrEmpty(title)) { Label((Transform)(object)val, title, Vector2.zero, size, 17f); } return val; } } internal static class AdminSpawnMenuController { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class ConnectionPatch { [HarmonyPostfix] private static void Postfix(ZNetPeer peer) { peer.m_rpc.Register<int>("ccorp_AdminSpawnMenuAccess", (Action<ZRpc, int>)ReceiveRequest); peer.m_rpc.Register<int, bool>("ccorp_AdminSpawnMenuAccessResult", (Action<ZRpc, int, bool>)ReceiveResponse); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class DisconnectPatch { [HarmonyPrefix] private static void Prefix() { Reset(); } } [HarmonyPatch(typeof(TextInput), "IsVisible")] private static class ModalPatch { [HarmonyPostfix] private static void Postfix(ref bool __result) { __result |= AdminSpawnMenu.IsOpen; } } [HarmonyPatch(typeof(Player), "TakeInput")] private static class InputPatch { [HarmonyPostfix] private static void Postfix(Player __instance, ref bool __result) { if (AdminSpawnMenu.IsOpen && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { __result = false; } } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] private static class CursorPatch { [HarmonyPrefix] private static bool Prefix() { if (!AdminSpawnMenu.IsOpen) { return true; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); return false; } } [HarmonyPatch(typeof(Menu), "Update")] private static class EscapePatch { [HarmonyPrefix] private static bool Prefix() { if (!AdminSpawnMenu.IsOpen) { return true; } if (Input.GetKeyDown((KeyCode)27)) { if (AdminSpawnMenu.HasQuantityPrompt) { AdminSpawnMenu.CancelQuantity(); } else { Reset(); } } return false; } } private const string AccessRequestRpc = "ccorp_AdminSpawnMenuAccess"; private const string AccessResponseRpc = "ccorp_AdminSpawnMenuAccessResult"; private static int _sequence; private static int _pending; private static float _deadline; private static Player _requestPlayer; private static Player _menuPlayer; private static void Message(string text) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } internal static void Update() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || (AdminSpawnMenu.IsOpen && (Object)(object)_menuPlayer != (Object)(object)localPlayer) || (_pending != 0 && (Object)(object)_requestPlayer != (Object)(object)localPlayer)) { Reset(); return; } if (_pending != 0 && Time.unscaledTime > _deadline) { _pending = 0; Message("Could not verify admin access. Try again."); } if (!Input.GetKeyDown((KeyCode)288)) { return; } if (AdminSpawnMenu.IsOpen || _pending != 0) { Reset(); } else { if (!CanOpen()) { return; } if (ZNet.instance.IsServer()) { if (LocalHostIsAdmin()) { Open(); } else { Message("You're not admin"); } return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer?.m_rpc != null) { _pending = ++_sequence; _requestPlayer = localPlayer; _deadline = Time.unscaledTime + 6f; serverPeer.m_rpc.Invoke("ccorp_AdminSpawnMenuAccess", new object[1] { _pending }); } } } private static bool CanOpen() { if ((Object)(object)Hud.instance != (Object)null && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && !Minimap.IsOpen() && !Hud.IsPieceSelectionVisible() && !UnifiedPopup.IsVisible()) { if (!((Object)(object)Chat.instance == (Object)null)) { return !Chat.instance.HasFocus(); } return true; } return false; } private static bool LocalHostIsAdmin() { return ZNet.instance.IsAdmin(((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref UserInfo.GetLocalUser().UserId)/*cast due to .constrained prefix*/).ToString()); } private static void Open() { _menuPlayer = Player.m_localPlayer; try { AdminSpawnMenu.Show(); } catch (Exception ex) { AdminSpawnMenu.Close(); Plugin.Log.LogError((object)("Failed to open admin spawn menu: " + ex)); Message("Could not open the spawn menu. Check the log."); } } private static void ReceiveRequest(ZRpc rpc, int request) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ((rpc != null) ? rpc.GetSocket() : null) != null) { string hostName = rpc.GetSocket().GetHostName(); bool flag = ZNet.instance.IsAdmin(hostName); if (!flag) { Plugin.Log.LogWarning((object)("Admin spawn menu denied for connection '" + hostName + "'.")); } rpc.Invoke("ccorp_AdminSpawnMenuAccessResult", new object[2] { request, flag }); } } private static void ReceiveResponse(ZRpc rpc, int request, bool allowed) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || _pending == 0 || request != _pending || Time.unscaledTime > _deadline || (Object)(object)_requestPlayer != (Object)(object)Player.m_localPlayer || (Object)(object)Player.m_localPlayer == (Object)null || ((rpc != null) ? rpc.GetSocket() : null) == null) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); object obj; if (serverPeer == null) { obj = null; } else { ZRpc rpc2 = serverPeer.m_rpc; obj = ((rpc2 != null) ? rpc2.GetSocket() : null); } ISocket val = (ISocket)obj; if (val != null && !(rpc.GetSocket().GetHostName() != val.GetHostName())) { _pending = 0; if (!allowed) { Message("You're not admin"); } else if (!((Character)Player.m_localPlayer).IsDead() && !((Character)Player.m_localPlayer).IsTeleporting() && CanOpen()) { Open(); } } } internal static bool RequestSpawn(string prefab, int amount) { if (!AdminSpawnMenu.IsOpen || (Object)(object)_menuPlayer != (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting() || (Object)(object)ZNetScene.instance == (Object)null || !AdminSpawnMenuInput.IsValid(prefab, amount)) { return false; } if (ZNet.instance.IsServer()) { if (!LocalHostIsAdmin()) { Reset(); Message("You're not admin"); return false; } Plugin.Log.LogWarning((object)$"Admin menu spawn authorized for local host: {prefab} x{amount}."); Plugin.MaterializeAdminSpawn(prefab, amount); return true; } if (ZNet.instance.GetServerPeer()?.m_rpc == null) { return false; } ZNet.instance.RemoteCommand($"ccorp_spawn {prefab} {amount}"); return true; } internal static void Reset() { _pending = 0; _requestPlayer = (_menuPlayer = null); if (AdminSpawnMenu.IsOpen) { AdminSpawnMenu.Close(); } } } internal static class AdminSpawnMenuInput { internal static bool TryAmount(string text, out int amount) { if (int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out amount)) { return amount > 0; } return false; } internal static bool IsValid(string prefab, int amount) { if (string.IsNullOrEmpty(prefab) || amount <= 0) { return false; } foreach (char c in prefab) { if (char.IsWhiteSpace(c) || char.IsControl(c) || c == ';') { return false; } } return true; } } internal static class AreaRepair { [HarmonyPatch(typeof(Player), "Repair")] private static class PlayerRepairPatch { private static void Postfix(Player __instance) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || RepairRadius == null || RepairRadius.Value <= 0f) { return; } Piece hoveringPiece = __instance.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null || !PrivateArea.CheckAccess(((Component)hoveringPiece).transform.position, 0f, true, false)) { return; } int num = 0; HashSet<WearNTear> hashSet = new HashSet<WearNTear>(); Collider[] array = Physics.OverlapSphere(((Component)hoveringPiece).transform.position, RepairRadius.Value, LayerMask.GetMask(new string[2] { "piece", "piece_nonsolid" })); for (int i = 0; i < array.Length; i++) { WearNTear componentInParent = ((Component)array[i]).GetComponentInParent<WearNTear>(); if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent)) { Piece component = ((Component)componentInParent).GetComponent<Piece>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component == (Object)(object)hoveringPiece) && CanRepair(__instance, component) && PrivateArea.CheckAccess(((Component)component).transform.position, 0f, true, false) && componentInParent.Repair()) { num++; component.m_placeEffect.Create(((Component)component).transform.position, ((Component)component).transform.rotation, (Transform)null, 1f, -1, ((Character)__instance).GetZDOID()); } } } if (num > 0) { ((Character)__instance).Message((MessageType)1, $"Estruturas próximas reparadas: {num}", 0, (Sprite)null, false); } } } private static readonly MethodInfo CheckCanRemovePiece = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, (Type[])null); private static ConfigEntry<float> RepairRadius; internal static void Initialize(ConfigFile config) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown RepairRadius = config.Bind<float>("Building", "RepairRadius", 3f, new ConfigDescription("Raio em metros que repara estruturas próximas ao usar o martelo. Use 0 para reparar somente a peça clicada.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); } private static bool CanRepair(Player player, Piece piece) { if (!(CheckCanRemovePiece == null)) { return (bool)CheckCanRemovePiece.Invoke(player, new object[1] { piece }); } return true; } } internal static class ChestAccess { [HarmonyPatch(typeof(Container), "Awake")] private static class RegisterPatch { [HarmonyPostfix] private static void Postfix(Container __instance) { ZNetView val = View.Invoke(__instance); if (!((Object)(object)val == (Object)null) && val.IsValid() && QuickStack.IsChest(__instance)) { val.Register<ZPackage>("ccorp_RequestChestAccess", (Action<long, ZPackage>)delegate(long sender, ZPackage package) { ReceiveRequest(__instance, sender, package); }); val.Register<ZPackage>("ccorp_ChestAccessResponse", (Action<long, ZPackage>)delegate(long sender, ZPackage package) { ReceiveResponse(__instance, sender, package); }); } } } [HarmonyPatch] private static class OpenReservationPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Container), "RPC_RequestOpen", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Container), "RPC_RequestStack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Container), "RPC_RequestTakeAll", (Type[])null, (Type[])null); } [HarmonyPrefix] private static bool Prefix(Container __instance, long uid, MethodBase __originalMethod) { ZNetView val = View.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner() || !ReservedForAnother(val.GetZDO(), uid)) { return true; } string text = ((__originalMethod.Name == "RPC_RequestStack") ? "RPC_StackResponse" : ((__originalMethod.Name == "RPC_RequestTakeAll") ? "RPC_TakeAllResponse" : "RPC_OpenResponse")); val.InvokeRPC(uid, text, new object[1] { false }); return false; } } private sealed class Request { internal Container Chest; internal int Token; internal long Owner; internal uint Revision; internal float NextRetry; internal ChestAccessStatus Status; } private sealed class Operation { internal Player Player; internal float Radius; internal float Deadline; internal Action<List<Container>, HashSet<Container>> Complete; internal readonly List<Request> Requests = new List<Request>(); } private const string RequestRpc = "ccorp_RequestChestAccess"; private const string ResponseRpc = "ccorp_ChestAccessResponse"; private const string LeaseOwner = "ccorp.chest.leaseOwner"; private const string LeaseToken = "ccorp.chest.leaseToken"; private const string LeaseExpiry = "ccorp.chest.leaseExpiry"; private const float Timeout = 4f; private const double LeaseSeconds = 8.0; private static readonly FieldRef<Container, ZNetView> View = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly Func<Container, bool> Load = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldRef<List<PrivateArea>> Wards = AccessTools.StaticFieldRefAccess<List<PrivateArea>>(AccessTools.Field(typeof(PrivateArea), "m_allAreas")); private static readonly Func<PrivateArea, bool> WardEnabled = AccessTools.MethodDelegate<Func<PrivateArea, bool>>(AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<PrivateArea, Vector3, float, bool> WardInside = AccessTools.MethodDelegate<Func<PrivateArea, Vector3, float, bool>>(AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<PrivateArea, long, bool> WardPermitted = AccessTools.MethodDelegate<Func<PrivateArea, long, bool>>(AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null), (object)null, true); private static Operation _operation; private static int _nextToken; internal static List<Container> PreparedChests { get; private set; } internal static bool Busy { get { if (_operation == null) { return PreparedChests != null; } return true; } } internal static bool IsInUse(Container chest) { if ((Object)(object)chest == (Object)null) { return false; } ZNetView val = View.Invoke(chest); bool localInUse = chest.IsInUse(); bool remoteOwner = (Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner(); int replicatedInUse; if (val == null) { replicatedInUse = 0; } else { ZDO zDO = val.GetZDO(); replicatedInUse = ((((zDO != null) ? new int?(zDO.GetInt(ZDOVars.s_inUse, 0)) : ((int?)null)) == 1) ? 1 : 0); } return ChestTransferRules.InUse(localInUse, remoteOwner, (byte)replicatedInUse != 0); } internal static bool CanMutate(Container chest) { if ((Object)(object)chest == (Object)null || IsInUse(chest)) { return false; } ZNetView val = View.Invoke(chest); if ((Object)(object)val != (Object)null && val.IsValid() && val.IsOwner()) { return !ReservedForAnother(val.GetZDO(), ZNet.GetUID()); } return false; } private static long NowTicks() { return ZNet.instance.GetTime().Ticks; } private static bool ReservedForAnother(ZDO zdo, long requester) { return ChestTransferRules.ReservedForAnother(zdo.GetLong("ccorp.chest.leaseOwner", 0L), zdo.GetLong("ccorp.chest.leaseExpiry", 0L), requester, NowTicks()); } private static void Reserve(ZDO zdo, long requester, int token) { zdo.Set("ccorp.chest.leaseOwner", requester); zdo.Set("ccorp.chest.leaseToken", token); zdo.Set("ccorp.chest.leaseExpiry", NowTicks() + 80000000); } internal static bool Begin(Player player, IEnumerable<Container> chests, float radius, Action<List<Container>, HashSet<Container>> complete) { if (Busy || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.instance == (Object)null) { return false; } Operation operation = (_operation = new Operation { Player = player, Radius = radius, Complete = complete, Deadline = Time.realtimeSinceStartup + 4f }); foreach (Container item in chests.Distinct().ToList()) { if ((Object)(object)item == (Object)null) { continue; } Request request = new Request { Chest = item, Token = ++_nextToken }; operation.Requests.Add(request); ZNetView val = View.Invoke(item); if ((Object)(object)val == (Object)null || !val.IsValid() || !QuickStack.CanAccessChest(item, player, radius)) { request.Status = ChestAccessStatus.Unavailable; } else if (IsInUse(item)) { request.Status = ChestAccessStatus.InUse; } else if (val.IsOwner()) { if (ReservedForAnother(val.GetZDO(), ZNet.GetUID())) { request.Status = ChestAccessStatus.InUse; continue; } Reserve(val.GetZDO(), ZNet.GetUID(), request.Token); Load(item); request.Status = ChestAccessStatus.Granted; } else { SendRequest(operation, request); } } Update(); return true; } private static void SendRequest(Operation operation, Request request) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) ZNetView val = View.Invoke(request.Chest); if ((Object)(object)val == (Object)null || !val.IsValid()) { request.Status = ChestAccessStatus.Unavailable; return; } request.Owner = val.GetZDO().GetOwner(); if (request.Owner == 0L) { request.Status = ChestAccessStatus.Unavailable; return; } request.NextRetry = Time.realtimeSinceStartup + 0.75f; ZPackage val2 = new ZPackage(); val2.Write(request.Token); val2.Write(((Character)operation.Player).GetZDOID()); val2.Write(operation.Player.GetPlayerID()); val2.Write(operation.Radius); val.InvokeRPC(request.Owner, "ccorp_RequestChestAccess", new object[1] { val2 }); } private static void ReceiveRequest(Container chest, long sender, ZPackage package) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Expected O, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) ZNetView val = View.Invoke(chest); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner()) { int num = package.ReadInt(); ZDOID val2 = package.ReadZDOID(); long num2 = package.ReadLong(); float num3 = package.ReadSingle(); ZDO zDO = val.GetZDO(); ChestAccessStatus chestAccessStatus = ChestAccessStatus.Unavailable; ZNetPeer val3 = (ZNet.instance.IsServer() ? ZNet.instance.GetPeer(sender) : null); ZDOID val4 = val3?.m_characterID ?? val2; ZDO zDO2 = ZDOMan.instance.GetZDO(val4); long num4 = val3?.m_playerID ?? num2; bool flag = ((!ZNet.instance.IsServer()) ? (zDO2 != null && zDO2.GetOwner() == sender && zDO2.GetLong(ZDOVars.s_playerID, 0L) == num4) : (val3 != null && zDO2 != null && num4 != 0)); if (zDO2 != null && flag && !float.IsNaN(num3) && num3 >= 1f && num3 <= 100f && QuickStack.IsChest(chest) && Vector3.Distance(zDO2.GetPosition(), ((Component)chest).transform.position) <= num3 && QuickStack.HasContainerAccess(chest, num4) && HasWardAccess(((Component)chest).transform.position, num4)) { chestAccessStatus = ((chest.IsInUse() || ReservedForAnother(zDO, sender)) ? ChestAccessStatus.InUse : ChestAccessStatus.Granted); } if (chestAccessStatus == ChestAccessStatus.Unavailable) { Plugin.Log.LogWarning((object)$"Chest access rejected for {((Object)chest).name}: sender={sender}, peerFound={val3 != null}, characterFound={zDO2 != null}, authenticated={flag}, claimedCharacterMatches={((ZDOID)(ref val2)).Equals(val4)}, claimedPlayerMatches={num2 == num4}, radius={num3:0.#}, distance={((zDO2 == null) ? (-1f) : Vector3.Distance(zDO2.GetPosition(), ((Component)chest).transform.position)):0.#}, containerAccess={QuickStack.HasContainerAccess(chest, num4)}, wardAccess={HasWardAccess(((Component)chest).transform.position, num4)}."); } if (chestAccessStatus == ChestAccessStatus.Granted) { Reserve(zDO, sender, num); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); zDO.SetOwner(sender); } ZPackage val5 = new ZPackage(); val5.Write(num); val5.Write((int)chestAccessStatus); val5.Write(zDO.DataRevision); val.InvokeRPC(sender, "ccorp_ChestAccessResponse", new object[1] { val5 }); } } private static bool HasWardAccess(Vector3 position, long playerId) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) bool flag = false; foreach (PrivateArea item in Wards.Invoke()) { if ((Object)(object)item == (Object)null || !WardEnabled(item) || !WardInside(item, position, 0f)) { continue; } flag = true; if (!WardPermitted(item, playerId)) { Piece component = ((Component)item).GetComponent<Piece>(); if (component == null || component.GetCreator() != playerId) { continue; } } return true; } return !flag; } private static void ReceiveResponse(Container chest, long sender, ZPackage package) { Operation operation = _operation; if (operation == null) { return; } int token = package.ReadInt(); Request request = operation.Requests.Find((Request r) => (Object)(object)r.Chest == (Object)(object)chest && r.Token == token && r.Owner == sender); if (request != null && request.Status == ChestAccessStatus.Waiting) { ChestAccessStatus chestAccessStatus = (ChestAccessStatus)package.ReadInt(); request.Revision = package.ReadUInt(); request.Status = chestAccessStatus switch { ChestAccessStatus.InUse => chestAccessStatus, ChestAccessStatus.Granted => ChestAccessStatus.Synchronizing, _ => ChestAccessStatus.Unavailable, }; if (request.Status == ChestAccessStatus.Unavailable) { Plugin.Log.LogWarning((object)$"Chest access denied by owner for {((Object)chest).name} (owner={sender})."); } } } internal static void Update() { Operation operation = _operation; if (operation == null) { return; } if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)operation.Player == (Object)null || (Object)(object)operation.Player != (Object)(object)Player.m_localPlayer || ((Character)operation.Player).IsDead() || ((Character)operation.Player).IsTeleporting()) { Reset(); return; } foreach (Request request in operation.Requests) { if (request.Status != ChestAccessStatus.Waiting && request.Status != ChestAccessStatus.Synchronizing) { continue; } if ((Object)(object)request.Chest == (Object)null) { request.Status = ChestAccessStatus.Unavailable; continue; } ZNetView val = View.Invoke(request.Chest); if ((Object)(object)val == (Object)null || !val.IsValid()) { request.Status = ChestAccessStatus.Unavailable; continue; } ZDO zDO = val.GetZDO(); if (request.Status == ChestAccessStatus.Synchronizing && val.IsOwner() && zDO.DataRevision >= request.Revision && zDO.GetInt("ccorp.chest.leaseToken", 0) == request.Token && zDO.GetLong("ccorp.chest.leaseOwner", 0L) == ZNet.GetUID()) { Load(request.Chest); request.Status = (CanMutate(request.Chest) ? ChestAccessStatus.Granted : ChestAccessStatus.InUse); } else if (Time.realtimeSinceStartup >= operation.Deadline) { request.Status = ChestAccessStatus.Unavailable; Plugin.Log.LogWarning((object)string.Format("Chest access timed out for {0} (owner={1}, phase={2}).", ((Object)request.Chest).name, request.Owner, (request.Revision == 0) ? "request" : "synchronization")); } else if (request.Status == ChestAccessStatus.Waiting && Time.realtimeSinceStartup >= request.NextRetry) { SendRequest(operation, request); } } if (operation.Requests.Any((Request r) => r.Status == ChestAccessStatus.Waiting || r.Status == ChestAccessStatus.Synchronizing)) { return; } List<Container> list = (from r in operation.Requests where r.Status == ChestAccessStatus.Granted && CanMutate(r.Chest) && QuickStack.CanAccessChest(r.Chest, operation.Player, operation.Radius) select r.Chest).ToList(); HashSet<Container> arg = new HashSet<Container>(from r in operation.Requests where r.Status == ChestAccessStatus.InUse select r.Chest); PreparedChests = list; try { operation.Complete(list, arg); } catch (Exception ex) { Logger.CreateLogSource("ccorp").LogError((object)("Chest transfer failed: " + ex)); } finally { PreparedChests = null; Release(operation); _operation = null; } } private static void Release(Operation operation) { foreach (Request request in operation.Requests) { if ((Object)(object)request.Chest == (Object)null) { continue; } ZNetView val = View.Invoke(request.Chest); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner()) { ZDO zDO = val.GetZDO(); if (zDO.GetLong("ccorp.chest.leaseOwner", 0L) == ZNet.GetUID() && zDO.GetInt("ccorp.chest.leaseToken", 0) == request.Token) { zDO.Set("ccorp.chest.leaseOwner", 0L); zDO.Set("ccorp.chest.leaseExpiry", 0L); } } } } internal static void Reset() { if (_operation != null && (Object)(object)ZNet.instance != (Object)null) { Release(_operation); } _operation = null; PreparedChests = null; } } internal enum ChestAccessStatus { Waiting, Synchronizing, Granted, InUse, Unavailable } internal static class ChestTransferRules { internal static bool InUse(bool localInUse, bool remoteOwner, bool replicatedInUse) { if (!localInUse) { return remoteOwner && replicatedInUse; } return true; } internal static bool ReservedForAnother(long holder, long expiry, long requester, long now) { if (holder != 0L && holder != requester) { return expiry > now; } return false; } internal static string PullMessage(string itemName, int moved, int requested, bool blocked) { if (blocked && moved < requested) { if (moved <= 0) { return "Chest in use."; } return $"Collected {moved}/{requested} {itemName}. Chest in use."; } if (moved <= 0) { return "No available ingredients or inventory space."; } return $"Collected {moved}/{requested} {itemName} from nearby chests."; } } internal sealed class ConnectedPlotSearch { internal readonly struct Cell : IEquatable<Cell> { internal readonly int X; internal readonly int Z; internal Cell(int x, int z) { X = x; Z = z; } public bool Equals(Cell other) { if (X == other.X) { return Z == other.Z; } return false; } public override bool Equals(object obj) { if (obj is Cell other) { return Equals(other); } return false; } public override int GetHashCode() { return (X * 397) ^ Z; } } private const int MaxVisitedCells = 100000; private readonly Queue<Cell> _pending = new Queue<Cell>(); private readonly HashSet<Cell> _visited = new HashSet<Cell>(); private readonly float _radiusSquared; private readonly int _stride; internal readonly float Step; internal bool Truncated { get; private set; } internal bool Complete => _pending.Count == 0; internal ConnectedPlotSearch(float radius, float spacing) { if (radius <= 0f || spacing <= 0f || float.IsNaN(radius) || float.IsNaN(spacing) || float.IsInfinity(radius) || float.IsInfinity(spacing)) { throw new ArgumentOutOfRangeException("radius"); } spacing = Math.Max(0.75f, spacing); _stride = (int)Math.Ceiling(spacing / 0.5f); Step = spacing / (float)_stride; _radiusSquared = radius * radius; Enqueue(new Cell(0, 0)); } private void Enqueue(Cell cell) { float num = (float)cell.X * Step; float num2 = (float)cell.Z * Step; if (!(num * num + num2 * num2 > _radiusSquared) && !_visited.Contains(cell)) { if (_visited.Count >= 100000) { Truncated = true; return; } _visited.Add(cell); _pending.Enqueue(cell); } } internal void Advance(int checks, Func<Cell, bool> isCultivated, Queue<Cell> candidates) { for (int i = 0; i < checks; i++) { if (_pending.Count <= 0) { break; } Cell cell = _pending.Dequeue(); if (isCultivated(cell)) { if ((cell.X != 0 || cell.Z != 0) && cell.X % _stride == 0 && cell.Z % _stride == 0) { candidates.Enqueue(cell); } Enqueue(new Cell(cell.X + 1, cell.Z)); Enqueue(new Cell(cell.X - 1, cell.Z)); Enqueue(new Cell(cell.X, cell.Z + 1)); Enqueue(new Cell(cell.X, cell.Z - 1)); } } } } internal static class CraftFromContainers { private sealed class PendingBuild { internal Player Player; internal Piece Piece; internal GameObject Ghost; internal Vector3 Position; internal Quaternion Rotation; internal Dictionary<string, int> Costs; internal float Deadline; } [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static class AuthorizeBuildPatch { [HarmonyPrefix] private static bool Prefix(Player __instance, bool takeInput) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if (_replayingBuild || !Enabled.Value || ShiftAutoPlant.InventoryOnly || !takeInput || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (!ZInput.GetButtonDown("Attack") && !ZInput.GetButtonDown("JoyPlace"))) { return true; } Piece val = SelectedPiece(__instance); GameObject val2 = PlacementGhost.Invoke(__instance); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || __instance.NoCostCheat() || NoPlacementCost.Invoke(__instance)) { return true; } Dictionary<string, int> dictionary = Costs(val.m_resources, 0, 1); if (dictionary.Count == 0 || CoversCosts(__instance, dictionary, Array.Empty<Container>())) { return true; } if (!ResourceChests(__instance, dictionary.Keys).Any()) { return true; } if (_pendingBuild != null) { return false; } _pendingBuild = new PendingBuild { Player = __instance, Piece = val, Ghost = val2, Position = val2.transform.position, Rotation = val2.transform.rotation, Costs = dictionary, Deadline = Time.realtimeSinceStartup + 10f }; if (!ChestAccess.Busy) { BeginPendingBuild(); } return false; } } [HarmonyPatch(typeof(ZInput), "GetButtonDown", new Type[] { typeof(string) })] private static class ReplayBuildInputPatch { [HarmonyPrefix] private static bool Prefix(string name, ref bool __result) { if (!_forcePlaceButton || name != "Attack") { return true; } _forcePlaceButton = false; __result = true; return false; } } [HarmonyPatch(typeof(BuildUi), "OnSelectPiece")] private static class BuildingResourcePullPatch { [HarmonyPrefix] private static bool Prefix(Piece piece) { if (!CtrlClickPull.Value || !IsResourcePullModifierHeld() || (Object)(object)piece == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return true; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { string text = val?.m_resItem?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text)) { int amount = val.GetAmount(0); if (amount > 0) { dictionary.TryGetValue(text, out var value); dictionary[text] = value + amount; } } } PullResources(Player.m_localPlayer, dictionary); return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private static class RequirementDisplayPatch { private static readonly HashSet<int> AdjustedTextInstances = new HashSet<int>(); [HarmonyPostfix] private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result) { //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: 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_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)elementRoot != (Object)null) { RequirementResourcePull requirementResourcePull = ((Component)elementRoot).GetComponent<RequirementResourcePull>(); if ((Object)(object)requirementResourcePull == (Object)null) { requirementResourcePull = ((Component)elementRoot).gameObject.AddComponent<RequirementResourcePull>(); } requirementResourcePull.Player = player; requirementResourcePull.ItemName = ((!__result) ? null : req?.m_resItem?.m_itemData?.m_shared?.m_name); requirementResourcePull.RequiredAmount = ((req != null) ? (req.GetAmount(quality) * craftMultiplier) : 0); Transform obj = elementRoot.Find("res_icon"); Graphic val = ((obj != null) ? ((Component)obj).GetComponent<Graphic>() : null); if ((Object)(object)val != (Object)null) { val.raycastTarget = true; } } if (!__result || (Object)(object)elementRoot == (Object)null || (Object)(object)req?.m_resItem == (Object)null) { return; } string itemName = req.m_resItem.m_itemData?.m_shared?.m_name; if (!TryGetDisplayedResourceCounts(player, itemName, out var inventoryCount, out var nearbyChestCount)) { return; } Transform val2 = elementRoot.Find("res_amount"); TMP_Text val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<TMP_Text>() : null); if (!((Object)(object)val3 == (Object)null)) { int num = req.GetAmount(quality) * craftMultiplier; val3.text = $"{inventoryCount} / {num}\n<size=85%>({nearbyChestCount})</size>"; if (AdjustedTextInstances.Add(((Object)val3).GetInstanceID())) { float num2 = (val3.fontSize *= 0.85f); val3.enableAutoSizing = true; val3.fontSizeMax = num2; val3.fontSizeMin = Mathf.Max(8f, num2 * 0.65f); RectTransform rectTransform = val3.rectTransform; Rect rect = rectTransform.rect; float height = ((Rect)(ref rect)).height; float num4 = Mathf.Max(height, num2 * 2.8f); rectTransform.SetSizeWithCurrentAnchors((Axis)1, num4); rectTransform.anchoredPosition -= new Vector2(0f, (num4 - height) * (1f - rectTransform.pivot.y)); rectTransform.anchoredPosition += new Vector2(0f, 2f); } val3.richText = true; val3.textWrappingMode = (TextWrappingModes)0; val3.overflowMode = (TextOverflowModes)0; val3.alignment = (TextAlignmentOptions)258; if (inventoryCount >= num) { ((Graphic)val3).color = Color.white; } else if (inventoryCount + nearbyChestCount >= num) { ((Graphic)val3).color = Color.yellow; } else { ((Graphic)val3).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : Color.white); } } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static class AuthorizeCraftPatch { private static readonly FieldRef<InventoryGui, Recipe> Recipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static readonly FieldRef<InventoryGui, ItemData> Upgrade = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem"); private static readonly FieldRef<InventoryGui, int> Variant = AccessTools.FieldRefAccess<InventoryGui, int>("m_craftVariant"); private static readonly FieldRef<InventoryGui, int> Amount = AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount"); private static readonly FieldRef<InventoryGui, bool> Multiple = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting"); private static readonly Action<InventoryGui, Player> Craft = AccessTools.MethodDelegate<Action<InventoryGui, Player>>(AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null), (object)null, true); [HarmonyPrefix] private static bool Prefix(InventoryGui __instance, Player player) { if (!Enabled.Value || ShiftAutoPlant.InventoryOnly || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)player == (Object)null || player.NoCostCheat() || ChestAccess.PreparedChests != null) { return true; } Recipe recipe = Recipe.Invoke(__instance); if ((Object)(object)recipe == (Object)null) { return true; } ItemData upgrade = Upgrade.Invoke(__instance); int upgradeQuality = upgrade?.m_quality ?? 0; int quality = upgradeQuality + 1; int variant = Variant.Invoke(__instance); int amount = Amount.Invoke(__instance); bool multiple = Multiple.Invoke(__instance); Dictionary<string, int> dictionary = Costs(recipe.m_resources, quality, (!multiple) ? 1 : amount); if (CoversCosts(player, dictionary, Array.Empty<Container>())) { return true; } if (ChestAccess.Busy) { ((Character)player).Message((MessageType)2, "Chest transfer in progress.", 0, (Sprite)null, false); return false; } int generation = _craftGeneration; CraftingStation station = player.GetCurrentCraftingStation(); ChestAccess.Begin(player, ResourceChests(player, dictionary.Keys), Radius.Value, delegate(List<Container> available, HashSet<Container> blocked) { if (!((Object)(object)__instance == (Object)null) && InventoryGui.IsVisible() && generation == _craftGeneration && !((Object)(object)Recipe.Invoke(__instance) != (Object)(object)recipe) && Upgrade.Invoke(__instance) == upgrade && (upgrade?.m_quality ?? 0) == upgradeQuality && Variant.Invoke(__instance) == variant && Amount.Invoke(__instance) == amount && Multiple.Invoke(__instance) == multiple && !((Object)(object)player.GetCurrentCraftingStation() != (Object)(object)station)) { _cacheExpiresAt = 0f; if (blocked.Count > 0 && !player.HaveRequirements(recipe, false, quality, (!multiple) ? 1 : amount)) { ((Character)player).Message((MessageType)2, "Chest in use.", 0, (Sprite)null, false); } Craft(__instance, player); } }); return false; } } [HarmonyPatch(typeof(InventoryGui), "OnCraftCancelPressed")] private static class CraftCancelPatch { [HarmonyPrefix] private static void Prefix() { _craftGeneration++; } } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static class RecipeRequirementPatch { [HarmonyPrefix] private static void Prefix(Player __instance, bool discover, out ResourceContext __state) { __state = _requirementContext; if (!discover) { _requirementContext = CreateContext(__instance); } } [HarmonyPostfix] private static void Postfix(ResourceContext __state) { _requirementContext = __state; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static class BuildingRequirementPatch { [HarmonyPrefix] private static void Prefix(Player __instance, Piece piece, RequirementMode mode, out ResourceContext __state) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) __state = _requirementContext; if ((int)mode != 1) { _requirementContext = CreateContext(__instance); } if ((int)mode != 0 || _requirementContext == null) { return; } List<Container> list = _requirementContext.Containers.Where(ChestAccess.CanMutate).ToList(); Dictionary<string, int> dictionary = Costs(piece.m_resources, 0, 1); if (_pendingBuild == null && !ChestAccess.Busy && Time.realtimeSinceStartup >= _nextBuildAccess && (Object)(object)SelectedPiece(__instance) == (Object)(object)piece && !CoversCosts(__instance, dictionary, list)) { _nextBuildAccess = Time.realtimeSinceStartup + 1f; ChestAccess.Begin(__instance, ResourceChests(__instance, dictionary.Keys), Radius.Value, delegate { _cacheExpiresAt = 0f; }); } _requirementContext = new ResourceContext(__instance, list); } [HarmonyPostfix] private static void Postfix(ResourceContext __state) { _requirementContext = __state; } } [HarmonyPatch(typeof(Inventory), "CountItems")] private static class CountNearbyResourcesPatch { [HarmonyPostfix] private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { if (!ShiftAutoPlant.InventoryOnly && _requirementContext != null && __instance == ((Humanoid)_requirementContext.Player).GetInventory()) { __result += CountInNearbyChests(name, quality, matchWorldLevel); } } } [HarmonyPatch(typeof(Inventory), "HaveItem", new Type[] { typeof(string), typeof(bool) })] private static class HaveNearbyResourcePatch { [HarmonyPostfix] private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { if (!ShiftAutoPlant.InventoryOnly && !__result && _requirementContext != null && __instance == ((Humanoid)_requirementContext.Player).GetInventory()) { __result = CountInNearbyChests(name, -1, matchWorldLevel) > 0; } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] private static class ConsumeNearbyResourcesPatch { [HarmonyPrefix] private static void Prefix(Player __instance, out ResourceContext __state) { __state = _consumptionContext; ResourceContext resourceContext = CreateContext(__instance); _consumptionContext = ((resourceContext == null) ? null : new ResourceContext(__instance, resourceContext.Containers.Where(ChestAccess.CanMutate).ToList())); } [HarmonyPostfix] private static void Postfix(ResourceContext __state) { _consumptionContext = __state; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] private static class ConsumeFromNearbyChestsPatch { [HarmonyPrefix] private static void Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased, out int __state) { __state = 0; if (!ShiftAutoPlant.InventoryOnly && _consumptionContext != null && __instance == ((Humanoid)_consumptionContext.Player).GetInventory()) { int num = __instance.CountItems(name, itemQuality, worldLevelBased); __state = Mathf.Max(0, amount - num); } } [HarmonyPostfix] private static void Postfix(string name, int itemQuality, bool worldLevelBased, int __state) { if (_consumptionContext == null || __state <= 0) { return; } int num = __state; foreach (Container container in _consumptionContext.Containers) { Inventory inventory = container.GetInventory(); if (inventory == null) { continue; } int num2 = Mathf.Min(inventory.CountItems(name, itemQuality, worldLevelBased), num); if (num2 > 0 && ChestAccess.CanMutate(container) && QuickStack.CanAccessChest(container, _consumptionContext.Player, Radius.Value)) { inventory.RemoveItem(name, num2, itemQuality, worldLevelBased); num -= num2; if (num <= 0) { break; } } } } } private sealed class ResourceContext { internal readonly Player Player; internal readonly List<Container> Containers; internal ResourceContext(Player player, List<Container> containers) { Player = player; Containers = containers; } } private static ConfigEntry<bool> Enabled; private static ConfigEntry<float> Radius; private static ConfigEntry<bool> CtrlClickPull; private static ResourceContext _requirementContext; private static ResourceContext _consumptionContext; private static Player _cachedPlayer; private static Vector3 _cachedPosition; private static float _cachedRadius; private static float _cacheExpiresAt; private static List<Container> _cachedContainers = new List<Container>(); private static float _nextBuildAccess; private static int _craftGeneration; private static PendingBuild _pendingBuild; private static bool _replayingBuild; private static bool _forcePlaceButton; private static readonly Func<Player, Piece> SelectedPiece = AccessTools.MethodDelegate<Func<Player, Piece>>(AccessTools.Method(typeof(Player), "GetSelectedPiece", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<Player, bool, float> UpdatePlacement = AccessTools.MethodDelegate<Action<Player, bool, float>>(AccessTools.Method(typeof(Player), "UpdatePlacement", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldRef<Player, GameObject> PlacementGhost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); private static readonly FieldRef<Player, bool> NoPlacementCost = AccessTools.FieldRefAccess<Player, bool>("m_noPlacementCost"); internal static void Reset() { _requirementContext = null; _consumptionContext = null; _cachedPlayer = null; _cachedContainers.Clear(); _cacheExpiresAt = (_nextBuildAccess = 0f); _craftGeneration++; _pendingBuild = null; _replayingBuild = (_forcePlaceButton = false); } internal static void Update() { if (_pendingBuild != null && !ChestAccess.Busy) { BeginPendingBuild(); } } private static bool BuildTargetUnchanged(PendingBuild pending) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (pending == null || (Object)(object)pending.Player == (Object)null || (Object)(object)pending.Player != (Object)(object)Player.m_localPlayer || ((Character)pending.Player).IsDead() || ((Character)pending.Player).IsTeleporting() || (Object)(object)SelectedPiece(pending.Player) != (Object)(object)pending.Piece || Time.realtimeSinceStartup > pending.Deadline) { return false; } GameObject val = PlacementGhost.Invoke(pending.Player); if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)pending.Ghost && Vector3.Distance(val.transform.position, pending.Position) < 0.2f) { return Quaternion.Angle(val.transform.rotation, pending.Rotation) < 2f; } return false; } private static void BeginPendingBuild() { PendingBuild pending = _pendingBuild; if (!BuildTargetUnchanged(pending)) { _pendingBuild = null; } else if (!ChestAccess.Begin(pending.Player, ResourceChests(pending.Player, pending.Costs.Keys), Radius.Value, delegate(List<Container> available, HashSet<Container> blocked) { if (_pendingBuild == pending) { _pendingBuild = null; _cacheExpiresAt = 0f; if (BuildTargetUnchanged(pending)) { if (CoversCosts(pending.Player, pending.Costs, available)) { _replayingBuild = (_forcePlaceButton = true); try { UpdatePlacement(pending.Player, arg2: true, Time.deltaTime); return; } finally { _replayingBuild = (_forcePlaceButton = false); } } Plugin.Log.LogWarning((object)string.Format("Build chest stock unavailable: piece={0}, authorized={1}, inUse={2}, requirements={3}.", ((Object)pending.Piece).name, available.Count, blocked.Count, string.Join(", ", pending.Costs.Select((KeyValuePair<string, int> cost) => $"{cost.Key}:{cost.Value}")))); ((Character)pending.Player).Message((MessageType)2, (blocked.Count > 0) ? "Chest in use." : "Nearby chest resources are unavailable.", 0, (Sprite)null, false); } } })) { _pendingBuild = null; } } private static Dictionary<string, int> Costs(Requirement[] requirements, int quality, int multiplier) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Requirement val in requirements) { string text = val?.m_resItem?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text)) { int num = val.GetAmount(quality) * multiplier; if (num > 0) { dictionary.TryGetValue(text, out var value); dictionary[text] = value + num; } } } return dictionary; } private static bool CoversCosts(Player player, Dictionary<string, int> costs, IEnumerable<Container> chests) { ResourceContext requirementContext = _requirementContext; _requirementContext = null; try { return costs.All((KeyValuePair<string, int> cost) => ((Humanoid)player).GetInventory().CountItems(cost.Key, -1, true) + chests.Where((Container chest) => ChestAccess.CanMutate(chest) && QuickStack.CanAccessChest(chest, player, Radius.Value)).Sum((Container chest) => chest.GetInventory().CountItems(cost.Key, -1, true)) >= cost.Value); } finally { _requirementContext = requirementContext; } } internal static void Initialize(ConfigFile config) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown ConfigEntry<bool> val = config.Bind<bool>("Crafting", "ShiftClickPullResources", true, (ConfigDescription)null); CtrlClickPull = config.Bind<bool>("Crafting", "CtrlClickPullResources", val.Value, "Ctrl + clique esquerdo no ingrediente da bancada traz a quantidade completa do custo exibido, independente do estoque no inventário. No menu de construção, Ctrl + clique na peça traz todos os ingredientes para construir uma unidade, independente do estoque no inventário. Se houver menos, traz o disponível. Respeita NearbyChestRadius, acesso, baús em uso e espaço. Não produz/constrói automaticamente. Sincronizado e bloqueado pelo servidor."); ConfigRemoveLegacyPull(config, val); Enabled = config.Bind<bool>("Crafting", "UseNearbyChestResources", true, "Permite construir, fabricar e melhorar itens usando recursos de baús próximos depois dos recursos do inventário."); Radius = config.Bind<float>("Crafting", "NearbyChestRadius", 25f, new ConfigDescription("Raio em metros usado para localizar baús cujos recursos podem ser usados na construção e em todas as estações.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); } private static void ConfigRemoveLegacyPull(ConfigFile config, ConfigEntry<bool> oldPull) { config.Remove(((ConfigEntryBase)oldPull).Definition); config.Save(); } internal static bool IsResourcePullModifierHeld() { if (!Input.GetKey((KeyCode)306)) { return Input.GetKey((KeyCode)305); } return true; } private static ResourceContext CreateContext(Player player) { if (!Enabled.Value || ShiftAutoPlant.InventoryOnly || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return null; } return new ResourceContext(player, GetNearbyContainers(player)); } internal static void PullResources(Player player, string itemName, int requiredAmount) { PullResources(player, new Dictionary<string, int> { [itemName] = requiredAmount }); } private static bool CanPull(Player player) { if (CtrlClickPull.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible()) { if (!((Object)(object)Chat.instance == (Object)null)) { return !Chat.instance.HasFocus(); } return true; } return false; } private static IEnumerable<Container> ResourceChests(Player player, IEnumerable<string> names) { HashSet<string> requestedNames = new HashSet<string>(names); return from chest in QuickStack.FindEligibleChests(player, Radius.Value, includeInUse: true) where chest.GetInventory() != null && chest.GetInventory().GetAllItems().Any((ItemData item) => item != null && item.m_worldLevel >= Game.m_worldLevel && requestedNames.Contains(item.m_shared.m_name)) orderby Vector3.Distance(((Component)player).transform.position, ((Component)chest).transform.position) select chest; } private static void PullResources(Player player, Dictionary<string, int> costs) { if (!CanPull(player) || ChestAccess.Busy) { return; } Dictionary<string, int> requested = costs.Where((KeyValuePair<string, int> cost) => !string.IsNullOrEmpty(cost.Key) && cost.Value > 0).ToDictionary((KeyValuePair<string, int> cost) => cost.Key, (KeyValuePair<string, int> cost) => ResourcePullTransfer.Requested(cost.Value)); if (requested.Count == 0) { return; } ChestAccess.Begin(player, ResourceChests(player, requested.Keys), Radius.Value, delegate(List<Container> chests, HashSet<Container> blocked) { if (CanPull(player)) { List<string> list = new List<string>(); foreach (KeyValuePair<string, int> cost in requested) { int num = chests.Where((Container chest) => ChestAccess.CanMutate(chest) && QuickStack.CanAccessChest(chest, player, Radius.Value)).Sum((Container chest) => (from item in chest.GetInventory().GetAllItems() where item != null && item.m_shared.m_name == cost.Key && item.m_worldLevel >= Game.m_worldLevel select item).Sum((ItemData item) => item.m_stack)); int num2 = TransferResources(player, cost.Key, cost.Value, chests); bool blocked2 = num2 < cost.Value && num < cost.Value && blocked.Any(delegate(Container chest) { if ((Object)(object)chest != (Object)null) { Inventory inventory = chest.GetInventory(); if (inventory == null) { return false; } return inventory.GetAllItems().Any((ItemData item) => item != null && item.m_shared.m_name == cost.Key && item.m_worldLevel >= Game.m_worldLevel); } return false; }); list.Add(ChestTransferRules.PullMessage(Localization.instance.Localize(cost.Key), num2, cost.Value, blocked2)); } _cacheExpiresAt = 0f; ((Character)player).Message((MessageType)2, string.Join("\n", list), 0, (Sprite)null, false); } }); } private static int TransferResources(Player player, string itemName, int requiredAmount, IEnumerable<Container> chests) { Inventory destination = ((Humanoid)player).GetInventory(); if (destination == null) { return 0; } ResourceContext requirementContext = _requirementContext; ResourceContext consumptionContext = _consumptionContext; _requirementContext = null; _consumptionContext = null; int num = 0; try { int num2 = requiredAmount; foreach (Container chest in chests) { if (!ChestAccess.CanMutate(chest) || !QuickStack.CanAccessChest(chest, player, Radius.Value)) { continue; } Inventory source = chest.GetInventory(); if (source == null || source == destination) { continue; } foreach (ItemData item in new List<ItemData>(source.GetAllItems())) { if (num2 <= 0) { break; } if (item != null && !(item.m_shared.m_name != itemName) && item.m_worldLevel >= Game.m_worldLevel && source.ContainsItem(item)) { int num3 = ResourcePullTransfer.Move(item, Mathf.Min(num2, item.m_stack), delegate(ItemData original, int amount) { ItemData obj = original.Clone(); obj.m_stack = amount; return obj; }, (ItemData original) => destination.CountItems(itemName, original.m_quality, true), delegate(ItemData copy) { destination.AddItem(copy); }, delegate(ItemData original, int amount) { source.RemoveItem(original, amount); }); num2 -= num3; num += num3; } } if (num2 <= 0) { break; } } return num; } finally { _requirementContext = requirementContext; _consumptionContext = consumptionContext; } } private static List<Container> GetNearbyContainers(Player player) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) if (ChestAccess.PreparedChests != null) { return ChestAccess.PreparedChests; } float value = Radius.Value; Vector3 position = ((Component)player).transform.position; if ((Object)(object)_cachedPlayer == (Object)(object)player && Time.unscaledTime < _cacheExpiresAt && Mathf.Approximately(_cachedRadius, value) && Vector3.Distance(_cachedPosition, position) < 0.25f) { return _cachedContainers; } _cachedPlayer = player; _cachedPosition = position; _cachedRadius = value; _cacheExpiresAt = Time.unscaledTime + 0.25f; _cachedContainers = (from container in QuickStack.FindEligibleChests(player, value) orderby Vector3.Distance(position, ((Component)container).transform.position) select container).ToList(); return _cachedContainers; } private static int CountInNearbyChests(string itemName, int quality, bool matchWorldLevel) { if (_requirementContext == null || string.IsNullOrEmpty(itemName)) { return 0; } int num = 0; foreach (Container container in _requirementContext.Containers) { if (!((Object)(object)container == (Object)null) && !ChestAccess.IsInUse(container) && QuickStack.CanAccessChest(container, _requirementContext.Player, Radius.Value)) { Inventory inventory = container.GetInventory(); if (inventory != null) { num += inventory.CountItems(itemName, quality, matchWorldLevel); } } } return num; } private static bool TryGetDisplayedResourceCounts(Player player, string itemName, out int inventoryCount, out int nearbyChestCount) { inventoryCount = 0; nearbyChestCount = 0; if (!Enabled.Value || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || string.IsNullOrEmpty(itemName)) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } inventoryCount = inventory.CountItems(itemName, -1, true); foreach (Container nearbyContainer in GetNearbyContainers(player)) { Inventory inventory2 = nearbyContainer.GetInventory(); if (inventory2 != null) { nearbyChestCount += inventory2.CountItems(itemName, -1, true); } } return true; } } internal static class DynamicFlattenRadius { [HarmonyPatch(typeof(Player), "PlacePiece")] private static class PlacementScopePatch { [HarmonyPrefix] private static void Prefix(Player __instance, Piece piece, out PlacementState __state) { __state = null; if (Enabled != null && Enabled.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)piece == (Object)null) && !((Object)(object)piece != (Object)(object)_selectedPiece) && !(_currentRadius <= 0f)) { __state = new PlacementState(piece); __state.Apply(_currentRadius); } } [HarmonyPostfix] private static void Postfix(PlacementState __state) { __state?.Restore(); } [HarmonyFinalizer] private static void Finalizer(PlacementState __state) { __state?.Restore(); } } private sealed class PlacementState { private readonly TerrainOp _terrainOp; private readonly TerrainModifier _modifier; private readonly float _levelRadius; private readonly float _raiseRadius; private readonly float _smoothRadius; private readonly float _paintRadius; private bool _restored; internal PlacementState(Piece piece) { _terrainOp = ((Component)piece).GetComponent<TerrainOp>(); _modifier = ((Component)piece).GetComponent<TerrainModifier>(); if ((Object)(object)_terrainOp != (Object)null && _terrainOp.m_settings != null) { _levelRadius = _terrainOp.m_settings.m_levelRadius; _raiseRadius = _terrainOp.m_settings.m_raiseRadius; _smoothRadius = _terrainOp.m_settings.m_smoothRadius; _paintRadius = _terrainOp.m_settings.m_paintRadius; } else if ((Object)(object)_modifier != (Object)null) { _levelRadius = _modifier.m_levelRadius; _smoothRadius = _modifier.m_smoothRadius; _paintRadius = _modifier.m_paintRadius; } } internal void Apply(float radius) { if ((Object)(object)_terrainOp != (Object)null) { DynamicFlattenRadius.Apply(_terrainOp.m_settings, radius); } if ((Object)(object)_modifier != (Object)null) { DynamicFlattenRadius.Apply(_modifier, radius); } } internal void Restore() { if (!_restored) { _restored = true; if ((Object)(object)_terrainOp != (Object)null && _terrainOp.m_settings != null) { _terrainOp.m_settings.m_levelRadius = _levelRadius; _terrainOp.m_settings.m_raiseRadius = _raiseRadius; _terrainOp.m_settings.m_smoothRadius = _smoothRadius; _terrainOp.m_settings.m_paintRadius = _paintRadius; } if ((Object)(object)_modifier != (Object)null) { _modifier.m_levelRadius = _levelRadius; _modifier.m_smoothRadius = _smoothRadius; _modifier.m_paintRadius = _paintRadius; } } } } private static readonly FieldRef<Player, GameObject> PlacementGhost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); private static ConfigEntry<bool> Enabled; private static ConfigEntry<float> MaximumRadius; private static Piece _selectedPiece; private static float _originalRadius; private static float _currentRadius; private static float _scroll; internal static void Initialize(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Enabled = config.Bind<bool>("Terrain", "DynamicFlattenRadius", true, "Permite ajustar com Ctrl + roda do mouse o raio de Terraplanar, Cultivar, colocar grama e pavimentar com pedra. Trocar de função, ferramenta ou desconectar restaura o raio original. Sincronizado e bloqueado pelo servidor."); MaximumRadius = config.Bind<float>("Terrain", "MaximumFlattenRadius", 10f, new ConfigDescription("Raio máximo, em metros, permitido para as ações de terreno compatíveis com Ctrl + roda do mouse. Cada passo altera 0,5 m. Sincronizado e bloqueado pelo servidor.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 25f), Array.Empty<object>())); } internal static void Reset() { _selectedPiece = null; _originalRadius = 0f; _currentRadius = 0f; _scroll = 0f; } internal static void Update() { Player localPlayer = Player.m_localPlayer; Piece val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetSelectedPiece() : null); if (Enabled == null || !Enabled.Value || (Object)(object)val == (Object)null || (Object)(object)PlacementGhost.Invoke(localPlayer) == (Object)null || !FlattenRadiusRules.IsSupportedTerrainAction(Utils.GetPrefabName(((Component)val).gameObject))) { ResetSelection(); return; } if ((Object)(object)_selectedPiece != (Object)(object)val) { _selectedPiece = val; _originalRadius = GetOriginalRadius(val); _currentRadius = _originalRadius; _scroll = 0f; } ApplyPreview(localPlayer); if (!ControlHeld() || IsUiBlocking()) { _scroll = 0f; return; } _scroll += ZInput.GetMouseScrollWheel(); if (!(Mathf.Abs(_scroll) < 0.1f)) { int direction = ((_scroll > 0f) ? 1 : (-1)); _scroll = 0f; float num = FlattenRadiusRules.Adjust(_currentRadius, _originalRadius, MaximumRadius.Value, direction); if (!Mathf.Approximately(num, _currentRadius)) { _currentRadius = num; ApplyPreview(localPlayer); ((Character)localPlayer).Message((MessageType)2, $"Raio de {FlattenRadiusRules.ActionName(Utils.GetPrefabName(((Component)val).gameObject))}: {_currentRadius:0.0} m", 0, (Sprite)null, false); } } } private static void ResetSelection() { _selectedPiece = null; _originalRadius = 0f; _currentRadius = 0f; _scroll = 0f; } private static float GetOriginalRadius(Piece piece) { TerrainOp component = ((Component)piece).GetComponent<TerrainOp>(); if ((Object)(object)component != (Object)null) { return component.GetRadius(); } TerrainModifier component2 = ((Component)piece).GetComponent<TerrainModifier>(); if (!((Object)(object)component2 != (Object)null)) { return 3f; } return component2.GetRadius(); } private static void ApplyPreview(Player player) { GameObject val = PlacementGhost.Invoke(player); if (!((Object)(object)val == (Object)null) && FlattenRadiusRules.IsSupportedTerrainAction(Utils.GetPrefabName(val))) { TerrainOp component = val.GetComponent<TerrainOp>(); if ((Object)(object)component != (Object)null) { Apply(component.m_settings, _currentRadius); } CircleProjector[] componentsInChildren = val.GetComponentsInChildren<CircleProjector>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].m_radius = _currentRadius; } } } private static void Apply(Settings settings, float radius) { if (settings != null) { if (settings.m_level) { settings.m_levelRadius = radius; } if (settings.m_raise) { settings.m_raiseRadius = radius; } if (settings.m_smooth) { settings.m_smoothRadius = radius; } if (settings.m_paintCleared) { settings.m_paintRadius = radius; } } } private static void Apply(TerrainModifier modifier, float radius) { if (modifier.m_level) { modifier.m_levelRadius = radius; } if (modifier.m_smooth) { modifier.m_smoothRadius = radius; } if (modifier.m_paintCleared) { modifier.m_paintRadius = radius; } } private static bool ControlHeld() { if (!Input.GetKey((KeyCode)306)) { return Input.GetKey((KeyCode)305); } return true; } private static bool IsUiBlocking() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 if (!Hud.IsPieceSelectionVisible() && !InventoryGui.IsVisible() && !Menu.IsActive() && !Console.IsVisible() && !TextInput.IsVisible() && (!((Object)(object)Minimap.instance != (Object)null) || (int)Minimap.instance.m_mode != 2)) { if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.HasFocus(); } return false; } return true; } } internal static class EquipmentUpgrades { [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class CopyDatabasePatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance) { Apply(__instance); } } [HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")] private static class RequiredLevelPatch { [HarmonyPostfix] private static void Postfix(Recipe __instance, int quality, ref int __result) { SharedData val = __instance.m_item?.m_itemData?.m_shared; if (ExtraLevels != null && ExtraLevels.Value != 0 && val != null && OriginalLimits.TryGetValue(val, out var value) && quality > value && quality <= val.m_maxQuality) { CraftingStation requiredStation = __instance.GetRequiredStation(quality); if ((Object)(object)requiredStation != (Object)null && !requiredStation.m_upgrader && StationMaxima.TryGetValue(requiredStation.m_name, out var value2)) { __result = value2; } } } } private static ConfigEntry<int> ExtraLevels; private static readonly Dictionary<SharedData, int> OriginalLimits = new Dictionary<SharedData, int>(); private static readonly Dictionary<string, int> StationMaxima = new Dictionary<string, int>(); internal static void Initialize(ConfigFile config) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown ExtraLevels = config.Bind<int>("Equipment", "ExtraUpgradeLevels", 2, new ConfigDescription("Níveis extras para armas, escudos e armaduras melhoráveis. 2 aumenta um limite original de 4 para 6; 0 preserva original. Os níveis extras exigem a estação com todas as melhorias disponíveis no catálogo de construção. Custos e atributos seguem as fórmulas nativas. Não reduz a qualidade de itens existentes. Sincronizado e bloqueado pelo servidor.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())); ExtraLevels.SettingChanged += OnChanged; } private static void OnChanged(object sender, EventArgs args) { Apply(ObjectDB.instance); } private static bool IsEquipment(ItemType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected I4, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 switch (type - 3) { default: if ((int)type != 22) { break; } goto case 0; case 0: case 1: case 2: case 3: case 4: case 8: case 9: case 11: case 14: return true; case 5: case 6: case 7: case 10: case 12: case 13: break; } return false; } internal static void Apply(ObjectDB db) { //IL_0231: Unknown result type (might be due to invalid IL or missing references) if (db?.m_items == null || ExtraLevels == null) { return; } Dictionary<string, HashSet<string>> dictionary = new Dictionary<string, HashSet<string>>(); HashSet<string> hashSet = new HashSet<string>(); HashSet<PieceTable> hashSet2 = new HashSet<PieceTable>(); foreach (GameObject item in db.m_items) { PieceTable val = ((!((Object)(object)item != (Object)null)) ? null : item.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); if ((Object)(object)val == (Object)null || !hashSet2.Add(val)) { continue; } foreach (GameObject piece in val.m_pieces) { if ((Object)(object)piece == (Object)null) { continue; } StationExtension component = piece.GetComponent<StationExtension>(); Piece component2 = piece.GetComponent<Piece>(); if (!((Object)(object)component?.m_craftingStation == (Object)null) && !((Object)(object)component2 == (Object)null) && component2.m_enabled) { string name = component.m_craftingStation.m_name; if (component.m_stack) { hashSet.Add(name); } if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = new HashSet<string>()); } value.Add(component2.m_name); } } } StationMaxima.Clear(); foreach (KeyValuePair<string, HashSet<string>> item2 in dictionary) { if (!hashSet.Contains(item2.Key)) { StationMaxima[item2.Key] = 1 + item2.Value.Count; } } HashSet<SharedData> hashSet4 = new HashSet<SharedData>(); foreach (Recipe recipe in db.m_recipes) { SharedData val2 = recipe?.m_item?.m_itemData?.m_shared; if (val2 != null && IsEquipment(val2.m_itemType)) { if (!OriginalLimits.TryGetValue(val2, out var value2)) { value2 = (OriginalLimits[val2] = val2.m_maxQuality); } CraftingStation requiredStation = recipe.GetRequiredStation(value2 + 1); if (value2 > 1 && (Object)(object)requiredStation != (Object)null && !requiredStation.m_upgrader && StationMaxima.ContainsKey(requiredStation.m_name)) { hashSet4.Add(va