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 RustyHeathensQoL v1.0.1
RustyHeathensQoL.dll
Decompiled 3 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.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using RustyHeathens.Automation; using RustyHeathens.Backpacks; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Rusty Heathens QoL")] [assembly: AssemblyDescription("Heathens' Haven quality-of-life features")] [assembly: AssemblyCompany("RustyLaserGaming")] [assembly: AssemblyProduct("Rusty Heathens QoL")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyVersion("1.0.1.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 RustyHeathens.Automation { internal static class GroundStoreRules { internal static bool IsEligible(bool isPiece, int maxStackSize, bool isConsumable) { if (!isPiece && maxStackSize > 0) { if (!isConsumable) { return maxStackSize > 1; } return true; } return false; } } internal static class LiveAutoStore { private sealed class Request { internal ZDOID Drop; internal int Token; internal long Deadline; internal float Range; internal float NextAttempt; internal string Item = "unknown"; internal string LastWait = "not_attempted"; internal readonly List<ZDOID> Chests = new List<ZDOID>(); internal Action<string> Log; internal Action<ZPackage> Report; } internal const string ReadyRpc = "RHSQOL_StoreReady_v3"; internal const string JobRpc = "RHSQOL_StoreJob_v3"; internal const string ResultRpc = "RHSQOL_StoreResult_v3"; private static readonly Dictionary<ZDOID, Request> Pending = new Dictionary<ZDOID, Request>(); private static readonly Dictionary<ZDOID, int> Seen = new Dictionary<ZDOID, int>(); private static readonly MethodInfo LoadDrop = AccessTools.Method(typeof(ItemDrop), "Load", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo LoadChest = AccessTools.Method(typeof(Container), "CheckForChanges", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo RequestOwn = AccessTools.Method(typeof(ItemDrop), "RequestOwn", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo ChestAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); private static bool paused; private static long Now { get { if (!((Object)(object)ZNet.instance == (Object)null)) { return ZNet.instance.GetTime().Ticks; } return 0L; } } internal static void Clear() { Pending.Clear(); Seen.Clear(); paused = false; } private static ZNetView View(GameObject obj) { if (!((Object)(object)obj == (Object)null)) { return obj.GetComponent<ZNetView>(); } return null; } private static GameObject Instance(ZDOID id) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNetScene.instance == (Object)null)) { return ZNetScene.instance.FindInstance(id); } return null; } internal static void Handle(ZPackage pkg, Action<string> log, Action<ZPackage> report) { //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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) if (pkg == null || paused || (Object)(object)ZNet.instance == (Object)null) { return; } pkg.SetPos(0); Request request = new Request(); request.Drop = pkg.ReadZDOID(); request.Token = pkg.ReadInt(); request.Deadline = pkg.ReadLong(); request.Range = pkg.ReadSingle(); int num = pkg.ReadInt(); if (request.Token > 0 && !((ZDOID)(ref request.Drop)).IsNone() && num > 0 && num <= 64 && !(request.Range <= 0f) && !(request.Range > 64f) && StoreLease.IsLive(Now, request.Deadline) && (!Seen.TryGetValue(request.Drop, out var value) || value < request.Token) && (!Pending.TryGetValue(request.Drop, out var value2) || !StoreLease.IsLive(Now, value2.Deadline))) { for (int i = 0; i < num; i++) { request.Chests.Add(pkg.ReadZDOID()); } request.Log = log; request.Report = report; if (Seen.Count > 4096 && Pending.Count == 0) { Seen.Clear(); } Seen[request.Drop] = request.Token; Pending[request.Drop] = request; Tick(); } } private unsafe static void Finish(Request request, string status, int amount, ZDOID chest) { //IL_0006: 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_007e: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Pending.Remove(request.Drop); if (status != "stored" && request.Log != null) { Action<string> log = request.Log; string[] obj = new string[6] { "RESULT drop=", null, null, null, null, null }; ZDOID drop = request.Drop; obj[1] = ((object)(*(ZDOID*)(&drop))/*cast due to .constrained prefix*/).ToString(); obj[2] = " item="; obj[3] = request.Item; obj[4] = " reason="; obj[5] = status; log(string.Concat(obj)); } ZPackage val = new ZPackage(); val.Write(request.Drop); val.Write(request.Token); val.Write(status); val.Write(amount); val.Write(chest); if (request.Report != null) { request.Report(val); } } internal unsafe static void Tick() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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) if (paused || Pending.Count == 0) { return; } foreach (Request item in new List<Request>(Pending.Values)) { if (!StoreLease.IsLive(Now, item.Deadline)) { Finish(item, "expired:" + item.LastWait, 0, ZDOID.None); } else if (!(Time.realtimeSinceStartup < item.NextAttempt)) { item.NextAttempt = Time.realtimeSinceStartup + 0.25f; try { TryStore(item); } catch (Exception ex) { paused = true; Action<string> log = item.Log; ZDOID drop = item.Drop; log("AUTOSTORE PAUSED drop=" + ((object)(*(ZDOID*)(&drop))/*cast due to .constrained prefix*/).ToString() + ": " + ex); Finish(item, "paused", 0, ZDOID.None); Pending.Clear(); break; } } } } private static string AccessBlock(Container chest) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 //IL_0091: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((int)chest.m_privacy == 0) { if ((Object)(object)localPlayer == (Object)null) { return "private_no_local_player"; } if (ChestAccess == null) { return "private_access_api_missing"; } if (!(bool)ChestAccess.Invoke(chest, new object[1] { localPlayer.GetPlayerID() })) { return "private_access_denied"; } } else if ((int)chest.m_privacy != 1 && (int)chest.m_privacy != 2) { return "unknown_privacy"; } if (chest.m_checkGuardStone) { if ((Object)(object)localPlayer == (Object)null) { return "ward_no_local_player"; } if (!PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, false, false)) { return "ward_denied"; } } return null; } private static void Count(SortedDictionary<string, int> reasons, string reason) { reasons.TryGetValue(reason, out var value); reasons[reason] = value + 1; } private static string Describe(SortedDictionary<string, int> reasons) { List<string> list = new List<string>(); foreach (KeyValuePair<string, int> reason in reasons) { list.Add(reason.Key + "=" + reason.Value); } return string.Join(",", list.ToArray()); } private unsafe static void TryStore(Request request) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Invalid comparison between Unknown and I4 //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { request.LastWait = "local_player_loading"; return; } GameObject val = Instance(request.Drop); ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>()); ZNetView val3 = View(val); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || !val3.IsValid()) { request.LastWait = "drop_not_loaded"; return; } if (LoadDrop == null || LoadChest == null || RequestOwn == null) { throw new InvalidOperationException("Vanilla load/ownership API unavailable."); } LoadDrop.Invoke(val2, null); ItemData itemData = val2.m_itemData; if (itemData == null || itemData.m_shared == null) { request.LastWait = "drop_data_unavailable"; return; } request.Item = itemData.m_shared.m_name; if (itemData.m_stack <= 0) { Finish(request, "gone", 0, ZDOID.None); return; } if (!GroundStoreRules.IsEligible(val3.GetZDO().GetBool(ZDOVars.s_piece, false), itemData.m_shared.m_maxStackSize, (int)itemData.m_shared.m_itemType == 2)) { Finish(request, "excluded", 0, ZDOID.None); return; } ZDOID val4 = ZDOID.None; float num = request.Range * request.Range; bool flag = false; SortedDictionary<string, int> reasons = new SortedDictionary<string, int>(StringComparer.Ordinal); foreach (ZDOID chest in request.Chests) { GameObject val5 = Instance(chest); if ((Object)(object)val5 == (Object)null) { flag = true; Count(reasons, "chest_not_loaded"); continue; } Container component = val5.GetComponent<Container>(); ZNetView val6 = View(val5); if ((Object)(object)component == (Object)null) { Count(reasons, "container_missing"); continue; } if ((Object)(object)val6 == (Object)null || !val6.IsValid()) { Count(reasons, "chest_view_invalid"); continue; } if (!val6.IsOwner()) { Count(reasons, "chest_not_owned"); continue; } if (component.IsInUse() || val6.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 0) { Count(reasons, "chest_in_use"); continue; } if (!OwnerAutomation.EligibleChest(component, val6)) { Count(reasons, "chest_excluded"); continue; } string text = AccessBlock(component); if (text != null) { Count(reasons, text); continue; } Vector3 val7 = val5.transform.position - val.transform.position; float sqrMagnitude = ((Vector3)(ref val7)).sqrMagnitude; if (sqrMagnitude > request.Range * request.Range) { Count(reasons, "outside_range"); } else if (!(sqrMagnitude > num)) { LoadChest.Invoke(component, null); Inventory inventory = component.GetInventory(); if (inventory == null) { Count(reasons, "inventory_unavailable"); continue; } if (inventory.CountItems(itemData.m_shared.m_name, -1, true) <= 0) { Count(reasons, "no_matching_items"); continue; } if (!inventory.CanAddItem(itemData, itemData.m_stack)) { Count(reasons, "matching_chest_full"); continue; } val4 = chest; num = sqrMagnitude; } } if (((ZDOID)(ref val4)).IsNone()) { request.LastWait = "no_matching_chest:" + Describe(reasons); if (!flag) { Finish(request, request.LastWait, 0, ZDOID.None); } } else if (!val3.IsOwner()) { RequestOwn.Invoke(val2, null); request.LastWait = "drop_owner_handoff"; } else if (!val2.CanPickup(true)) { request.LastWait = "vanilla_pickup_not_ready"; } else if (StoreLease.IsLive(Now, request.Deadline)) { int stack = itemData.m_stack; string lastWait = request.LastWait; request.LastWait = "transfer_rejected"; if (OwnerAutomation.Store(request.Drop, val4, request.Range, request.Log, delegate(string reason) { request.LastWait = reason; })) { Finish(request, "stored", stack, val4); } else if (lastWait != request.LastWait && request.Log != null) { Action<string> log = request.Log; string[] obj = new string[6] { "TRANSFER WAIT drop=", null, null, null, null, null }; ZDOID drop = request.Drop; obj[1] = ((object)(*(ZDOID*)(&drop))/*cast due to .constrained prefix*/).ToString(); obj[2] = " item="; obj[3] = request.Item; obj[4] = " reason="; obj[5] = request.LastWait; log(string.Concat(obj)); } } } } internal static class OwnerAutomation { internal const string ReadyRpc = "RHSQOL_AutomationReady_v2"; internal const string JobRpc = "RHSQOL_AutomationJob_v2"; private static readonly int BackpackMarker = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack"); private static readonly int GraveMarker = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Grave"); private static readonly Dictionary<ZDOID, float> NextJob = new Dictionary<ZDOID, float>(); private static readonly HashSet<ZDOID> Blocked = new HashSet<ZDOID>(); private static readonly List<ZDOID> EmptyDrops = new List<ZDOID>(); private static bool emergencyPaused; private static readonly MethodInfo SaveContainer = AccessTools.Method(typeof(Container), "Save", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo LoadContainer = AccessTools.Method(typeof(Container), "CheckForChanges", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo SaveDrop = AccessTools.Method(typeof(ItemDrop), "Save", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo QueueOre = AccessTools.Method(typeof(Smelter), "QueueOre", new Type[2] { typeof(string), typeof(bool) }, (Type[])null); private static readonly MethodInfo SetFuel = AccessTools.Method(typeof(Smelter), "SetFuel", new Type[1] { typeof(float) }, (Type[])null); internal static void Clear() { NextJob.Clear(); Blocked.Clear(); EmptyDrops.Clear(); emergencyPaused = false; } private static bool Owned(ZNetView view) { if ((Object)(object)view != (Object)null && view.IsValid()) { return view.IsOwner(); } return false; } private static ZNetView View(GameObject obj) { if (!((Object)(object)obj == (Object)null)) { return obj.GetComponent<ZNetView>(); } return null; } private static GameObject Instance(ZDOID id) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNetScene.instance == (Object)null)) { return ZNetScene.instance.FindInstance(id); } return null; } internal static bool EligibleChest(Container chest, ZNetView view) { if ((Object)(object)chest == (Object)null || !Owned(view) || (Object)(object)chest.m_wagon != (Object)null || chest.m_autoDestroyEmpty || chest.IsInUse()) { return false; } ZDO zDO = view.GetZDO(); if (zDO.GetInt(ZDOVars.s_inUse, 0) == 0 && !zDO.GetBool(BackpackMarker, false)) { return !zDO.GetBool(GraveMarker, false); } return false; } internal unsafe static void Handle(ZPackage job, Action<string> log) { //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) if (emergencyPaused || job == null || (Object)(object)ZNetScene.instance == (Object)null) { return; } job.SetPos(0); int num = job.ReadInt(); ZDOID val = job.ReadZDOID(); if (Blocked.Contains(val)) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (NextJob.TryGetValue(val, out var value) && realtimeSinceStartup < value) { return; } if (NextJob.Count > 4096) { NextJob.Clear(); } NextJob[val] = realtimeSinceStartup + ((num == 1) ? 1.8f : 0.5f); try { switch (num) { case 1: { float num3 = job.ReadSingle(); int maxFuel = Math.Max(0, Math.Min(20, job.ReadInt())); int maxOre = Math.Max(0, Math.Min(20, job.ReadInt())); int reserveFuel = Math.Max(0, job.ReadInt()); int reserveOre = Math.Max(0, job.ReadInt()); int num4 = job.ReadInt(); if (num4 >= 0 && num4 <= 64 && !(num3 <= 0f) && !(num3 > 64f)) { List<ZDOID> list = new List<ZDOID>(); for (int i = 0; i < num4; i++) { list.Add(job.ReadZDOID()); } Process(val, list, num3, maxFuel, maxOre, reserveFuel, reserveOre, log); } break; } case 2: { ZDOID val2 = job.ReadZDOID(); float num2 = job.ReadSingle(); if (!(num2 <= 0f) && !(num2 > 64f) && !Blocked.Contains(val2)) { Store(val, val2, num2, log); } break; } } } catch (Exception ex) { Blocked.Add(val); emergencyPaused = true; ZDOID val3 = val; log("PAUSED object=" + ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString() + ": " + ex); } } internal static void Tick() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) for (int num = EmptyDrops.Count - 1; num >= 0; num--) { GameObject val = Instance(EmptyDrops[num]); if ((Object)(object)val == (Object)null) { EmptyDrops.RemoveAt(num); } else { ZNetView val2 = View(val); ItemDrop component = val.GetComponent<ItemDrop>(); if (!Owned(val2) || (Object)(object)component == (Object)null || component.m_itemData.m_stack != 0) { EmptyDrops.RemoveAt(num); } else { try { val2.Destroy(); EmptyDrops.RemoveAt(num); } catch { } } } } } private static byte[] Bytes(Inventory inventory) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); inventory.Save(val); return val.GetArray(); } private static bool Same(byte[] a, byte[] b) { if (a == null || b == null || a.Length != b.Length) { return false; } for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) { return false; } } return true; } private static void Persist(Container chest, ZNetView view) { if (!Owned(view) || SaveContainer == null) { throw new InvalidOperationException("Container ownership/save unavailable."); } SaveContainer.Invoke(chest, null); if (!Same(Bytes(chest.GetInventory()), view.GetZDO().GetByteArray(ZDOVars.s_items, (byte[])null))) { throw new InvalidOperationException("Container inventory save was not verified."); } } private static void Restore(Container chest, ZNetView view, byte[] bytes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Load(bytes); chest.GetInventory().Load(val); Persist(chest, view); } private static bool Feed(Smelter smelter, ZNetView station, Container chest, ZNetView chestView, string sharedName, string prefabName, int reserve, bool fuel) { if (!Owned(station) || !EligibleChest(chest, chestView)) { return false; } Inventory inv = chest.GetInventory(); int beforeCount = inv.CountItems(sharedName, -1, true); if (beforeCount <= reserve) { return false; } ItemData item = inv.GetItem(sharedName, -1, false); if (item == null) { return false; } ZDO zdo = station.GetZDO(); float beforeFuel = zdo.GetFloat(ZDOVars.s_fuel, 0f); int beforeQueue = zdo.GetInt(ZDOVars.s_queued, 0); if (fuel ? (Math.Ceiling(beforeFuel) >= (double)smelter.m_maxFuel) : (beforeQueue >= smelter.m_maxOre)) { return false; } if ((fuel && SetFuel == null) || (!fuel && QueueOre == null)) { return false; } string slotKey = "item" + beforeQueue; string oldSlot = zdo.GetString(slotKey, ""); bool oldCheated = zdo.GetBool(ZDOVars.s_cheatedQueued, false); byte[] chestBefore = Bytes(inv); float expectedFuel = Math.Min(smelter.m_maxFuel, beforeFuel + 1f); return TransferSafety.Commit(delegate { if (!Owned(station) || !EligibleChest(chest, chestView)) { throw new InvalidOperationException("Ownership changed."); } if (fuel) { SetFuel.Invoke(smelter, new object[1] { expectedFuel }); } else { QueueOre.Invoke(smelter, new object[2] { prefabName, item.m_cheated }); } }, () => Owned(station) && ((!fuel) ? (zdo.GetInt(ZDOVars.s_queued, 0) == beforeQueue + 1 && zdo.GetString(slotKey, "") == prefabName) : (Math.Abs(zdo.GetFloat(ZDOVars.s_fuel, 0f) - expectedFuel) < 0.001f)), delegate { if (!EligibleChest(chest, chestView) || !inv.RemoveItem(item, 1)) { throw new InvalidOperationException("Source removal was rejected."); } Persist(chest, chestView); }, () => Owned(station) && Owned(chestView) && inv.CountItems(sharedName, -1, true) == beforeCount - 1, delegate { if (!Owned(station)) { throw new InvalidOperationException("Cannot restore a processor owned by another peer."); } if (fuel) { SetFuel.Invoke(smelter, new object[1] { beforeFuel }); } else { zdo.Set(slotKey, oldSlot); zdo.Set(ZDOVars.s_queued, beforeQueue, false); zdo.Set(ZDOVars.s_cheatedQueued, oldCheated); } }, delegate { Restore(chest, chestView, chestBefore); }); } private unsafe static void Process(ZDOID stationId, List<ZDOID> chests, float range, int maxFuel, int maxOre, int reserveFuel, int reserveOre, Action<string> log) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) GameObject val = Instance(stationId); ZNetView val2 = View(val); Smelter val3 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<Smelter>()); if (!Owned(val2) || (Object)(object)val3 == (Object)null) { return; } int i = 0; int j = 0; for (int k = 0; k < chests.Count; k++) { GameObject val4 = Instance(chests[k]); Container val5 = (((Object)(object)val4 == (Object)null) ? null : val4.GetComponent<Container>()); ZNetView val6 = View(val4); if (!EligibleChest(val5, val6)) { continue; } Vector3 val7 = val4.transform.position - val.transform.position; if (((Vector3)(ref val7)).sqrMagnitude > range * range) { continue; } Player localPlayer = Player.m_localPlayer; string text = ProcessChestHandoff.AccessBlock(val5, ((Object)(object)localPlayer == (Object)null) ? 0 : localPlayer.GetPlayerID()); if (text != null) { string[] obj = new string[6] { "PROCESS WAIT station=", null, null, null, null, null }; ZDOID val8 = stationId; obj[1] = ((object)(*(ZDOID*)(&val8))/*cast due to .constrained prefix*/).ToString(); obj[2] = " chest="; obj[3] = ((object)chests[k]/*cast due to .constrained prefix*/).ToString(); obj[4] = " reason="; obj[5] = text; log(string.Concat(obj)); continue; } if (LoadContainer == null) { throw new InvalidOperationException("Container refresh API unavailable."); } LoadContainer.Invoke(val5, null); if (!EligibleChest(val5, val6)) { continue; } for (; i < maxFuel; i++) { if (!((Object)(object)val3.m_fuelItem != (Object)null)) { break; } if (!Feed(val3, val2, val5, val6, val3.m_fuelItem.m_itemData.m_shared.m_name, null, reserveFuel, fuel: true)) { break; } } if (val3.m_conversion == null) { continue; } for (int l = 0; l < val3.m_conversion.Count; l++) { if (j >= maxOre) { break; } ItemConversion val9 = val3.m_conversion[l]; if (val9 == null || (Object)(object)val9.m_from == (Object)null) { continue; } for (; j < maxOre; j++) { if (!Feed(val3, val2, val5, val6, val9.m_from.m_itemData.m_shared.m_name, ((Object)((Component)val9.m_from).gameObject).name, reserveOre, fuel: false)) { break; } } } } if (i + j > 0) { string[] obj2 = new string[6] { "FED owner-verified station=", null, null, null, null, null }; ZDOID val8 = stationId; obj2[1] = ((object)(*(ZDOID*)(&val8))/*cast due to .constrained prefix*/).ToString(); obj2[2] = " fuel+="; obj2[3] = i.ToString(); obj2[4] = " input+="; obj2[5] = j.ToString(); log(string.Concat(obj2)); } } internal static bool Store(ZDOID dropId, ZDOID targetId, float range, Action<string> log) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Store(dropId, targetId, range, log, null); } private static bool RejectStore(Action<string> rejected, string stage) { rejected?.Invoke("transfer_rejected:" + stage); return false; } private static bool SavedDropStack(ZNetView view, ItemData data, int expected) { if (!Owned(view)) { return false; } ZDO zDO = view.GetZDO(); byte[] byteArray = zDO.GetByteArray(ZDOVars.s_itemData, (byte[])null); if (byteArray == null || byteArray.Length <= 2) { return false; } ItemData obj = data.Clone(); obj.m_stack = -1; ItemDrop.LoadFromZDO(obj, zDO, -1); return obj.m_stack == expected; } internal unsafe static bool Store(ZDOID dropId, ZDOID targetId, float range, Action<string> log, Action<string> rejected) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02db: 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_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Invalid comparison between Unknown and I4 //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) GameObject val = Instance(dropId); GameObject val2 = Instance(targetId); ItemDrop drop = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>()); Container chest = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<Container>()); ZNetView dropView = View(val); ZNetView chestView = View(val2); if (!Owned(dropView)) { return RejectStore(rejected, "drop_not_owned"); } if (!EligibleChest(chest, chestView)) { return RejectStore(rejected, "chest_unavailable"); } if ((Object)(object)drop == (Object)null || SaveDrop == null) { return RejectStore(rejected, "drop_save_unavailable"); } ItemData data = drop.m_itemData; if (data == null || data.m_shared == null) { return RejectStore(rejected, "drop_data_unavailable"); } if (data.m_stack <= 0) { dropView.Destroy(); return false; } if (!GroundStoreRules.IsEligible(dropView.GetZDO().GetBool(ZDOVars.s_piece, false), data.m_shared.m_maxStackSize, (int)data.m_shared.m_itemType == 2)) { return RejectStore(rejected, "drop_excluded"); } Vector3 val3 = val.transform.position - val2.transform.position; if (((Vector3)(ref val3)).sqrMagnitude > range * range) { return RejectStore(rejected, "outside_range"); } Inventory inv = chest.GetInventory(); string name = data.m_shared.m_name; int beforeCount = inv.CountItems(name, -1, true); int stack = data.m_stack; if (beforeCount <= 0 || !inv.CanAddItem(data, stack)) { return RejectStore(rejected, "chest_match_or_capacity_changed"); } byte[] before = Bytes(inv); string stage = "destination_ownership"; if (!TransferSafety.Commit(delegate { if (!Owned(dropView) || !EligibleChest(chest, chestView)) { throw new InvalidOperationException("Ownership changed."); } ItemData val5 = data.Clone(); val5.m_stack = stack; stage = "destination_add"; if (!inv.AddItem(val5)) { throw new InvalidOperationException("Target chest rejected the stack."); } stage = "destination_save"; Persist(chest, chestView); }, delegate { stage = "destination_verify"; return Owned(chestView) && inv.CountItems(name, -1, true) == beforeCount + stack; }, delegate { stage = "source_ownership_or_count"; if (!Owned(dropView) || data.m_stack != stack) { throw new InvalidOperationException("Ground stack changed."); } stage = "source_save"; data.m_stack = 0; SaveDrop.Invoke(drop, null); }, delegate { stage = "source_verify"; return Owned(dropView) && data.m_stack == 0 && SavedDropStack(dropView, data, 0); }, delegate { Restore(chest, chestView, before); }, delegate { if (!Owned(dropView)) { throw new InvalidOperationException("Cannot restore another peer's ground item."); } data.m_stack = stack; SaveDrop.Invoke(drop, null); if (!SavedDropStack(dropView, data, stack)) { throw new InvalidOperationException("Ground item rollback save was not verified."); } })) { return RejectStore(rejected, stage); } try { dropView.Destroy(); } catch { EmptyDrops.Add(dropId); } string[] obj2 = new string[8] { "STORED owner-verified item=", name, " count=", stack.ToString(), " drop=", null, null, null }; ZDOID val4 = dropId; obj2[5] = ((object)(*(ZDOID*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj2[6] = " chest="; val4 = targetId; obj2[7] = ((object)(*(ZDOID*)(&val4))/*cast due to .constrained prefix*/).ToString(); log(string.Concat(obj2)); return true; } } internal static class ProcessChestHandoff { internal const string ReadyRpc = "RHSQOL_ProcessChestReady_v1"; internal const string JobRpc = "RHSQOL_ProcessChestHandoff_v1"; internal const string ResultRpc = "RHSQOL_ProcessChestResult_v1"; private static readonly Dictionary<ZDOID, int> Seen = new Dictionary<ZDOID, int>(); private static readonly MethodInfo LoadChest = AccessTools.Method(typeof(Container), "CheckForChanges", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo SaveChest = AccessTools.Method(typeof(Container), "Save", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo CheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); private static readonly FieldInfo WardAreas = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo WardEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo WardInside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo WardPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); internal static void Clear() { Seen.Clear(); } internal static string AccessBlock(Container chest, long playerId) { //IL_0010: 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: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 //IL_011a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)chest == (Object)null) { return "container_missing"; } if ((int)chest.m_privacy == 0) { if (playerId == 0L || CheckAccess == null) { return "private_access_unavailable"; } if (!(bool)CheckAccess.Invoke(chest, new object[1] { playerId })) { return "private_access_denied"; } } else if ((int)chest.m_privacy != 1 && (int)chest.m_privacy != 2) { return "unknown_privacy"; } if (!chest.m_checkGuardStone) { return null; } if (WardAreas == null || WardEnabled == null || WardInside == null || WardPermitted == null) { return "ward_access_unavailable"; } if (!(WardAreas.GetValue(null) is IEnumerable enumerable)) { return "ward_access_unavailable"; } bool flag = false; foreach (object item in enumerable) { PrivateArea val = (PrivateArea)((item is PrivateArea) ? item : null); if (!((Object)(object)val == (Object)null) && (bool)WardEnabled.Invoke(val, null) && (bool)WardInside.Invoke(val, new object[2] { ((Component)chest).transform.position, 0f })) { if (playerId == 0L) { return "ward_access_unavailable"; } Piece component = ((Component)val).GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { return "ward_access_unavailable"; } if (component.GetCreator() == playerId || (bool)WardPermitted.Invoke(val, new object[1] { playerId })) { return null; } flag = true; } } if (!flag) { return null; } return "ward_denied"; } internal static bool HasInputs(Smelter smelter, ZDO station, Inventory inv, int reserveFuel, int reserveOre) { if ((Object)(object)smelter == (Object)null || station == null || inv == null) { return false; } if ((Object)(object)smelter.m_fuelItem != (Object)null && smelter.m_fuelItem.m_itemData != null && Math.Ceiling(station.GetFloat(ZDOVars.s_fuel, 0f)) < (double)smelter.m_maxFuel && inv.CountItems(smelter.m_fuelItem.m_itemData.m_shared.m_name, -1, true) > reserveFuel) { return true; } if (station.GetInt(ZDOVars.s_queued, 0) >= smelter.m_maxOre || smelter.m_conversion == null) { return false; } foreach (ItemConversion item in smelter.m_conversion) { if (item != null && (Object)(object)item.m_from != (Object)null && item.m_from.m_itemData != null && inv.CountItems(item.m_from.m_itemData.m_shared.m_name, -1, true) > reserveOre) { return true; } } return false; } private static bool ReadyToGrant(Container chest, ZNetView chestView, ZNetView stationView, long recipient, long playerId, float range, long deadline) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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) if (StoreLease.IsLive(ZNet.instance.GetTime().Ticks, deadline) && OwnerAutomation.EligibleChest(chest, chestView) && stationView.IsValid() && stationView.GetZDO().GetOwner() == recipient) { Vector3 val = ((Component)stationView).transform.position - ((Component)chestView).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= range * range) { return AccessBlock(chest, playerId) == null; } } return false; } internal static string Handle(ZPackage pkg, Action<long, ZDOID> replicate, out ZDOID chestId, out int token) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Expected O, but got Unknown //IL_03fb: Unknown result type (might be due to invalid IL or missing references) chestId = ZDOID.None; token = 0; try { if (pkg == null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return "not_loaded"; } pkg.SetPos(0); ZDOID val = pkg.ReadZDOID(); chestId = pkg.ReadZDOID(); token = pkg.ReadInt(); long num = pkg.ReadLong(); long num2 = pkg.ReadLong(); long playerId = pkg.ReadLong(); float num3 = pkg.ReadSingle(); int num4 = pkg.ReadInt(); int num5 = pkg.ReadInt(); long ticks = ZNet.instance.GetTime().Ticks; if (((ZDOID)(ref val)).IsNone() || ((ZDOID)(ref chestId)).IsNone() || val == chestId || token <= 0 || num2 == 0L || float.IsNaN(num3) || float.IsInfinity(num3) || num3 <= 0f || num3 > 64f || num4 < 0 || num4 > 999 || num5 < 0 || num5 > 999 || !StoreLease.IsLive(ticks, num) || num - ticks > 100000000) { return "invalid_or_expired"; } if (Seen.TryGetValue(chestId, out var value) && value >= token) { return "replayed"; } if (Seen.Count > 4096) { Seen.Clear(); } Seen[chestId] = token; GameObject val2 = ZNetScene.instance.FindInstance(val); GameObject val3 = ZNetScene.instance.FindInstance(chestId); ZNetView val4 = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<ZNetView>()); ZNetView val5 = (((Object)(object)val3 == (Object)null) ? null : val3.GetComponent<ZNetView>()); Smelter val6 = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<Smelter>()); Container val7 = (((Object)(object)val3 == (Object)null) ? null : val3.GetComponent<Container>()); if ((Object)(object)val4 == (Object)null || !val4.IsValid() || (Object)(object)val6 == (Object)null) { return "station_not_loaded"; } if (val4.GetZDO().GetOwner() != num2) { return "station_owner_changed"; } if (!OwnerAutomation.EligibleChest(val7, val5)) { return "chest_unavailable"; } if ((Object)(object)((Component)val7).GetComponent<TombStone>() != (Object)null || ((Object)val3).name.IndexOf("private", StringComparison.OrdinalIgnoreCase) >= 0) { return "chest_excluded"; } if (val5.GetZDO().GetOwner() == num2) { return "already_owned"; } Vector3 val8 = val2.transform.position - val3.transform.position; if (((Vector3)(ref val8)).sqrMagnitude > num3 * num3) { return "outside_range"; } string text = AccessBlock(val7, playerId); if (text != null) { return text; } if (LoadChest == null || SaveChest == null || replicate == null) { return "handoff_api_unavailable"; } LoadChest.Invoke(val7, null); if (!OwnerAutomation.EligibleChest(val7, val5)) { return "chest_changed"; } Inventory inventory = val7.GetInventory(); if (!HasInputs(val6, val4.GetZDO(), inventory, num4, num5)) { return "no_needed_inputs"; } SaveChest.Invoke(val7, null); ZPackage val9 = new ZPackage(); inventory.Save(val9); byte[] array = val9.GetArray(); byte[] byteArray = val5.GetZDO().GetByteArray(ZDOVars.s_items, (byte[])null); if (byteArray == null || array.Length != byteArray.Length) { return "save_not_verified"; } for (int i = 0; i < byteArray.Length; i++) { if (byteArray[i] != array[i]) { return "save_not_verified"; } } if (!ReadyToGrant(val7, val5, val4, num2, playerId, num3, num)) { return "state_changed"; } replicate(num2, chestId); if (!ReadyToGrant(val7, val5, val4, num2, playerId, num3, num)) { return "state_changed"; } val5.GetZDO().SetOwner(num2); return (val5.GetZDO().GetOwner() == num2) ? "granted" : "grant_not_verified"; } catch (Exception ex) { return "handoff_error:" + ex.GetType().Name; } } } internal static class StoreLease { internal const long DurationTicks = 100000000L; internal const long QuietTicks = 30000000L; internal static bool IsLive(long now, long deadline) { if (deadline > 0) { return now < deadline; } return false; } internal static bool CanDispatch(long now, long previousDeadline) { if (previousDeadline > 0) { return now >= previousDeadline + 30000000; } return true; } internal static bool Matches(int token, long owner, int reportedToken, long sender) { if (token > 0 && token == reportedToken) { return owner == sender; } return false; } } internal static class TransferSafety { internal static bool Commit(Action destination, Func<bool> destinationAccepted, Action source, Func<bool> sourceCommitted, Action restoreDestination, Action restoreSource) { bool flag = false; bool flag2 = false; try { flag = true; destination(); if (!destinationAccepted()) { throw new InvalidOperationException("Destination did not accept the transfer."); } flag2 = true; source(); if (!sourceCommitted()) { throw new InvalidOperationException("Source did not commit the transfer."); } return true; } catch (Exception ex) { Exception ex2 = null; if (flag2) { try { restoreSource(); } catch (Exception ex3) { ex2 = ex3; } } if (flag) { try { restoreDestination(); } catch (Exception ex4) { if (ex2 == null) { ex2 = ex4; } } } if (ex2 != null) { throw new InvalidOperationException("Transfer rollback failed; automation is paused for these objects.", new AggregateException(ex, ex2)); } return false; } } } } namespace RustyHeathens.Backpacks { internal sealed class BackpackDeathLocation { internal Vector3 DeathPoint; internal ZDOID GraveId = ZDOID.None; internal Vector3 GravePoint; } internal enum DeathLocationRead { Legacy, Valid, Invalid } internal static class BackpackDeathPlacement { internal const string AnchorKey = "RHSQOL_RustyBackpack_DeathAnchor"; internal const float GraveSpacing = 1.25f; private const int WireMarker = 1380467249; internal static bool Finite(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (Coordinate(point.x) && Coordinate(point.y)) { return Coordinate(point.z); } return false; } private static bool Coordinate(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Math.Abs(value) < 100000f; } return false; } internal static Vector3 Beside(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return point + Vector3.right * 1.25f; } internal static void Write(ZPackage report, ZDOID character, BackpackDeathLocation location) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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) report.Write(1380467249); report.Write(character); report.Write(location.DeathPoint); report.Write(location.GraveId); report.Write(location.GravePoint); } internal static DeathLocationRead Read(ZPackage report, ZDOID character, out BackpackDeathLocation location) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_005a: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) location = null; if (report.GetPos() == report.Size()) { return DeathLocationRead.Legacy; } try { if (report.ReadInt() != 1380467249 || report.ReadZDOID() != character) { return DeathLocationRead.Invalid; } BackpackDeathLocation backpackDeathLocation = new BackpackDeathLocation { DeathPoint = report.ReadVector3(), GraveId = report.ReadZDOID(), GravePoint = report.ReadVector3() }; if (report.GetPos() != report.Size() || !Finite(backpackDeathLocation.DeathPoint) || !Finite(backpackDeathLocation.GravePoint)) { return DeathLocationRead.Invalid; } if (!((ZDOID)(ref backpackDeathLocation.GraveId)).IsNone()) { Vector3 val = backpackDeathLocation.GravePoint - backpackDeathLocation.DeathPoint; if (((Vector3)(ref val)).sqrMagnitude > 16f) { return DeathLocationRead.Invalid; } } location = backpackDeathLocation; return DeathLocationRead.Valid; } catch { return DeathLocationRead.Invalid; } } internal static bool IsInventoryGrave(ZDO grave, long playerId) { if (grave != null && grave.IsValid() && playerId != 0L && grave.GetPrefab() == StringExtensionMethods.GetStableHashCode("Player_tombstone") && grave.GetLong(ZDOVars.s_owner, 0L) == playerId && !grave.GetBool("RHSQOL_RustyBackpack_Grave", false)) { return !grave.GetString(ZDOVars.s_ownerName, "").EndsWith(" - Rusty Backpack", StringComparison.Ordinal); } return false; } internal static Vector3 Resolve(BackpackDeathLocation location, Vector3 frozenDeathPoint, ZDO grave, long playerId, out ZDOID anchor) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) anchor = ZDOID.None; if (location == null) { return frozenDeathPoint; } if (((ZDOID)(ref location.GraveId)).IsNone()) { return location.DeathPoint; } if (grave != null) { if (grave.m_uid != location.GraveId || !IsInventoryGrave(grave, playerId) || !Finite(grave.GetPosition())) { return location.DeathPoint; } anchor = grave.m_uid; return Beside(grave.GetPosition()); } anchor = location.GraveId; return Beside(location.GravePoint); } } } namespace RustyHeathens.QoL { internal static class BackpackClient { internal const string RequestRpc = "RHSQOL_BackpackRequest_v2"; internal const string AssignedRpc = "RHSQOL_BackpackAssigned_v2"; internal const string DeathRpc = "RHSQOL_BackpackDeath_v2"; private static readonly int Marker = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack"); private static readonly int PlayerKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Player"); private static readonly HashSet<Inventory> Weightless = new HashSet<Inventory>(); internal static ZDOID AssignedId = ZDOID.None; internal static void Clear() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Weightless.Clear(); AssignedId = ZDOID.None; BackpackDeathCapture.Clear(); } internal static bool IsWeightless(Inventory inv) { if (inv != null) { return Weightless.Contains(inv); } return false; } internal static bool IsGrave(Container container) { if ((Object)(object)container == (Object)null) { return false; } ZNetView component = ((Component)container).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (!zDO.GetBool("RHSQOL_RustyBackpack_Grave", false)) { return zDO.GetString(ZDOVars.s_ownerName, "").EndsWith(" - Rusty Backpack", StringComparison.Ordinal); } return true; } internal static void Register(Container container) { if ((Object)(object)container == (Object)null || container.GetInventory() == null) { return; } ZNetView component = ((Component)container).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (!zDO.GetBool(Marker, false) && !IsGrave(container)) { return; } Weightless.Add(container.GetInventory()); if (zDO.GetBool(Marker, false)) { StandaloneInventory.SetRawHeight(height: container.m_height = Math.Max(container.GetInventory().GetHeight(), zDO.GetInt("Container.m_height", container.m_height)), inv: container.GetInventory()); if ((Object)(object)Player.m_localPlayer != (Object)null && zDO.GetLong(PlayerKey, 0L) == Player.m_localPlayer.GetPlayerID()) { StandaloneInventoryUI.RegisterRustyBackpack(container.GetInventory()); } } } internal static Container OwnedBackpack() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (((ZDOID)(ref AssignedId)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return null; } GameObject val = ZNetScene.instance.FindInstance(AssignedId); if ((Object)(object)val == (Object)null) { return null; } ZNetView component = val.GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return null; } ZDO zDO = component.GetZDO(); if (!zDO.GetBool(Marker, false) || zDO.GetLong(PlayerKey, 0L) != Player.m_localPlayer.GetPlayerID()) { return null; } Container component2 = val.GetComponent<Container>(); Register(component2); return component2; } private static byte[] Save(Inventory inv) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); inv.Save(val); return val.GetArray(); } private static void Restore(Container container, byte[] bytes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Load(bytes); container.GetInventory().Load(val); Persist(container); } private static void Persist(Container container) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsOwner()) { throw new InvalidOperationException("Backpack/grave ownership changed."); } AccessTools.Method(typeof(Container), "Save", Type.EmptyTypes, (Type[])null).Invoke(container, null); byte[] byteArray = component.GetZDO().GetByteArray(ZDOVars.s_items, (byte[])null); byte[] array = Save(container.GetInventory()); if (byteArray == null || byteArray.Length != array.Length) { throw new InvalidOperationException("Recovery save failed."); } for (int i = 0; i < array.Length; i++) { if (byteArray[i] != array[i]) { throw new InvalidOperationException("Recovery save failed."); } } } internal static bool Recover(Container grave) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)grave == (Object)null || !IsGrave(grave)) { return false; } ZNetView component = ((Component)grave).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO().GetLong(ZDOVars.s_owner, 0L) != localPlayer.GetPlayerID()) { return false; } Container target = OwnedBackpack(); if ((Object)(object)target == (Object)null || !component.IsOwner()) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.RequestBackpack(open: false, "wave"); } ((Character)localPlayer).Message((MessageType)2, "Open your Rusty Backpack with Wave, then use Take All on the backpack grave.", 0, (Sprite)null, false); return true; } Inventory src = grave.GetInventory(); Inventory dst = target.GetInventory(); List<ItemData> list = new List<ItemData>(src.GetAllItems()); int num = 0; try { foreach (ItemData item in list) { if (item != null && dst.CanAddItem(item, item.m_stack)) { byte[] beforeSrc = Save(src); byte[] beforeDst = Save(dst); int amount = item.m_stack; string name = item.m_shared.m_name; int sourceCount = src.CountItems(name, -1, true); int destCount = dst.CountItems(name, -1, true); if (TransferSafety.Commit(delegate { if (!dst.AddItem(item.Clone())) { throw new InvalidOperationException("Backpack is full."); } Persist(target); }, () => dst.CountItems(name, -1, true) == destCount + amount, delegate { if (!src.RemoveItem(item)) { throw new InvalidOperationException("Grave changed."); } Persist(grave); }, () => src.CountItems(name, -1, true) == sourceCount - amount, delegate { Restore(target, beforeDst); }, delegate { Restore(grave, beforeSrc); })) { num++; } } } } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogWarning("[RHQOL Backpack] Recovery stopped: " + ex); } ((Character)localPlayer).Message((MessageType)2, "Backpack recovery stopped. Check the log before retrying.", 0, (Sprite)null, false); return true; } ((Character)localPlayer).Message((MessageType)2, num + " stack(s) returned to Rusty Backpack." + ((src.NrOfItems() > 0) ? " Remaining items stay in the grave until there is space." : ""), 0, (Sprite)null, false); if (src.NrOfItems() == 0) { TombStone component2 = ((Component)grave).GetComponent<TombStone>(); if ((Object)(object)component2 != (Object)null) { try { AccessTools.Method(typeof(TombStone), "OnTakeAllSuccess", (Type[])null, (Type[])null).Invoke(component2, null); } catch { } } } return true; } } [HarmonyPatch(typeof(Container), "Awake")] internal static class BackpackWeightRegistrationPatch { private static void Postfix(Container __instance) { BackpackClient.Register(__instance); } } [HarmonyPatch(typeof(Inventory), "GetTotalWeight")] internal static class WeightlessBackpackPatch { private static bool Prefix(Inventory __instance, ref float __result) { if (!BackpackClient.IsWeightless(__instance)) { return true; } __result = 0f; return false; } } [HarmonyPatch(typeof(Inventory), "IsTeleportable")] internal static class BackpackTeleportCargoPatch { private static void Postfix(Inventory __instance, bool __0, ref bool __result) { Player localPlayer = Player.m_localPlayer; if (__result && !((Object)(object)localPlayer == (Object)null) && __instance == ((Humanoid)localPlayer).GetInventory()) { Container val = BackpackClient.OwnedBackpack(); if ((Object)(object)val != (Object)null && !val.GetInventory().IsTeleportable(__0)) { __result = false; } } } } [HarmonyPatch(typeof(TombStone), "EasyFitInInventory")] internal static class BackpackGraveAutoLootPatch { private static bool Prefix(TombStone __instance, ref bool __result) { if (!BackpackClient.IsGrave(((Component)__instance).GetComponent<Container>())) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(InventoryGui), "OnTakeAll")] internal static class BackpackGraveTakeAllPatch { private static bool Prefix(Container ___m_currentContainer) { return !BackpackClient.Recover(___m_currentContainer); } } internal static class BackpackDeathCapture { internal sealed class Snapshot { internal ZDOID Backpack; internal ZDOID Character; internal long PlayerId; internal byte[] Items; internal BackpackDeathLocation Location; } private static Snapshot active; internal static void Clear() { active = null; } internal static Snapshot Begin(Player player) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) active = null; if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)Plugin.Instance == (Object)null) { return null; } ZNetView component = ((Component)player).GetComponent<ZNetView>(); Container val = BackpackClient.OwnedBackpack(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || (Object)(object)val == (Object)null) { return null; } ZPackage val2 = new ZPackage(); val.GetInventory().Save(val2); Vector3 centerPoint = ((Character)player).GetCenterPoint(); active = new Snapshot { Backpack = BackpackClient.AssignedId, Character = component.GetZDO().m_uid, PlayerId = player.GetPlayerID(), Items = val2.GetArray(), Location = new BackpackDeathLocation { DeathPoint = centerPoint, GravePoint = centerPoint } }; return active; } internal static void RecordGrave(TombStone grave, long owner) { //IL_004b: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (active == null || (Object)(object)grave == (Object)null || owner != active.PlayerId) { return; } ZNetView component = ((Component)grave).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !BackpackDeathPlacement.IsInventoryGrave(component.GetZDO(), owner)) { return; } Vector3 position = ((Component)grave).transform.position; if (BackpackDeathPlacement.Finite(position)) { Vector3 val = position - active.Location.DeathPoint; if (!(((Vector3)(ref val)).sqrMagnitude > 16f)) { active.Location.GraveId = component.GetZDO().m_uid; active.Location.GravePoint = position; } } } internal static void Finish(Snapshot snapshot) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Clear(); if (snapshot != null && !((Object)(object)Plugin.Instance == (Object)null)) { ZPackage val = new ZPackage(); val.Write(snapshot.Backpack); val.Write(snapshot.Items); BackpackDeathPlacement.Write(val, snapshot.Character, snapshot.Location); Plugin.Instance.SendToServer("RHSQOL_BackpackDeath_v2", val); } } } [HarmonyPatch(typeof(TombStone), "Setup")] internal static class BackpackDeathAnchorSetupPatch { private static void Postfix(TombStone __instance, long ownerUID) { BackpackDeathCapture.RecordGrave(__instance, ownerUID); } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class BackpackDeathFlushPatch { private static void Prefix(Player __instance, ref BackpackDeathCapture.Snapshot __state) { try { __state = BackpackDeathCapture.Begin(__instance); } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogWarning("[RHQOL Backpack] Death snapshot: " + ex.Message); } } } private static void Postfix(BackpackDeathCapture.Snapshot __state) { try { BackpackDeathCapture.Finish(__state); } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogWarning("[RHQOL Backpack] Death report: " + ex.Message); } } } private static void Finalizer() { BackpackDeathCapture.Clear(); } } internal sealed class BackpackGraveAnchor : MonoBehaviour { private ZNetView view; private Rigidbody body; private bool pinned; private bool wasKinematic; private void Awake() { view = ((Component)this).GetComponent<ZNetView>(); body = ((Component)this).GetComponent<Rigidbody>(); } private void ReleaseBody() { if (pinned && (Object)(object)body != (Object)null) { body.isKinematic = wasKinematic; } pinned = false; } private void OnDisable() { ReleaseBody(); } internal void Follow() { //IL_006a: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: 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_0245: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: 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_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { ReleaseBody(); return; } ZDO zDO = view.GetZDO(); if (!zDO.GetBool("RHSQOL_RustyBackpack_Grave", false)) { ReleaseBody(); return; } ZDOID zDOID = zDO.GetZDOID("RHSQOL_RustyBackpack_DeathAnchor"); ZDO val = (((ZDOID)(ref zDOID)).IsNone() ? null : ZDOMan.instance.GetZDO(zDOID)); if (!BackpackDeathPlacement.IsInventoryGrave(val, zDO.GetLong(ZDOVars.s_owner, 0L))) { ReleaseBody(); return; } GameObject val2 = ZNetScene.instance.FindInstance(zDOID); Vector3 point = (((Object)(object)val2 == (Object)null) ? val.GetPosition() : val2.transform.position); if (!BackpackDeathPlacement.Finite(point)) { ReleaseBody(); return; } Vector3 val3 = BackpackDeathPlacement.Beside(point); if ((Object)(object)ZoneSystem.instance != (Object)null) { val3.y = Mathf.Max(val3.y, ZoneSystem.instance.GetGroundHeight(val3) + 0.5f); } if (!BackpackDeathPlacement.Finite(val3)) { ReleaseBody(); return; } Vector3 val4; if ((Object)(object)body != (Object)null) { if (!pinned) { wasKinematic = body.isKinematic; if (!wasKinematic) { body.linearVelocity = Vector3.zero; body.angularVelocity = Vector3.zero; } body.isKinematic = true; pinned = true; } val4 = body.position - val3; if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f) { body.position = val3; } } val4 = ((Component)this).transform.position - val3; if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f) { ((Component)this).transform.position = val3; } val4 = zDO.GetPosition() - val3; if (!(((Vector3)(ref val4)).sqrMagnitude > 0.0001f)) { val4 = zDO.GetVec3(ZDOVars.s_spawnPoint, val3 + Vector3.up) - val3; if (!(((Vector3)(ref val4)).sqrMagnitude > 0.0001f)) { return; } } zDO.SetPosition(val3); zDO.Set(ZDOVars.s_spawnPoint, val3); } private void FixedUpdate() { Follow(); } } [HarmonyPatch(typeof(TombStone), "Awake")] internal static class BackpackGraveAnchorAwakePatch { private static void Postfix(TombStone __instance) { //IL_0036: 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) ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetBool("RHSQOL_RustyBackpack_Grave", false)) { ZDOID zDOID = component.GetZDO().GetZDOID("RHSQOL_RustyBackpack_DeathAnchor"); if (!((ZDOID)(ref zDOID)).IsNone() && (Object)(object)((Component)__instance).GetComponent<BackpackGraveAnchor>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<BackpackGraveAnchor>(); } } } } internal static class BackpackHostVisibility { private static readonly int MarkerKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack"); internal static void HideIfRustyBackpack(ZNetView view) { if ((Object)(object)view == (Object)null) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null && instance.IsServer()) { return; } ZDO val = null; try { val = view.GetZDO(); } catch { } if (val == null || !val.IsValid() || !val.GetBool(MarkerKey, false)) { return; } GameObject gameObject = ((Component)view).gameObject; if ((Object)(object)gameObject == (Object)null) { return; } Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { val2.enabled = false; } } Collider[] componentsInChildren2 = gameObject.GetComponentsInChildren<Collider>(true); foreach (Collider val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null) { val3.enabled = false; } } Light[] componentsInChildren3 = gameObject.GetComponentsInChildren<Light>(true); foreach (Light val4 in componentsInChildren3) { if ((Object)(object)val4 != (Object)null) { ((Behaviour)val4).enabled = false; } } WearNTear component = gameObject.GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } Container component2 = gameObject.GetComponent<Container>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "Rusty Backpack"; component2.m_checkGuardStone = false; component2.m_autoDestroyEmpty = false; } } } [HarmonyPatch(typeof(ZNetView), "Awake")] internal static class RustyBackpackHostAwakePatch { private static void Postfix(ZNetView __instance) { try { BackpackHostVisibility.HideIfRustyBackpack(__instance); } catch (Exception ex) { Plugin instance = Plugin.Instance; if ((Object)(object)instance != (Object)null) { instance.LogWarning("[RHQOL Backpack] Failed to hide dedicated backpack host on Awake: " + ex.Message); } } } } [HarmonyPatch(typeof(ZNetView), "LoadFields")] internal static class RustyBackpackHostLoadFieldsPatch { private static void Postfix(ZNetView __instance) { try { BackpackHostVisibility.HideIfRustyBackpack(__instance); } catch (Exception ex) { Plugin instance = Plugin.Instance; if ((Object)(object)instance != (Object)null) { instance.LogWarning("[RHQOL Backpack] Failed to hide dedicated backpack host after field load: " + ex.Message); } } } } internal static class CraftAuditClient { internal sealed class AuditState { internal Player Player; internal Inventory Inventory; internal string Station; internal Dictionary<string, int> Before; } private sealed class ItemSnapshot { internal string ItemKey; internal int Quality; internal int Count; } internal const string ReportRpc = "RHSQOL_CraftAudit_v1"; private static readonly FieldInfo StationNameField = AccessTools.Field(typeof(CraftingStation), "m_name"); private static AuditState pending; private static float pendingUntil; internal static void Clear() { pending = null; pendingUntil = 0f; } internal static void Tick() { AuditState auditState = pending; if (auditState == null) { return; } if (TryComplete(auditState)) { pending = null; pendingUntil = 0f; } else if (Time.realtimeSinceStartup >= pendingUntil) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogVerbose("CraftAudit verification expired without a positive inventory delta."); } pending = null; pendingUntil = 0f; } } internal static AuditState Begin(InventoryGui gui) { try { if ((Object)(object)gui == (Object)null || (Object)(object)Plugin.Instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return null; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return null; } AuditState auditState = new AuditState { Player = localPlayer, Inventory = inventory, Station = ResolveStation(localPlayer), Before = SnapshotInventory(inventory) }; Plugin.Instance.LogCraftAuditClient("HOOK DoCrafting station=" + auditState.Station + " stacks=" + auditState.Before.Count + "."); return auditState; } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogCraftAuditClient("CAPTURE-ERROR " + ex.GetType().Name + ": " + ex.Message); } return null; } } internal static void Complete(AuditState state) { try { if (state != null && !((Object)(object)state.Player == (Object)null) && state.Inventory != null && !((Object)(object)Plugin.Instance == (Object)null) && state.Player == Player.m_localPlayer && !TryComplete(state)) { pending = state; pendingUntil = Time.realtimeSinceStartup + 2f; } } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogCraftAuditClient("COMPLETE-ERROR " + ex.GetType().Name + ": " + ex.Message); } } } private static bool TryComplete(AuditState state) { try { if (state == null || (Object)(object)state.Player == (Object)null || state.Inventory == null || (Object)(object)Plugin.Instance == (Object)null) { return false; } if (state.Player != Player.m_localPlayer) { return false; } List<ItemSnapshot> list = SnapshotItems(state.Inventory); for (int i = 0; i < list.Count; i++) { ItemSnapshot itemSnapshot = list[i]; int num = Read(state.Before, MakeKey(itemSnapshot.ItemKey, itemSnapshot.Quality)); int num2 = itemSnapshot.Count - num; if (num2 <= 0) { continue; } bool flag = false; int qualityBefore = 0; int qualityAfter = 0; if (itemSnapshot.Quality > 1) { string key = MakeKey(itemSnapshot.ItemKey, itemSnapshot.Quality - 1); int num3 = Read(state.Before, key); int num4 = Count(list, itemSnapshot.ItemKey, itemSnapshot.Quality - 1); if (num3 > num4) { flag = true; qualityBefore = itemSnapshot.Quality - 1; qualityAfter = itemSnapshot.Quality; } } if (flag) { Send("UPGRADE", itemSnapshot.ItemKey, Localize(itemSnapshot.ItemKey), 1, qualityBefore, qualityAfter, state.Station); } else { Send("CRAFT", itemSnapshot.ItemKey, Localize(itemSnapshot.ItemKey), num2, 0, 0, state.Station); } return true; } return false; } catch (Exception ex) { if ((Object)(object)Plugin.Instance != (Object)null) { Plugin.Instance.LogCraftAuditClient("VERIFY-ERROR " + ex.GetType().Name + ": " + ex.Message); } return false; } } private static Dictionary<string, int> SnapshotInventory(Inventory inventory) { Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); List<ItemSnapshot> list = SnapshotItems(inventory); for (int i = 0; i < list.Count; i++) { dictionary[MakeKey(list[i].ItemKey, list[i].Quality)] = list[i].Count; } return dictionary; } private static List<ItemSnapshot> SnapshotItems(Inventory inventory) { Dictionary<string, ItemSnapshot> dictionary = new Dictionary<string, ItemSnapshot>(StringComparer.Ordinal); if (inventory == null) { return new List<ItemSnapshot>(); } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return new List<ItemSnapshot>(); } for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (val != null && val.m_shared != null && !string.IsNullOrWhiteSpace(val.m_shared.m_name) && val.m_stack > 0) { string key = MakeKey(val.m_shared.m_name, val.m_quality); if (!dictionary.TryGetValue(key, out var value)) { value = new ItemSnapshot { ItemKey = val.m_shared.m_name, Quality = val.m_quality, Count = 0 }; dictionary.Add(key, value); } value.Count += val.m_stack; } } return new List<ItemSnapshot>(dictionary.Values); } private static int Count(List<ItemSnapshot> items, string itemKey, int quality) { if (items == null || string.IsNullOrEmpty(itemKey)) { return 0; } for (int i = 0; i < items.Count; i++) { ItemSnapshot itemSnapshot = items[i]; if (itemSnapshot != null && itemSnapshot.Quality == quality && string.Equals(itemSnapshot.ItemKey, itemKey, StringComparison.Ordinal)) { return itemSnapshot.Count; } } return 0; } private static string MakeKey(string itemKey, int quality) { return (itemKey ?? string.Empty) + "\u001f" + quality; } private static int Read(Dictionary<string, int> map, string key) { if (map == null || key == null) { return 0; } if (!map.TryGetValue(key, out var value)) { return 0; } return value; } private static void Send(string action, string itemKey, string itemDisplay, int amount, int qualityBefore, int qualityAfter, string station) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer()) { ZPackage val = new ZPackage(); val.Write(1); val.Write(action ?? string.Empty); val.Write(itemKey ?? string.Empty); val.Write(itemDisplay ?? string.Empty); val.Write(amount); val.Write(qualityBefore); val.Write(qualityAfter); val.Write(station ?? string.Empty); Plugin.Instance.SendToServer("RHSQOL_CraftAudit_v1", val); Plugin.Instance.LogCraftAuditClient("SENT " + action + " item=" + (itemDisplay ?? itemKey) + " qty=" + amount + " station=" + (station ?? "Unknown") + "."); } } private static string ResolveStation(Player player) { try { CraftingStation station = ChestCrafting.GetStation(player); if ((Object)(object)station == (Object)null) { return "Handcraft"; } string text = ((StationNameField == null) ? null : (StationNameField.GetValue(station) as string)); if (string.IsNullOrWhiteSpace(text) && (Object)(object)((Component)station).gameObject != (Object)null) { text = ((Object)((Component)station).gameObject).name; } return Localize(text); } catch { return "Unknown"; } } private static string Localize(string text) { if (string.IsNullOrWhiteSpace(text)) { return "Unknown"; } try { if (Localization.instance != null) { string text2 = Localization.instance.Localize(text); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } } } catch { } return text; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class CraftAuditDoCraftingPatch { private static void Prefix(InventoryGui __instance, ref CraftAuditClient.AuditState __state) { __state = CraftAuditClient.Begin(__instance); } private static void Postfix(CraftAuditClient.AuditState __state) { CraftAuditClient.Complete(__state); } } [HarmonyPatch(typeof(Player), "Update")] internal static class FoodHotkeySitSuppressionPatch { private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)null || __instance != Player.m_localPlayer || (!Input.GetKey((KeyCode)308) && !Input.GetKey((KeyCode)307)) || !Input.GetKeyDown((KeyCode)120)) { return; } try { ZInput.ResetButtonStatus("Sit"); ZInput.ResetButtonStatus("JoySit"); } catch { } } } internal static class GearGraveService { internal const string MarkerName = "GEAR"; private static readonly Color GearRed = new Color(1f, 0.05f, 0.05f, 1f); private static readonly HashSet<TombStone> Loaded = new HashSet<TombStone>(); private static readonly Dictionary<ZDOID, PinData> Markers = new Dictionary<ZDOID, PinData>(); private static readonly HashSet<ZDOID> Recovered = new HashSet<ZDOID>(); private static readonly MethodInfo LoadContainer = AccessTools.Method(typeof(Container), "CheckForChanges", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo SceneInstances = AccessTools.Field(typeof(ZNetScene), "m_instances"); private static float nextTick; private static float nextDiscovery; private static Vector3 pendingDeathPosition; private static float pendingDeathUntil; internal static void Clear() { Loaded.Clear(); Markers.Clear(); Recovered.Clear(); nextTick = (nextDiscovery = (pendingDeathUntil = 0f)); } internal static void Observe(TombStone grave) { if ((Object)(object)grave != (Object)null) { Loaded.Add(grave); } } internal unsafe static void RegisterDeath(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) pendingDeathPosition = position; pendingDeathUntil = Time.realtimeSinceStartup + 15f; if ((Object)(object)Plugin.Instance != (Object)null) { Plugin instance = Plugin.Instance; Vector3 val = position; instance.LogGearMarker("DEATH with gear at " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + "; waiting for the ordinary player grave."); } } internal static IEnumerator RegisterAfterSetup(TombStone grave, long ownerUid) { Observe(grave); for (int attempt = 0; attempt < 30; attempt++) { if (!((Object)(object)grave != (Object)null)) { break; } CheckGrave(grave); ZNetView component = ((Component)grave).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && Markers.ContainsKey(component.GetZDO().m_uid)) { break; } yield return (object)new WaitForSeconds(0.1f); } } internal unsafe static void Tick() { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.Instance == (Object)null || Plugin.Instance.Effective == null || !Plugin.Instance.Effective.GearGraveMarker || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Minimap.instance == (Object)null || Time.realtimeSinceStartup < nextTick) { return; } nextTick = Time.realtimeSinceStartup + 0.5f; if (Time.realtimeSinceStartup >= nextDiscovery) { nextDiscovery = Time.realtimeSinceStartup + 5f; IDictionary dictionary = (((Object)(object)ZNetScene.instance == (Object)null || SceneInstances == null) ? null : (SceneInstances.GetValue(ZNetScene.instance) as IDictionary)); if (dictionary != null) { foreach (object item in new ArrayList(dictionary.Values)) { ZNetView val = (ZNetView)((item is ZNetView) ? item : null); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode("tombstone")) { Observe(((Component)val).GetComponent<TombStone>()); } } } } foreach (TombStone item2 in new List<TombStone>(Loaded)) { if ((Object)(object)item2 == (Object)null) { Loaded.Remove(item2); } else { CheckGrave(item2); } } if (pendingDeathUntil > 0f && Time.realtimeSinceStartup >= pendingDeathUntil) { pendingDeathUntil = 0f; Plugin instance = Plugin.Instance; Vector3 val2 = pendingDeathPosition; instance.LogGearMarker("WAIT: no loaded ordinary gear grave confirmed at " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString()); } } internal unsafe static void CheckGrave(TombStone grave) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: 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_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: 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) SyncedSettings syncedSettings = (((Object)(object)Plugin.Instance == (Object)null) ? null : Plugin.Instance.Effective); if ((Object)(object)grave == (Object)null || syncedSettings == null || !syncedSettings.GearGraveMarker || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Minimap.instance == (Object)null) { return; } ZNetView component = ((Component)grave).GetComponent<ZNetView>(); Container container = GetContainer(grave); if ((Object)(object)component == (Object)null || !component.IsValid() || (Object)(object)container == (Object)null || BackpackClient.IsGrave(container)) { return; } ZDO zDO = component.GetZDO(); if (zDO.GetLong(ZDOVars.s_owner, 0L) != Player.m_localPlayer.GetPlayerID()) { return; } ZDOID uid = zDO.m_uid; if (Recovered.Contains(uid)) { return; } if (LoadContainer != null && !container.IsInUse()) { LoadContainer.Invoke(container, null); } Inventory inventory = container.GetInventory(); if (inventory == null) { return; } PinData value; bool flag = Markers.TryGetValue(uid, out value); string text = (((Object)(object)ZNet.instance == (Object)null) ? 0 : ZNet.instance.GetWorldUID()).ToString(); ZDOID val = uid; string key = "rhqol_geargrave_v2_" + text + "_" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(); string value2; bool flag2 = Player.m_localPlayer.m_customData.TryGetValue(key, out value2); if (!flag && flag2) { value = FindUnboundPin(TryPosition(value2, out var position) ? position : ((Component)grave).transform.position); if (value != null) { Markers[uid] = value; flag = true; } } if (ContainsRealGear(inventory)) { if (!flag) { value = FindUnboundPin(((Component)grave).transform.position); if (value == null) { value = Minimap.instance.AddPin(((Component)grave).transform.position, (PinType)4, "GEAR", true, false, 0L, default(PlatformUserID)); } Markers[uid] = value; Plugin instance = Plugin.Instance; val = uid; instance.LogGearMarker("MARKED own gear grave=" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString() + " items=" + inventory.NrOfItems()); } if (!flag2) { Player.m_localPlayer.m_customData[key] = PositionText(value.m_pos); } value.m_pos = ((Component)grave).transform.position; Tint(value); if (Time.realtimeSinceStartup < pendingDeathUntil) { Vector3 val2 = pendingDeathPosition - value.m_pos; if (((Vector3)(ref val2)).sqrMagnitude < 36f) { pendingDeathUntil = 0f; } } } else if (GearMarkerRules.ShouldClear(ownGrave: true, backpackGrave: false, flag || flag2, VerifiedEmpty(inventory, zDO))) { if (value != null) { Minimap.instance.RemovePin(value); } Markers.Remove(uid); Recovered.Add(uid); Player.m_localPlayer.m_customData.Remove(key); Plugin instance2 = Plugin.Instance; val = uid; instance2.LogGearMarker("CLEARED recovered gear grave=" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString()); } } private static string PositionText(Vector3 p) { return p.x.ToString("R", CultureInfo.InvariantCulture) + "," + p.y.ToString("R", CultureInfo.InvariantCulture) + "," + p.z.ToString("R", CultureInfo.InvariantCulture); } private static bool TryPosition(string value, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); if (string.IsNullOrEmpty(value)) { return false; } string[] array = value.Split(','); if (array.Length != 3 || !float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { return false; } position = new Vector3(result, result2, result3); return true; } private static bool VerifiedEmpty(Inventory inv, ZDO zdo) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (inv.NrOfItems() != 0) { return false; } byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null); if (byteArray == null) { return false; } ZPackage val = new ZPackage(); inv.Save(val); byte[] array = val.GetArray(); if (byteArray.Length != array.Length) { return false; } for (int i = 0; i < byteArray.Length; i++) { if (byteArray[i] != array[i]) { return false; } } return true; } private static PinData FindUnboundPin(Vector3 position) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) /