Decompiled source of RustyHeathensServerQoL v1.0.0

RustyHeathensServerQoL.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using RustyHeathens.Automation;
using RustyHeathens.Backpacks;
using UnityEngine;

[assembly: AssemblyProduct("Rusty Heathens Server QoL")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyCompany("RustyLaserGaming")]
[assembly: AssemblyDescription("Server-side quality-of-life modules for Heathens' Haven")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("Rusty Heathens Server QoL")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RustyHeathens.ServerQoL
{
	internal static class AutoDoorsModule
	{
		private sealed class TrackedDoor
		{
			internal ZDO Zdo;

			internal float CloseAt;
		}

		private static readonly HashSet<int> DoorPrefabHashes = new HashSet<int>();

		private static readonly Dictionary<ZDOID, TrackedDoor> Tracked = new Dictionary<ZDOID, TrackedDoor>();

		private static readonly List<ZDOID> ScratchKeys = new List<ZDOID>();

		private static bool prefabRegistryReady;

		private static float nextTick;

		internal static void Clear()
		{
			DoorPrefabHashes.Clear();
			Tracked.Clear();
			ScratchKeys.Clear();
			prefabRegistryReady = false;
			nextTick = 0f;
		}

		internal static void Tick()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (!Plugin.IsServer() || !instance.DoorsEnabled)
			{
				if (Tracked.Count > 0)
				{
					Tracked.Clear();
				}
				return;
			}
			EnsurePrefabRegistry();
			if (!prefabRegistryReady)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < nextTick)
			{
				return;
			}
			nextTick = realtimeSinceStartup + 0.2f;
			ScratchKeys.Clear();
			foreach (KeyValuePair<ZDOID, TrackedDoor> item in Tracked)
			{
				ScratchKeys.Add(item.Key);
			}
			for (int i = 0; i < ScratchKeys.Count; i++)
			{
				ZDOID key = ScratchKeys[i];
				if (!Tracked.TryGetValue(key, out var value))
				{
					continue;
				}
				ZDO zdo = value.Zdo;
				if (zdo == null || !zdo.IsValid())
				{
					Tracked.Remove(key);
					continue;
				}
				if (!DoorPrefabHashes.Contains(zdo.GetPrefab()))
				{
					Tracked.Remove(key);
					continue;
				}
				int num = zdo.GetInt(ZDOVars.s_state, 0);
				if (num == 0)
				{
					Tracked.Remove(key);
				}
				else
				{
					if (realtimeSinceStartup < value.CloseAt)
					{
						continue;
					}
					try
					{
						zdo.Set(ZDOVars.s_state, 0, true);
						if (ZDOMan.instance != null)
						{
							ZDOMan.instance.ForceSendZDO(zdo.m_uid);
						}
						instance.LogDoorEvent("CLOSED", zdo, num);
						Tracked.Remove(key);
					}
					catch (Exception ex)
					{
						instance.LogDoorError("Close failed for " + SafeZdoId(zdo) + ": " + ex.Message);
						value.CloseAt = realtimeSinceStartup + 2f;
					}
				}
			}
		}

		internal static void ObserveZdo(ZDO zdo)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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)
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || zdo == null || !Plugin.IsServer() || !instance.DoorsEnabled)
			{
				return;
			}
			EnsurePrefabRegistry();
			if (prefabRegistryReady && zdo.IsValid() && DoorPrefabHashes.Contains(zdo.GetPrefab()))
			{
				int num = zdo.GetInt(ZDOVars.s_state, 0);
				if (num == 0)
				{
					Tracked.Remove(zdo.m_uid);
					return;
				}
				if (Tracked.TryGetValue(zdo.m_uid, out var value))
				{
					value.Zdo = zdo;
					return;
				}
				TrackedDoor trackedDoor = new TrackedDoor();
				trackedDoor.Zdo = zdo;
				trackedDoor.CloseAt = Time.realtimeSinceStartup + instance.DoorDelay;
				Tracked[zdo.m_uid] = trackedDoor;
				instance.LogDoorEvent("OPEN", zdo, num);
			}
		}

		internal static void ObserveDoor(Door door)
		{
			if ((Object)(object)door == (Object)null)
			{
				return;
			}
			try
			{
				ZNetView component = ((Component)door).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					ObserveZdo(component.GetZDO());
				}
			}
			catch
			{
			}
		}

		private static void EnsurePrefabRegistry()
		{
			if (prefabRegistryReady || (Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.m_prefabs == null)
			{
				return;
			}
			DoorPrefabHashes.Clear();
			List<GameObject> prefabs = ZNetScene.instance.m_prefabs;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if (!((Object)(object)val == (Object)null))
				{
					Door val2 = null;
					try
					{
						val2 = val.GetComponentInChildren<Door>();
					}
					catch
					{
					}
					if (!((Object)(object)val2 == (Object)null) && !val2.m_canNotBeClosed && !((Object)(object)val2.m_keyItem != (Object)null))
					{
						DoorPrefabHashes.Add(StringExtensionMethods.GetStableHashCode(((Object)val).name));
					}
				}
			}
			if (DoorPrefabHashes.Count > 0)
			{
				prefabRegistryReady = true;
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.LogDoorRegistry(DoorPrefabHashes.Count);
				}
			}
		}

		private static string SafeZdoId(ZDO zdo)
		{
			try
			{
				return (zdo == null) ? "unknown" : ((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString();
			}
			catch
			{
				return "unknown";
			}
		}
	}
	[HarmonyPatch(typeof(ZDO), "Deserialize")]
	internal static class AutoDoorsZdoDeserializePatch
	{
		private static void Postfix(ZDO __instance)
		{
			AutoDoorsModule.ObserveZdo(__instance);
		}
	}
	[HarmonyPatch(typeof(Door), "RPC_UseDoor")]
	internal static class AutoDoorsRpcPatch
	{
		private static void Postfix(Door __instance)
		{
			AutoDoorsModule.ObserveDoor(__instance);
		}
	}
	[HarmonyPatch(typeof(Door), "UpdateState")]
	internal static class AutoDoorsUpdateStatePatch
	{
		private static void Postfix(Door __instance)
		{
			AutoDoorsModule.ObserveDoor(__instance);
		}
	}
	internal static class AutoProcessModule
	{
		private sealed class Handoff
		{
			internal int Token;

			internal long Owner;

			internal long Deadline;

			internal ZDOID Station;
		}

		private static readonly Dictionary<ZDOID, Handoff> Handoffs = new Dictionary<ZDOID, Handoff>();

		private static int nextHandoffToken;

		private static readonly Dictionary<int, Container> BuildableContainerPrefabs = new Dictionary<int, Container>();

		private static readonly Dictionary<int, Smelter> ProcessorPrefabs = new Dictionary<int, Smelter>();

		private static readonly List<ZDO> DiscoveryObjects = new List<ZDO>();

		private static readonly List<ZDO> SectorObjects = new List<ZDO>();

		private static readonly List<ZDO> Nearby = new List<ZDO>();

		private static readonly HashSet<ZDOID> SeenStations = new HashSet<ZDOID>();

		private static readonly HashSet<long> DiscoverySectorKeys = new HashSet<long>();

		private static readonly HashSet<int> LoggedProcessorPrefabs = new HashSet<int>();

		private static readonly Dictionary<ZDOID, float> LastWaitLog = new Dictionary<ZDOID, float>();

		private static bool prefabMapsReady;

		private static bool registryLogged;

		private static float nextTick;

		private static float nextDiscoveryLog;

		internal static void Clear()
		{
			Handoffs.Clear();
			nextHandoffToken = 0;
			BuildableContainerPrefabs.Clear();
			ProcessorPrefabs.Clear();
			DiscoveryObjects.Clear();
			SectorObjects.Clear();
			Nearby.Clear();
			SeenStations.Clear();
			DiscoverySectorKeys.Clear();
			LoggedProcessorPrefabs.Clear();
			LastWaitLog.Clear();
			prefabMapsReady = false;
			registryLogged = false;
			nextTick = 0f;
			nextDiscoveryLog = 0f;
		}

		internal static void Tick()
		{
			//IL_00b7: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || !Plugin.IsServer() || !instance.AutoProcessEnabledValue || !EnsurePrefabMaps() || ZDOMan.instance == null || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < nextTick)
			{
				return;
			}
			nextTick = realtimeSinceStartup + 2f;
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			int peerCount = peers?.Count ?? 0;
			int num = 0;
			int num2 = 0;
			SeenStations.Clear();
			DiscoverySectorKeys.Clear();
			if (peers != null)
			{
				for (int i = 0; i < peers.Count; i++)
				{
					ZNetPeer val = peers[i];
					if (val == null)
					{
						continue;
					}
					Vector2s zone = ZoneSystem.GetZone(val.m_refPos);
					long item = ((long)zone.x << 32) ^ (uint)zone.y;
					if (!DiscoverySectorKeys.Add(item))
					{
						continue;
					}
					DiscoveryObjects.Clear();
					ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(1, 0, false), DiscoveryObjects, (List<ZDO>)null);
					num += DiscoveryObjects.Count;
					for (int j = 0; j < DiscoveryObjects.Count; j++)
					{
						ZDO val2 = DiscoveryObjects[j];
						if (val2 != null && val2.IsValid() && ProcessorPrefabs.TryGetValue(val2.GetPrefab(), out var value) && !((Object)(object)value == (Object)null) && SeenStations.Add(val2.m_uid))
						{
							num2++;
							try
							{
								ProcessStation(value, val2, instance);
							}
							catch (Exception ex)
							{
								instance.LogAutoProcessError("Dedicated-server processor pass failed: " + ex.Message);
							}
						}
					}
				}
			}
			DiscoveryObjects.Clear();
			DiscoverySectorKeys.Clear();
			if (realtimeSinceStartup >= nextDiscoveryLog)
			{
				nextDiscoveryLog = realtimeSinceStartup + 10f;
				instance.LogAutoProcessDiscovery(peerCount, num, num2);
			}
		}

		internal static void ProcessSmelter(Smelter smelter)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)smelter == (Object)null || !Plugin.IsServer() || !instance.AutoProcessEnabledValue || !EnsurePrefabMaps())
			{
				return;
			}
			ZNetView stationNetView = GetStationNetView(smelter);
			if (!((Object)(object)stationNetView == (Object)null) && stationNetView.IsValid())
			{
				ZDO zDO = stationNetView.GetZDO();
				if (zDO != null && zDO.IsValid())
				{
					ProcessStation(smelter, zDO, instance);
				}
			}
		}

		private static void ProcessStation(Smelter smelter, ZDO stationZdo, Plugin plugin)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_0142: 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_01a1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)smelter == (Object)null || stationZdo == null || (Object)(object)plugin == (Object)null)
			{
				return;
			}
			try
			{
				int prefab = stationZdo.GetPrefab();
				if (LoggedProcessorPrefabs.Add(prefab))
				{
					plugin.LogAutoProcessStation(smelter, prefab);
				}
			}
			catch
			{
			}
			float autoProcessRangeValue = plugin.AutoProcessRangeValue;
			if (autoProcessRangeValue <= 0f)
			{
				return;
			}
			long stationCreator = stationZdo.GetLong(ZDOVars.s_creator, 0L);
			BuildNearbyList(stationZdo.GetPosition(), autoProcessRangeValue, stationCreator);
			if (Nearby.Count == 0)
			{
				LogWaitRateLimited(plugin, stationZdo, "no eligible buildable source chest within " + autoProcessRangeValue.ToString("0.#") + "m");
				return;
			}
			long owner = stationZdo.GetOwner();
			if (!OwnerAutomationBridge.CanRun(owner))
			{
				LogWaitRateLimited(plugin, stationZdo, "waiting for updated QoL on the processor owner; no items removed");
				return;
			}
			List<ZDOID> list = new List<ZDOID>();
			int num = 0;
			for (int i = 0; i < Nearby.Count; i++)
			{
				if (list.Count >= 64)
				{
					break;
				}
				ZDO val = Nearby[i];
				if (val.GetOwner() == owner)
				{
					list.Add(val.m_uid);
				}
				else if (num < 2 && RequestHandoff(stationZdo, val, autoProcessRangeValue, plugin))
				{
					num++;
				}
			}
			if (list.Count == 0)
			{
				LogWaitRateLimited(plugin, stationZdo, "waiting for a closed source chest handoff; updated QoL and loaded station/chest required on both owners; no items removed");
				return;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(1);
			val2.Write(stationZdo.m_uid);
			val2.Write(autoProcessRangeValue);
			val2.Write(plugin.MaxFuelTransfersPerTickValue);
			val2.Write(plugin.MaxOreTransfersPerTickValue);
			val2.Write(plugin.LeaveAtLeastFuelValue);
			val2.Write(plugin.LeaveAtLeastOreValue);
			val2.Write(list.Count);
			for (int j = 0; j < list.Count; j++)
			{
				val2.Write(list[j]);
			}
			OwnerAutomationBridge.Dispatch(stationZdo, val2);
		}

		private static bool OwnerCanLoad(long owner, ZDO station, ZDO chest)
		{
			//IL_001b: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (owner == ZDOMan.GetSessionID())
			{
				if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.FindInstance(station.m_uid) != (Object)null)
				{
					return (Object)(object)ZNetScene.instance.FindInstance(chest.m_uid) != (Object)null;
				}
				return false;
			}
			ZNetPeer val = OwnerAutomationBridge.FindPeer(owner);
			if (val != null && val.IsReady() && ZNetScene.InActiveArea(station.GetPosition(), val.GetRefPos()))
			{
				return ZNetScene.InActiveArea(chest.GetPosition(), val.GetRefPos());
			}
			return false;
		}

		private static bool RequestHandoff(ZDO station, ZDO chest, float range, Plugin plugin)
		{
			//IL_00a1: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			long owner = station.GetOwner();
			long owner2 = chest.GetOwner();
			if (!OwnerAutomationBridge.CanHandoff(owner2) || !OwnerAutomationBridge.CanHandoff(owner) || !OwnerCanLoad(owner2, station, chest) || !OwnerCanLoad(owner, station, chest))
			{
				return false;
			}
			if (Math.Ceiling(station.GetFloat(ZDOVars.s_fuel, 0f)) >= (double)ProcessorPrefabs[station.GetPrefab()].m_maxFuel && station.GetInt(ZDOVars.s_queued, 0) >= ProcessorPrefabs[station.GetPrefab()].m_maxOre)
			{
				return false;
			}
			long ticks = ZNet.instance.GetTime().Ticks;
			if (Handoffs.TryGetValue(chest.m_uid, out var value) && !StoreLease.CanDispatch(ticks, value.Deadline))
			{
				return false;
			}
			if (nextHandoffToken == int.MaxValue)
			{
				return false;
			}
			long num = OwnerAutomationBridge.FindPeer(owner)?.m_playerID ?? 0;
			Handoff handoff = new Handoff();
			handoff.Token = ++nextHandoffToken;
			handoff.Owner = owner2;
			handoff.Deadline = ticks + 100000000;
			handoff.Station = station.m_uid;
			Handoff handoff2 = handoff;
			Handoffs[chest.m_uid] = handoff2;
			ZPackage val = new ZPackage();
			val.Write(station.m_uid);
			val.Write(chest.m_uid);
			val.Write(handoff2.Token);
			val.Write(handoff2.Deadline);
			val.Write(owner);
			val.Write(num);
			val.Write(range);
			val.Write(plugin.LeaveAtLeastFuelValue);
			val.Write(plugin.LeaveAtLeastOreValue);
			if (OwnerAutomationBridge.DispatchHandoff(owner2, val))
			{
				return true;
			}
			handoff2.Deadline = 0L;
			return false;
		}

		internal static void OnHandoffResult(long sender, ZPackage result)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.IsServer() || (Object)(object)Plugin.Instance == (Object)null || result == null)
			{
				return;
			}
			try
			{
				result.SetPos(0);
				ZDOID val = result.ReadZDOID();
				int reportedToken = result.ReadInt();
				string text = result.ReadString();
				if (Handoffs.TryGetValue(val, out var value) && StoreLease.Matches(value.Token, value.Owner, reportedToken, sender))
				{
					ZDO val2 = ((ZDOMan.instance == null) ? null : ZDOMan.instance.GetZDO(value.Station));
					if (val2 != null)
					{
						LogWaitRateLimited(Plugin.Instance, val2, string.Concat("source chest ", val, " handoff=", text));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.LogAutoProcessError("Invalid chest handoff result: " + ex.Message);
			}
		}

		private static void BuildNearbyList(Vector3 stationPosition, float range, long stationCreator)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			Nearby.Clear();
			SectorObjects.Clear();
			if (ZDOMan.instance == null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return;
			}
			Vector2s zone = ZoneSystem.GetZone(stationPosition);
			ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(1, 0, false), SectorObjects, (List<ZDO>)null);
			float num = range * range;
			for (int i = 0; i < SectorObjects.Count; i++)
			{
				ZDO val = SectorObjects[i];
				if (val == null || !val.IsValid() || !BuildableContainerPrefabs.TryGetValue(val.GetPrefab(), out var value) || (Object)(object)value == (Object)null || val.GetInt(ZDOVars.s_inUse, 0) != 0 || val.GetBool("RHSQOL_RustyBackpack", false) || val.GetBool("RHSQOL_RustyBackpack_Grave", false))
				{
					continue;
				}
				Vector3 val2 = val.GetPosition() - stationPosition;
				if (!(((Vector3)(ref val2)).sqrMagnitude > num))
				{
					long chestCreator = val.GetLong(ZDOVars.s_creator, 0L);
					if (CanUseContainer(value, stationCreator, chestCreator))
					{
						Nearby.Add(val);
					}
				}
			}
			SectorObjects.Clear();
		}

		private static bool CanUseContainer(Container prefab, long stationCreator, long chestCreator)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			if ((int)prefab.m_privacy == 0)
			{
				if (stationCreator != 0)
				{
					return chestCreator == stationCreator;
				}
				return false;
			}
			return true;
		}

		private static bool EnsurePrefabMaps()
		{
			if (prefabMapsReady)
			{
				return true;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.m_prefabs == null || ZNetScene.instance.m_prefabs.Count == 0)
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null || ObjectDB.instance.m_items.Count == 0)
			{
				return false;
			}
			ProcessorPrefabs.Clear();
			BuildableContainerPrefabs.Clear();
			for (int i = 0; i < ZNetScene.instance.m_prefabs.Count; i++)
			{
				GameObject val = ZNetScene.instance.m_prefabs[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Smelter val2 = val.GetComponent<Smelter>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = val.GetComponentInChildren<Smelter>();
				}
				if (!((Object)(object)val2 == (Object)null))
				{
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
					if (!ProcessorPrefabs.ContainsKey(stableHashCode))
					{
						ProcessorPrefabs.Add(stableHashCode, val2);
					}
				}
			}
			for (int j = 0; j < ObjectDB.instance.m_items.Count; j++)
			{
				GameObject val3 = ObjectDB.instance.m_items[j];
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				ItemDrop component = val3.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
				{
					continue;
				}
				PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
				if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
				{
					continue;
				}
				for (int k = 0; k < buildPieces.m_pieces.Count; k++)
				{
					GameObject val4 = buildPieces.m_pieces[k];
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					Container val5 = val4.GetComponent<Container>();
					if ((Object)(object)val5 == (Object)null)
					{
						val5 = val4.GetComponentInChildren<Container>();
					}
					if ((Object)(object)val5 == (Object)null || (Object)(object)val5.m_wagon != (Object)null || val5.m_autoDestroyEmpty)
					{
						continue;
					}
					string text = ((((Object)val4).name == null) ? "" : ((Object)val4).name);
					if (text.IndexOf("private", StringComparison.OrdinalIgnoreCase) < 0)
					{
						int stableHashCode2 = StringExtensionMethods.GetStableHashCode(text);
						if (!BuildableContainerPrefabs.ContainsKey(stableHashCode2))
						{
							BuildableContainerPrefabs.Add(stableHashCode2, val5);
						}
					}
				}
			}
			prefabMapsReady = ProcessorPrefabs.Count > 0 && BuildableContainerPrefabs.Count > 0;
			if (prefabMapsReady && !registryLogged)
			{
				registryLogged = true;
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.LogAutoProcessRegistry(ProcessorPrefabs.Count, BuildableContainerPrefabs.Count);
				}
			}
			return prefabMapsReady;
		}

		private static void LogWaitRateLimited(Plugin plugin, ZDO stationZdo, string reason)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)plugin == (Object)null) && stationZdo != null)
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!LastWaitLog.TryGetValue(stationZdo.m_uid, out var value) || !(realtimeSinceStartup - value < 10f))
				{
					LastWaitLog[stationZdo.m_uid] = realtimeSinceStartup;
					plugin.LogAutoProcessWait(stationZdo, reason);
				}
			}
		}

		private static ZNetView GetStationNetView(Smelter smelter)
		{
			if ((Object)(object)smelter == (Object)null)
			{
				return null;
			}
			ZNetView val = null;
			try
			{
				val = ((Component)smelter).GetComponent<ZNetView>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)smelter).GetComponentInParent<ZNetView>();
				}
			}
			catch
			{
			}
			return val;
		}
	}
	internal static class AutoStoreModule
	{
		private sealed class DropEntry
		{
			internal ZDOID Id;

			internal float RegisteredAt;

			internal float EarliestAttempt;

			internal int OwnerCursor;

			internal int PendingToken;

			internal long PendingOwner;

			internal long PendingDeadline;
		}

		private sealed class ChestSectorCacheEntry
		{
			internal float ExpiresAt;

			internal readonly List<ZDOID> ChestIds = new List<ZDOID>();
		}

		private static readonly List<DropEntry> Drops = new List<DropEntry>();

		private static readonly Dictionary<int, ItemDrop> ItemPrefabs = new Dictionary<int, ItemDrop>();

		private static readonly Dictionary<int, Container> BuildableContainerPrefabs = new Dictionary<int, Container>();

		private static readonly List<ZDO> SectorObjects = new List<ZDO>();

		private static readonly Dictionary<string, float> LastWaitLogByItem = new Dictionary<string, float>();

		private static readonly Dictionary<long, ChestSectorCacheEntry> ChestSectorCache = new Dictionary<long, ChestSectorCacheEntry>();

		private static readonly HashSet<long> DiscoverySectorKeys = new HashSet<long>();

		private static float nextTick;

		private static float nextDiscovery;

		private static float nextDiscoveryLog;

		private static float nextPrune;

		private static int cursor;

		private static bool prefabMapsReady;

		private static bool registryLogged;

		private static int nextToken;

		internal static void Clear()
		{
			Drops.Clear();
			ItemPrefabs.Clear();
			BuildableContainerPrefabs.Clear();
			SectorObjects.Clear();
			LastWaitLogByItem.Clear();
			ChestSectorCache.Clear();
			DiscoverySectorKeys.Clear();
			nextTick = 0f;
			nextDiscovery = 0f;
			nextDiscoveryLog = 0f;
			nextPrune = 0f;
			cursor = 0;
			prefabMapsReady = false;
			registryLogged = false;
			nextToken = 0;
		}

		internal static void ObserveZdo(ZDO zdo)
		{
			if (zdo != null && EnsurePrefabMaps() && ItemPrefabs.ContainsKey(zdo.GetPrefab()))
			{
				RegisterDrop(zdo);
			}
		}

		internal static void RegisterDrop(ItemDrop drop)
		{
			if ((Object)(object)drop == (Object)null)
			{
				return;
			}
			try
			{
				ZNetView component = ((Component)drop).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					ObserveZdo(component.GetZDO());
				}
			}
			catch
			{
			}
		}

		private static void RegisterDrop(ZDO zdo)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			if (zdo == null || !zdo.IsValid() || !IsRecentGroundDrop(zdo))
			{
				return;
			}
			ZDOID uid = zdo.m_uid;
			for (int i = 0; i < Drops.Count; i++)
			{
				if (Drops[i] != null && Drops[i].Id == uid)
				{
					return;
				}
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			DropEntry dropEntry = new DropEntry();
			dropEntry.Id = uid;
			dropEntry.RegisteredAt = realtimeSinceStartup;
			dropEntry.EarliestAttempt = realtimeSinceStartup + 1f;
			Drops.Add(dropEntry);
		}

		internal static void Tick()
		{
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || !Plugin.IsServer() || !instance.AutoStoreEnabledValue || !EnsurePrefabMaps())
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= nextDiscovery)
			{
				nextDiscovery = realtimeSinceStartup + 8f;
				DiscoverNearbyDrops();
			}
			if (realtimeSinceStartup < nextTick)
			{
				return;
			}
			nextTick = realtimeSinceStartup + 0.5f;
			Prune(realtimeSinceStartup);
			if (Drops.Count == 0)
			{
				return;
			}
			int num = instance.AutoStoreMaxDropsPerTickValue;
			if (num > Drops.Count)
			{
				num = Drops.Count;
			}
			int count = Drops.Count;
			int num2 = 0;
			int num3 = 0;
			long now = (((Object)(object)ZNet.instance == (Object)null) ? 0 : ZNet.instance.GetTime().Ticks);
			while (num2 < count && num3 < num && Drops.Count > 0)
			{
				if (cursor >= Drops.Count)
				{
					cursor = 0;
				}
				DropEntry dropEntry = Drops[cursor];
				cursor++;
				num2++;
				if (dropEntry == null || realtimeSinceStartup < dropEntry.EarliestAttempt || !StoreLease.CanDispatch(now, dropEntry.PendingDeadline))
				{
					continue;
				}
				ZDO val = ((ZDOMan.instance == null) ? null : ZDOMan.instance.GetZDO(dropEntry.Id));
				if (val == null || !val.IsValid() || !HasActiveStoreClient(val))
				{
					continue;
				}
				num3++;
				bool flag = false;
				try
				{
					flag = TryStore(dropEntry, val, instance, realtimeSinceStartup);
				}
				catch (Exception ex)
				{
					instance.LogAutoStoreError("Ground-drop transfer failed: " + ex.Message);
				}
				if (flag)
				{
					int num4 = Drops.IndexOf(dropEntry);
					if (num4 >= 0)
					{
						if (num4 < cursor)
						{
							cursor--;
						}
						Drops.RemoveAt(num4);
						if (cursor < 0)
						{
							cursor = 0;
						}
					}
				}
				else
				{
					dropEntry.EarliestAttempt = Math.Max(dropEntry.EarliestAttempt, realtimeSinceStartup + 1f);
				}
			}
		}

		private static bool HasActiveStoreClient(ZDO drop)
		{
			if (CanOwnerLoad(drop, ZDOMan.GetSessionID()))
			{
				return true;
			}
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			if (peers == null)
			{
				return false;
			}
			for (int i = 0; i < peers.Count; i++)
			{
				ZNetPeer val = peers[i];
				if (val != null && OwnerAutomationBridge.CanStore(val.m_uid) && CanOwnerLoad(drop, val.m_uid))
				{
					return true;
				}
			}
			return false;
		}

		private static bool CanOwnerLoad(ZDO zdo, long owner)
		{
			//IL_0020: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null)
			{
				return false;
			}
			if (owner == ZDOMan.GetSessionID())
			{
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					return (Object)(object)ZNetScene.instance.FindInstance(zdo.m_uid) != (Object)null;
				}
				return false;
			}
			ZNetPeer val = OwnerAutomationBridge.FindPeer(owner);
			if (val != null && val.IsReady())
			{
				return ZNetScene.InActiveArea(zdo.GetPosition(), val.GetRefPos());
			}
			return false;
		}

		private static bool EnsurePrefabMaps()
		{
			if (prefabMapsReady)
			{
				return true;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.m_prefabs == null || ZNetScene.instance.m_prefabs.Count == 0)
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null || ObjectDB.instance.m_items.Count == 0)
			{
				return false;
			}
			ItemPrefabs.Clear();
			BuildableContainerPrefabs.Clear();
			for (int i = 0; i < ZNetScene.instance.m_prefabs.Count; i++)
			{
				GameObject val = ZNetScene.instance.m_prefabs[i];
				if (!((Object)(object)val == (Object)null))
				{
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
					ItemDrop val2 = val.GetComponent<ItemDrop>();
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = val.GetComponentInChildren<ItemDrop>();
					}
					if ((Object)(object)val2 != (Object)null && !ItemPrefabs.ContainsKey(stableHashCode))
					{
						ItemPrefabs.Add(stableHashCode, val2);
					}
				}
			}
			for (int j = 0; j < ObjectDB.instance.m_items.Count; j++)
			{
				GameObject val3 = ObjectDB.instance.m_items[j];
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				ItemDrop component = val3.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
				{
					continue;
				}
				PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
				if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
				{
					continue;
				}
				for (int k = 0; k < buildPieces.m_pieces.Count; k++)
				{
					GameObject val4 = buildPieces.m_pieces[k];
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					Container val5 = val4.GetComponent<Container>();
					if ((Object)(object)val5 == (Object)null)
					{
						val5 = val4.GetComponentInChildren<Container>();
					}
					if ((Object)(object)val5 == (Object)null || (Object)(object)val5.m_wagon != (Object)null || val5.m_autoDestroyEmpty)
					{
						continue;
					}
					string text = ((((Object)val4).name == null) ? "" : ((Object)val4).name);
					if (text.IndexOf("private", StringComparison.OrdinalIgnoreCase) < 0)
					{
						int stableHashCode2 = StringExtensionMethods.GetStableHashCode(text);
						if (!BuildableContainerPrefabs.ContainsKey(stableHashCode2))
						{
							BuildableContainerPrefabs.Add(stableHashCode2, val5);
						}
					}
				}
			}
			if (BuildableContainerPrefabs.Count == 0)
			{
				for (int l = 0; l < ZNetScene.instance.m_prefabs.Count; l++)
				{
					GameObject val6 = ZNetScene.instance.m_prefabs[l];
					if ((Object)(object)val6 == (Object)null)
					{
						continue;
					}
					Piece val7 = val6.GetComponent<Piece>();
					if ((Object)(object)val7 == (Object)null)
					{
						val7 = val6.GetComponentInChildren<Piece>();
					}
					if ((Object)(object)val7 == (Object)null)
					{
						continue;
					}
					Container val8 = val6.GetComponent<Container>();
					if ((Object)(object)val8 == (Object)null)
					{
						val8 = val6.GetComponentInChildren<Container>();
					}
					if ((Object)(object)val8 == (Object)null || (Object)(object)val8.m_wagon != (Object)null || val8.m_autoDestroyEmpty)
					{
						continue;
					}
					string text2 = ((((Object)val6).name == null) ? "" : ((Object)val6).name);
					if (text2.IndexOf("private", StringComparison.OrdinalIgnoreCase) < 0)
					{
						int stableHashCode3 = StringExtensionMethods.GetStableHashCode(text2);
						if (!BuildableContainerPrefabs.ContainsKey(stableHashCode3))
						{
							BuildableContainerPrefabs.Add(stableHashCode3, val8);
						}
					}
				}
			}
			prefabMapsReady = ItemPrefabs.Count > 0 && BuildableContainerPrefabs.Count > 0;
			if (prefabMapsReady && !registryLogged)
			{
				registryLogged = true;
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.LogAutoStoreRegistry(ItemPrefabs.Count, BuildableContainerPrefabs.Count);
				}
			}
			return prefabMapsReady;
		}

		private static void DiscoverNearbyDrops()
		{
			//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_0073: 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_009e: 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 (ZDOMan.instance == null || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			int peerCount = peers?.Count ?? 0;
			int num = 0;
			int num2 = 0;
			DiscoverySectorKeys.Clear();
			if (peers != null)
			{
				for (int i = 0; i < peers.Count; i++)
				{
					ZNetPeer val = peers[i];
					if (val == null)
					{
						continue;
					}
					Vector2s zone = ZoneSystem.GetZone(val.m_refPos);
					long item = SectorKey(zone);
					if (!DiscoverySectorKeys.Add(item))
					{
						continue;
					}
					SectorObjects.Clear();
					ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(1, 0, false), SectorObjects, (List<ZDO>)null);
					num += SectorObjects.Count;
					for (int j = 0; j < SectorObjects.Count; j++)
					{
						ZDO val2 = SectorObjects[j];
						if (val2 != null && val2.IsValid() && ItemPrefabs.ContainsKey(val2.GetPrefab()))
						{
							num2++;
							RegisterDrop(val2);
						}
					}
				}
			}
			SectorObjects.Clear();
			DiscoverySectorKeys.Clear();
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= nextDiscoveryLog)
			{
				nextDiscoveryLog = realtimeSinceStartup + 10f;
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.LogAutoStoreDiscovery(peerCount, num, num2, Drops.Count);
				}
			}
		}

		private static bool TryStore(DropEntry entry, ZDO dropZdo, Plugin plugin, float now)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Invalid comparison between Unknown and I4
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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)
			if (entry == null || dropZdo == null || (Object)(object)plugin == (Object)null)
			{
				return false;
			}
			long num = (((Object)(object)ZNet.instance == (Object)null) ? 0 : ZNet.instance.GetTime().Ticks);
			if (!StoreLease.CanDispatch(num, entry.PendingDeadline))
			{
				return false;
			}
			if (!ItemPrefabs.TryGetValue(dropZdo.GetPrefab(), out var value) || (Object)(object)value == (Object)null)
			{
				return false;
			}
			ItemData val = LoadItemData(value, dropZdo);
			if (val == null || val.m_shared == null)
			{
				return false;
			}
			bool isPiece = dropZdo.GetBool(ZDOVars.s_piece, false);
			bool isConsumable = (int)val.m_shared.m_itemType == 2;
			if (!ServerQoLRules.ShouldAutoStoreItem(plugin.AutoStoreEnabledValue, autoPickup: true, isPiece, val.m_shared.m_maxStackSize, isConsumable))
			{
				return false;
			}
			int stack = val.m_stack;
			if (stack <= 0)
			{
				return false;
			}
			Vector3 position = dropZdo.GetPosition();
			float autoStoreMinPlayerDistanceValue = plugin.AutoStoreMinPlayerDistanceValue;
			bool playerInRange = autoStoreMinPlayerDistanceValue > 0f && IsAnyPeerInRange(position, autoStoreMinPlayerDistanceValue);
			float ageSeconds = now - entry.RegisteredAt;
			if (ServerQoLRules.IsPlayerProtectionActive(ageSeconds, plugin.AutoStorePlayerProtectionSecondsValue, playerInRange))
			{
				return false;
			}
			if (!FindTargetDirect(entry, dropZdo, position, plugin.AutoStoreRangeValue, out var owner, out var candidates, out var diagnostic))
			{
				LogWaitRateLimited(plugin, val.m_shared.m_name, diagnostic, now);
				return false;
			}
			if (nextToken == int.MaxValue)
			{
				nextToken = 0;
			}
			entry.PendingToken = ++nextToken;
			entry.PendingOwner = owner;
			entry.PendingDeadline = num + 100000000;
			ZPackage val2 = new ZPackage();
			val2.Write(dropZdo.m_uid);
			val2.Write(entry.PendingToken);
			val2.Write(entry.PendingDeadline);
			val2.Write(plugin.AutoStoreRangeValue);
			val2.Write(candidates.Count);
			foreach (ZDOID item in candidates)
			{
				val2.Write(item);
			}
			if (!OwnerAutomationBridge.DispatchStore(owner, val2))
			{
				entry.PendingDeadline = 0L;
				LogWaitRateLimited(plugin, val.m_shared.m_name, "waiting for a connected AutoStore v3 chest owner", now);
			}
			entry.EarliestAttempt = now + 1f;
			return false;
		}

		private static bool FindTargetDirect(DropEntry entry, ZDO drop, Vector3 position, float range, out long owner, out List<ZDOID> candidates, out string diagnostic)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			owner = 0L;
			candidates = null;
			diagnostic = "no nearby eligible buildable chest";
			if (ZDOMan.instance == null || (Object)(object)ZoneSystem.instance == (Object)null || range <= 0f)
			{
				return false;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			foreach (ZDOID cachedChestId in GetCachedChestIds(ZoneSystem.GetZone(position), Time.realtimeSinceStartup))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(cachedChestId);
				if (zDO == null || !zDO.IsValid() || !BuildableContainerPrefabs.ContainsKey(zDO.GetPrefab()))
				{
					continue;
				}
				Vector3 val = zDO.GetPosition() - position;
				if (((Vector3)(ref val)).sqrMagnitude > range * range)
				{
					continue;
				}
				num++;
				if (!zDO.GetBool("RHSQOL_RustyBackpack", false) && !zDO.GetBool("RHSQOL_RustyBackpack_Grave", false))
				{
					if (zDO.GetInt(ZDOVars.s_inUse, 0) != 0)
					{
						num2++;
					}
					else if (!OwnerAutomationBridge.CanStore(zDO.GetOwner()))
					{
						num3++;
					}
					else if (!CanOwnerLoad(drop, zDO.GetOwner()) || !CanOwnerLoad(zDO, zDO.GetOwner()))
					{
						num4++;
					}
					else
					{
						list.Add(zDO);
					}
				}
			}
			list.Sort(delegate(ZDO a, ZDO b)
			{
				//IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = a.GetPosition() - position;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				Vector3 val3 = b.GetPosition() - position;
				return sqrMagnitude.CompareTo(((Vector3)(ref val3)).sqrMagnitude);
			});
			List<long> list2 = new List<long>();
			foreach (ZDO item in list)
			{
				if (item.GetOwner() == drop.GetOwner())
				{
					list2.Add(drop.GetOwner());
					break;
				}
			}
			foreach (ZDO item2 in list)
			{
				if (!list2.Contains(item2.GetOwner()))
				{
					list2.Add(item2.GetOwner());
				}
			}
			if (list2.Count == 0)
			{
				diagnostic = "nearbyChests=" + num + " openChests=" + num2 + " ownersWithoutAutoStoreV3=" + num3 + " ownersOutsideLoadedArea=" + num4 + " range=" + range.ToString("0.#") + "m";
				return false;
			}
			owner = list2[entry.OwnerCursor % list2.Count];
			entry.OwnerCursor = (entry.OwnerCursor + 1) % list2.Count;
			candidates = new List<ZDOID>();
			foreach (ZDO item3 in list)
			{
				if (item3.GetOwner() == owner && candidates.Count < 64)
				{
					candidates.Add(item3.m_uid);
				}
			}
			return candidates.Count > 0;
		}

		internal static void OnResult(long sender, ZPackage result)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b4: 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)
			if (!Plugin.IsServer() || result == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			try
			{
				result.SetPos(0);
				ZDOID dropId = result.ReadZDOID();
				int reportedToken = result.ReadInt();
				string text = result.ReadString();
				int num = result.ReadInt();
				ZDOID val = result.ReadZDOID();
				DropEntry dropEntry = Drops.Find((DropEntry d) => d != null && d.Id == dropId);
				if (dropEntry != null && StoreLease.Matches(dropEntry.PendingToken, dropEntry.PendingOwner, reportedToken, sender))
				{
					if (text == "stored" && num > 0)
					{
						Plugin.Instance.LogOwnerAutomation(string.Concat("STORED live-owner drop=", dropId, " count=", num, " chest=", val));
						dropEntry.EarliestAttempt = Math.Max(dropEntry.EarliestAttempt, Time.realtimeSinceStartup + 10f);
					}
					else
					{
						LogWaitRateLimited(Plugin.Instance, ((object)Unsafe.As<ZDOID, ZDOID>(ref dropId)/*cast due to .constrained prefix*/).ToString(), text + "; chestOwner=" + sender, Time.realtimeSinceStartup);
					}
				}
			}
			catch (Exception ex)
			{
				if ((Object)(object)Plugin.Instance != (Object)null)
				{
					Plugin.Instance.LogAutoStoreError("Invalid owner result: " + ex.Message);
				}
			}
		}

		private static long SectorKey(Vector2s sector)
		{
			return ((long)sector.x << 32) ^ (uint)sector.y;
		}

		private static List<ZDOID> GetCachedChestIds(Vector2s sector, float now)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			long key = SectorKey(sector);
			if (ChestSectorCache.TryGetValue(key, out var value) && value != null && now < value.ExpiresAt)
			{
				return value.ChestIds;
			}
			if (value == null)
			{
				value = new ChestSectorCacheEntry();
			}
			if (ChestSectorCache.Count > 256)
			{
				ChestSectorCache.Clear();
			}
			value.ChestIds.Clear();
			SectorObjects.Clear();
			ZDOMan.instance.FindSectorObjects(sector, new SimulationDistance(1, 0, false), SectorObjects, (List<ZDO>)null);
			for (int i = 0; i < SectorObjects.Count; i++)
			{
				ZDO val = SectorObjects[i];
				if (val != null && val.IsValid() && BuildableContainerPrefabs.ContainsKey(val.GetPrefab()))
				{
					value.ChestIds.Add(val.m_uid);
				}
			}
			SectorObjects.Clear();
			value.ExpiresAt = now + 2f;
			ChestSectorCache[key] = value;
			return value.ChestIds;
		}

		private static bool IsRecentGroundDrop(ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			try
			{
				long num = zdo.GetLong(ZDOVars.s_spawnTime, 0L);
				if (num <= 0 || (Object)(object)ZNet.instance == (Object)null)
				{
					return true;
				}
				DateTime dateTime = new DateTime(num);
				double totalSeconds = (ZNet.instance.GetTime() - dateTime).TotalSeconds;
				if (totalSeconds < 0.0)
				{
					return true;
				}
				return totalSeconds <= 120.0;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsAnyPeerInRange(Vector3 position, float range)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			if (range <= 0f || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			if (peers == null || peers.Count == 0)
			{
				return false;
			}
			float num = range * range;
			for (int i = 0; i < peers.Count; i++)
			{
				ZNetPeer val = peers[i];
				if (val != null)
				{
					Vector3 val2 = val.m_refPos - position;
					if (((Vector3)(ref val2)).sqrMagnitude <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void LogWaitRateLimited(Plugin plugin, string itemName, string reason, float now)
		{
			if (!((Object)(object)plugin == (Object)null))
			{
				string text = (string.IsNullOrEmpty(itemName) ? "unknown" : itemName);
				if (!LastWaitLogByItem.TryGetValue(text, out var value) || !(now - value < 20f))
				{
					LastWaitLogByItem[text] = now;
					plugin.LogAutoStoreWait(text, reason);
				}
			}
		}

		private static ItemData LoadItemData(ItemDrop prefab, ZDO zdo)
		{
			if ((Object)(object)prefab == (Object)null || prefab.m_itemData == null || zdo == null)
			{
				return null;
			}
			try
			{
				ItemData val = prefab.m_itemData.Clone();
				val.m_dropPrefab = ((Component)prefab).gameObject;
				ItemDrop.LoadFromZDO(val, zdo, -1);
				return val;
			}
			catch
			{
				return null;
			}
		}

		private static void Prune(float now)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (now < nextPrune)
			{
				return;
			}
			nextPrune = now + 10f;
			if (ZDOMan.instance == null)
			{
				Drops.Clear();
				cursor = 0;
				return;
			}
			for (int num = Drops.Count - 1; num >= 0; num--)
			{
				DropEntry dropEntry = Drops[num];
				if (dropEntry == null || ZDOMan.instance.GetZDO(dropEntry.Id) == null)
				{
					Drops.RemoveAt(num);
				}
			}
			if (cursor > Drops.Count)
			{
				cursor = 0;
			}
		}
	}
	[HarmonyPatch(typeof(ZDO), "Deserialize")]
	internal static class AutoStoreZdoDeserializePatch
	{
		private static void Postfix(ZDO __instance)
		{
			if (Plugin.IsServer())
			{
				AutoStoreModule.ObserveZdo(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "Awake")]
	internal static class AutoStoreItemDropAwakePatch
	{
		private static void Postfix(ItemDrop __instance)
		{
			AutoStoreModule.RegisterDrop(__instance);
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "Start")]
	internal static class AutoStoreItemDropStartPatch
	{
		private static void Postfix(ItemDrop __instance)
		{
			AutoStoreModule.RegisterDrop(__instance);
		}
	}
}
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)
		{
			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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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();
				backpackDeathLocation.DeathPoint = report.ReadVector3();
				backpackDeathLocation.GraveId = report.ReadZDOID();
				backpackDeathLocation.GravePoint = report.ReadVector3();
				BackpackDeathLocation backpackDeathLocation2 = backpackDeathLocation;
				if (report.GetPos() != report.Size() || !Finite(backpackDeathLocation2.DeathPoint) || !Finite(backpackDeathLocation2.GravePoint))
				{
					return DeathLocationRead.Invalid;
				}
				if (!((ZDOID)(ref backpackDeathLocation2.GraveId)).IsNone())
				{
					Vector3 val = backpackDeathLocation2.GravePoint - backpackDeathLocation2.DeathPoint;
					if (((Vector3)(ref val)).sqrMagnitude > 16f)
					{
						return DeathLocationRead.Invalid;
					}
				}
				location = backpackDeathLocation2;
				return DeathLocationRead.Valid;
			}
			catch
			{
				return DeathLocationRead.Invalid;
			}
		}

		internal static bool IsInventoryGrave(ZDO grave, long playerId)
		{
			if (grave != null && grave.IsValid() && playerId != 0 && 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.ServerQoL
{
	internal static class BackpackModule
	{
		private sealed class DedicatedPlayerState
		{
			internal long PeerId;

			internal long PlayerId;

			internal ZDOID CharacterId = ZDOID.None;

			internal ZDOID BackpackId = ZDOID.None;

			internal int LastEmoteId = int.MinValue;

			internal bool LastDead;

			internal float OpenAt = -1f;

			internal int OpenAttemptsRemaining;

			internal float NextMaintenance;

			internal float PendingDeathAt = -1f;

			internal byte[] DeathSnapshot;

			internal ZDOID DeathSnapshotId = ZDOID.None;

			internal float NextAssigned;

			internal bool DeathConfirmed;

			internal bool HasDeathPoint;

			internal Vector3 DeathPoint;

			internal BackpackDeathLocation DeathLocation;
		}

		internal const string ArgusBackpackGuid = "ArgusMagnus.ServersideQoL.Backpack";

		internal const string ClientOpenRpc = "RHSQOL_BackpackOpen_v1";

		internal const string ClientAssignedRpc = "RHSQOL_BackpackAssigned_v2";

		internal const string RequestRpc = "RHSQOL_BackpackRequest_v2";

		internal const string DeathRpc = "RHSQOL_BackpackDeath_v2";

		private static readonly int MarkerKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack");

		private static readonly int PlayerKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Player");

		private static readonly int SlotsKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Slots");

		private static readonly int CanonicalKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Canonical");

		private static readonly int ArchivedKey = StringExtensionMethods.GetStableHashCode("RHSQOL_RustyBackpack_Archived");

		private static readonly List<ZDO> SearchZdos = new List<ZDO>();

		private static readonly string[] BossKeys = new string[7] { "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" };

		private static Container backpack;

		private static GameObject backpackObject;

		private static ZDOID backpackId = ZDOID.None;

		private static float openAt = -1f;

		private static float nextMaintenance;

		private static long lastPlayerId;

		private static long lastWorldUid;

		private static bool argusWarningLogged;

		private static readonly Dictionary<long, DedicatedPlayerState> DedicatedStates = new Dictionary<long, DedicatedPlayerState>();

		private static readonly HashSet<long> SeenDedicatedPeers = new HashSet<long>();

		private static float nextDedicatedTick;

		private static readonly Dictionary<long, ZDOID> CanonicalBackpacks = new Dictionary<long, ZDOID>();

		private static readonly HashSet<long> DuplicateWarnings = new HashSet<long>();

		private static bool globalLookupFailed;

		internal static bool ArgusBackpackPresent
		{
			get
			{
				if (Chainloader.PluginInfos != null)
				{
					return Chainloader.PluginInfos.ContainsKey("ArgusMagnus.ServersideQoL.Backpack");
				}
				return false;
			}
		}

		internal static void Clear()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			backpack = null;
			backpackObject = null;
			backpackId = ZDOID.None;
			openAt = -1f;
			nextMaintenance = 0f;
			lastPlayerId = 0L;
			lastWorldUid = 0L;
			argusWarningLogged = false;
			nextDedicatedTick = 0f;
			DedicatedStates.Clear();
			CanonicalBackpacks.Clear();
			DuplicateWarnings.Clear();
			SeenDedicatedPeers.Clear();
			SearchZdos.Clear();
		}

		internal static void RegisterRpc()
		{
			ZRoutedRpc.instance.Register<string>("RHSQOL_BackpackRequest_v2", (Action<long, string>)OnClientRequest);
			ZRoutedRpc.instance.Register<ZPackage>("RHSQOL_BackpackDeath_v2", (Action<long, ZPackage>)OnDeathSnapshot);
		}

		private static DedicatedPlayerState StateFor(ZNetPeer peer, ZDO player)
		{
			//IL_0046: 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_0089: 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)
			long num = player.GetLong(ZDOVars.s_playerID, 0L);
			if (!DedicatedStates.TryGetValue(peer.m_uid, out var value) || value.PlayerId != num)
			{
				DedicatedPlayerState dedicatedPlayerState = new DedicatedPlayerState();
				dedicatedPlayerState.PeerId = peer.m_uid;
				dedicatedPlayerState.PlayerId = num;
				dedicatedPlayerState.CharacterId = peer.m_characterID;
				dedicatedPlayerState.LastEmoteId = player.GetInt(ZDOVars.s_emoteID, 0);
				dedicatedPlayerState.LastDead = player.GetBool(ZDOVars.s_dead, false);
				value = dedicatedPlayerState;
				DedicatedStates[peer.m_uid] = value;
			}
			value.CharacterId = peer.m_characterID;
			return value;
		}

		private static void OnClientRequest(long sender, string request)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if (!ActivationAllowed(instance) || !Plugin.IsServer() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			ZNetPeer val = OwnerAutomationBridge.FindPeer(sender);
			if (val == null || !val.IsReady() || ((ZDOID)(ref val.m_characterID)).IsNone())
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID);
			if (zDO == null || zDO.GetBool(ZDOVars.s_dead, false) || zDO.GetLong(ZDOVars.s_playerID, 0L) == 0)
			{
				return;
			}
			bool flag = request == "open|" + instance.BackpackOpenEmoteValue;
			if (!flag && request != "resolve")
			{
				return;
			}
			DedicatedPlayerState dedicatedPlayerState = StateFor(val, zDO);
			if (!(dedicatedPlayerState.PendingDeathAt >= 0f) && EnsureDedicatedBackpack(dedicatedPlayerState, zDO, instance))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RHSQOL_BackpackAssigned_v2", new object[1] { dedicatedPlayerState.BackpackId });
				if (flag)
				{
					dedicatedPlayerState.OpenAttemptsRemaining = 6;
					dedicatedPlayerState.OpenAt = Time.realtimeSinceStartup;
					OpenDedicatedBackpack(dedicatedPlayerState, zDO, val, instance);
				}
			}
		}

		private static void OnDeathSnapshot(long sender, ZPackage report)
		{
			//IL_0046: 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_0074: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00f4: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if (!ActivationAllowed(instance) || !Plugin.IsServer() || report == null || ZDOMan.instance == null)
			{
				return;
			}
			ZNetPeer val = OwnerAutomationBridge.FindPeer(sender);
			if (val == null || !val.IsReady() || ((ZDOID)(ref val.m_characterID)).IsNone())
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID);
			if (zDO == null || zDO.GetLong(ZDOVars.s_playerID, 0L) == 0)
			{
				return;
			}
			DedicatedPlayerState dedicatedPlayerState = StateFor(val, zDO);
			ZDOID val2 = report.ReadZDOID();
			byte[] array = report.ReadByteArray();
			if (BackpackDeathPlacement.Read(report, val.m_characterID, out var location) == DeathLocationRead.Invalid)
			{
				instance.LogBackpackWarning("DEATH invalid or stale character location report; original backpack kept intact.");
				return;
			}
			ZDO zDO2 = ZDOMan.instance.GetZDO(val2);
			if (array != null && array.Length <= 2097152 && IsDedicatedBackpackFor(zDO2, dedicatedPlayerState.PlayerId) && (!CanonicalBackpacks.TryGetValue(dedicatedPlayerState.PlayerId, out var value) || !(value != val2)) && zDO2.GetOwner() == sender)
			{
				dedicatedPlayerState.BackpackId = val2;
				dedicatedPlayerState.DeathSnapshotId = val2;
				dedicatedPlayerState.DeathSnapshot = array;
				dedicatedPlayerState.DeathLocation = location;
				RememberDeathPoint(dedicatedPlayerState, zDO);
				dedicatedPlayerState.DeathConfirmed = dedicatedPlayerState.DeathConfirmed || zDO.GetBool(ZDOVars.s_dead, false);
				if (dedicatedPlayerState.PendingDeathAt < 0f)
				{
					dedicatedPlayerState.PendingDeathAt = Time.realtimeSinceStartup + 1f;
				}
			}
		}

		internal static bool ActivationAllowed(Plugin plugin)
		{
			if ((Object)(object)plugin == (Object)null || !plugin.BackpackEnabledValue)
			{
				return false;
			}
			if (ArgusBackpackPresent)
			{
				if (!argusWarningLogged)
				{
					argusWarningLogged = true;
					plugin.LogBackpackWarning("ArgusMagnus.ServersideQoL.Backpack is still loaded. Rusty Backpack is blocked to prevent two backpack systems from touching player storage. Remove the Argus Backpack add-on before using Rusty Backpack.");
				}
				return false;
			}
			return true;
		}

		internal static void Tick()
		{
			Plugin instance = Plugin.Instance;
			if (ActivationAllowed(instance) && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				if (ZNet.instance.IsDedicated())
				{
					TickDedicated(instance);
				}
				else
				{
					TickLocal(instance);
				}
			}
		}

		private static void TickLocal(Plugin plugin)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return;
			}
			if (openAt >= 0f && Time.realtimeSinceStartup >= openAt)
			{
				openAt = -1f;
				OpenBackpackNow(localPlayer, plugin);
			}
			if (!(Time.realtimeSinceStartup < nextMaintenance))
			{
				nextMaintenance = Time.realtimeSinceStartup + 1f;
				long playerID = localPlayer.GetPlayerID();
				long worldUID = ZNet.instance.GetWorldUID();
				if (playerID != lastPlayerId || worldUID != lastWorldUid)
				{
					ForgetRuntimeReference();
					lastPlayerId = playerID;
					lastWorldUid = worldUID;
				}
				if ((Object)(object)backpackObject != (Object)null)
				{
					FollowPlayer(localPlayer);
					EnsureCapacity(localPlayer, plugin);
				}
			}
		}

		private static void TickDedicated(Plugin plugin)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: 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)
			if (ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < nextDedicatedTick)
			{
				return;
			}
			nextDedicatedTick = realtimeSinceStartup + 0.1f;
			IList<ZNetPeer> list = new List<ZNetPeer>(ZNet.instance.GetPeers());
			SeenDedicatedPeers.Clear();
			for (int i = 0; i < list.Count; i++)
			{
				ZNetPeer val = list[i];
				if (val == null || !val.IsReady() || val.m_uid == 0 || ((ZDOID)(ref val.m_characterID)).IsNone())
				{
					continue;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID);
				if (zDO == null || !zDO.IsValid())
				{
					continue;
				}
				long num = zDO.GetLong(ZDOVars.s_playerID, 0L);
				if (num == 0)
				{
					continue;
				}
				SeenDedicatedPeers.Add(val.m_uid);
				DedicatedPlayerState dedicatedPlayerState = StateFor(val, zDO);
				bool flag = zDO.GetBool(ZDOVars.s_dead, false);
				int num2 = zDO.GetInt(ZDOVars.s_emoteID, 0);
				if (num2 != dedicatedPlayerState.LastEmoteId)
				{
					dedicatedPlayerState.LastEmoteId = num2;
					string a = zDO.GetString(ZDOVars.s_emote, string.Empty);
					if (!flag && dedicatedPlayerState.PendingDeathAt < 0f && string.Equals(a, plugin.BackpackOpenEmoteValue, StringComparison.OrdinalIgnoreCase) && EnsureDedicatedBackpack(dedicatedPlayerState, zDO, plugin))
					{
						dedicatedPlayerState.OpenAttemptsRemaining = 6;
						dedicatedPlayerState.OpenAt = realtimeSinceStartup + 0.25f;
						ZDO zDO2 = ZDOMan.instance.GetZDO(dedicatedPlayerState.BackpackId);
						if (zDO2 != null)
						{
							ZDOMan.instance.ForceSendZDO(val.m_uid, zDO2.m_uid);
						}
					}
				}
				if (flag && !dedicatedPlayerState.LastDead)
				{
					dedicatedPlayerState.DeathConfirmed = true;
					RememberDeathPoint(dedicatedPlayerState, zDO);
					if (dedicatedPlayerState.PendingDeathAt < 0f)
					{
						dedicatedPlayerState.PendingDeathAt = realtimeSinceStartup + 1f;
					}
				}
				dedicatedPlayerState.LastDead = flag;
				if (dedicatedPlayerState.PendingDeathAt >= 0f)
				{
					if (realtimeSinceStartup >= dedicatedPlayerState.PendingDeathAt && dedicatedPlayerState.DeathConfirmed)
					{
						HandleDedicatedDeath(dedicatedPlayerState, zDO, val, plugin);
						dedicatedPlayerState.PendingDeathAt = -1f;
						dedicatedPlayerState.DeathSnapshot = null;
						dedicatedPlayerState.DeathSnapshotId = ZDOID.None;
						dedicatedPlayerState.DeathConfirmed = false;
						dedicatedPlayerState.HasDeathPoint = false;
						dedicatedPlayerState.DeathLocation = null;
					}
					else
					{
						if (!(realtimeSinceStartup >= dedicatedPlayerState.PendingDeathAt + 3f))
						{
							continue;
						}
						dedicatedPlayerState.PendingDeathAt = -1f;
						dedicatedPlayerState.DeathSnapshot = null;
						dedicatedPlayerState.DeathSnapshotId = ZDOID.None;
						dedicatedPlayerState.DeathConfirmed = false;
						dedicatedPlayerState.HasDeathPoint = false;
						dedicatedPlayerState.DeathLocation = null;
					}
				}
				if (flag)
				{
					dedicatedPlayerState.OpenAt = -1f;
					dedicatedPlayerState.OpenAttemptsRemaining = 0;
					continue;
				}
				if (dedicatedPlayerState.OpenAt >= 0f && realtimeSinceStartup >= dedicatedPlayerState.OpenAt)
				{
					OpenDedicatedBackpack(dedicatedPlayerState, zDO, val, plugin);
					dedicatedPlayerState.OpenAttemptsRemaining--;
					dedicatedPlayerState.OpenAt = ((dedicatedPlayerState.OpenAttemptsRemaining > 0) ? (realtimeSinceStartup + 0.35f) : (-1f));
				}
				if (realtimeSinceStartup >= dedicatedPlayerState.NextMaintenance)
				{
					dedicatedPlayerState.NextMaintenance = realtimeSinceStartup + 1f;
					MaintainDedicatedBackpack(dedicatedPlayerState, zDO, val, plugin);
				}
			}
			if (DedicatedStates.Count <= SeenDedicatedPeers.Count)
			{
				return;
			}
			List<long> list2 = null;
			foreach (KeyValuePair<long, DedicatedPlayerState> dedicatedState in DedicatedStates)
			{
				if (!SeenDedicatedPeers.Contains(dedicatedState.Key))
				{
					if (list2 == null)
					{
						list2 = new List<long>();
					}
					list2.Add(dedicatedState.Key);
				}
			}
			if (list2 != null)
			{
				for (int j = 0; j < list2.Count; j++)
				{
					DedicatedStates.Remove(list2[j]);
				}
			}
		}

		private static bool EnsureDedicatedBackpack(DedicatedPlayerState state, ZDO playerZdo, Plugin plugin)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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)
			if (CanonicalBackpacks.TryGetValue(state.PlayerId, out var value))
			{
				state.BackpackId = value;
			}
			ZDO val = (((ZDOID)(ref state.BackpackId)).IsNone() ? null : ZDOMan.instance.GetZDO(state.BackpackId));
			if (val != null && val.IsValid() && !IsDedicatedBackpackFor(val, state.PlayerId))
			{
				return false;
			}
			if (IsDedicatedBackpackFor(val, state.PlayerId))
			{
				int desiredSlots = GetDesiredSlots(plugin);
				int num = val.GetInt(SlotsKey, 0);
				if (num < desiredSlots)
				{
					val = ResizeDedicatedBackpack(state, playerZdo, val, desiredSlots, plugin);
				}
				return val != null;
			}
			val = FindDedicatedBackpackGlobal(state.PlayerId, plugin);
			if (val != null)
			{
				state.BackpackId = val.m_uid;
				CanonicalBackpacks[state.PlayerId] = val.m_uid;
				int desiredSlots2 = GetDesiredSlots(plugin);
				int num2 = val.GetInt(SlotsKey, 0);
				if (num2 < desiredSlots2)
				{
					val = ResizeDedicatedBackpack(state, playerZdo, val, desiredSlots2, plugin);
				}
				return val != null;
			}
			if (globalLookupFailed)
			{
				return false;
			}
			int desiredSlots3 = GetDesiredSlots(plugin);
			ZDO val2 = CreateDedicatedBackpackZdo(playerZdo.GetPosition() + Vector3.down * 0.6f, state.PeerId, state.PlayerId, desiredSlots3, null, plugin);
			if (val2 == null)
			{
				return false;
			}
			state.BackpackId = val2.m_uid;
			CanonicalBackpacks[state.PlayerId] = val2.m_uid;
			if (plugin.VerboseLoggingValue)
			{
				plugin.LogBackpackInfo(string.Concat("CREATED dedicated backpack zdo=", val2.m_uid, " slots=", desiredSlots3, " playerId=", state.PlayerId, "."));
			}
			return true;
		}

		private static bool IsDedicatedBackpackFor(ZDO zdo, long playerId)
		{
			if (zdo != null && zdo.IsValid() && zdo.GetBool(MarkerKey, false) && !zdo.GetBool(ArchivedKey, false))
			{
				return zdo.GetLong(PlayerKey, 0L) == playerId;
			}
			return false;
		}

		private static ZDO FindDedicatedBackpackGlobal(long playerId, Plugin plugin)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: 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)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			globalLookupFailed = false;
			try
			{
				List<ZDOID> list = new List<ZDOID>(ZDOExtraData.GetAllZDOIDsWithHash((Type)4, PlayerKey));
				ZDO val = null;
				int num = -1;
				int num2 = 0;
				bool flag = false;
				List<ZDO> list2 = new List<ZDO>();
				for (int i = 0; i < list.Count; i++)
				{
					ZDO zDO = ZDOMan.instance.GetZDO(list[i]);
					if (!IsDedicatedBackpackFor(zDO, playerId))
					{
						continue;
					}
					num2++;
					list2.Add(zDO);
					int slots = Math.Max(1, zDO.GetInt(SlotsKey, plugin.BackpackInitialSlotsValue));
					GetStoredInventorySize(zDO, slots, out var width, out var height);
					int num3 = 0;
					try
					{
						Inventory val2 = LoadInventoryFromZdo(zDO, width, height);
						if (val2 != null)
						{
							num3 = val2.NrOfItems();
						}
					}
					catch (Exception innerException)
					{
						throw new InvalidOperationException(string.Concat("Could not read saved backpack ", zDO.m_uid, "; recovery must not create or archive storage."), innerException);
					}
					bool flag2 = zDO.GetBool(CanonicalKey, false);
					if (val == null || (flag2 && !flag) || (flag2 == flag && (num3 > num || (num3 == num && string.CompareOrdinal(((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).ToString()) < 0))))
					{
						val = zDO;
						num = num3;
						flag = flag2;
					}
				}
				if (val != null)
				{
					val.Set(CanonicalKey, true);
					foreach (ZDO item in list2)
					{
						if (!(item.m_uid == val.m_uid))
						{
							item.Set(CanonicalKey, false);
							item.Set(ArchivedKey, true);
						}
					}
				}
				if (num2 > 1 && DuplicateWarnings.Add(playerId))
				{
					plugin.LogBackpackWarning("Found " + num2 + " persistent Rusty Backpack ZDOs for playerId=" + playerId + ". The canonical-backpack recovery path preserves every other saved object and its contents.");
				}
				if (val != null && plugin.VerboseLoggingValue)
				{
					plugin.LogBackpackInfo(string.Concat("RECOVERED global dedicated backpack zdo=", val.m_uid, " playerId=", playerId, " itemStacks=", num, "."));
				}
				return val;
			}
			catch (Exception ex)
			{
				globalLookupFailed = true;
				plugin.LogBackpackWarning("Global backpack recovery failed for playerId=" + playerId + ": " + ex.Message);
				return null;
			}
		}

		private static ZDO CreateDedicatedBackpackZdo(Vector3 position, long peerId, long playerId, int slots, byte[] inventoryBytes, Plugin plugin)
		{
			//IL_005b: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = ZNetScene.instance.GetPrefab("piece_chest_private");
			if ((Object)(object)prefab == (Object)null)
			{
				prefab = ZNetScene.instance.GetPrefab("piece_chest_wood");
			}
			if ((Object)(object)prefab == (Object)null)
			{
				plugin.LogBackpackError("Could not find a vanilla chest prefab to host the dedicated Rusty backpack.");
				return null;
			}
			ServerQoLRules.GetBackpackInventorySize(slots, out var width, out var height);
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			ZDO val = ZDOMan.instance.CreateNewZDO(position, stableHashCode);
			if (val == null)
			{
				return null;
			}
			val.SetPrefab(stableHashCode);
			val.SetRotation(Quaternion.identity);
			val.Persistent = true;
			ZNetView component = prefab.GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				val.SetType(component.m_type);
			}
			val.SetDistant(true);
			val.Set(MarkerKey, true);
			val.Set(CanonicalKey, true);
			val.Set(PlayerKey, playerId);
			val.Set(SlotsKey, slots, false);
			val.Set(ZDOVars.s_addedDefaultItems, true);
			SetContainerCustomFields(val, width, height, "Rusty Backpack");
			if (inventoryBytes != null && inventoryBytes.Length > 0)
			{
				val.Set(ZDOVars.s_items, inventoryBytes);
			}
			val.SetOwner(peerId);
			ZDOMan.instance.ForceSendZDO(peerId, val.m_uid);
			return val;
		}

		private static void SetContainerCustomFields(ZDO zdo, int width, int height, string name)
		{
			zdo.Set("HasFields", true);
			zdo.Set("HasFieldsContainer", true);
			zdo.Set("Container.m_width", width);
			zdo.Set("Container.m_height", height);
			zdo.Set("Container.m_name", name);
			zdo.Set("Container.m_checkGuardStone", false);
			zdo.Set("Container.m_autoDestroyEmpty", false);
			zdo.Set("HasFieldsPiece", true);
			zdo.Set("Piece.m_canBeRemoved", false);
		}

		private static ZDO ResizeDedicatedBackpack(DedicatedPlayerState state, ZDO playerZdo, ZDO oldZdo, int desiredSlots, Plugin plugin)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			int num = Math.Max(1, oldZdo.GetInt("Container.m_width", 8));
			int height = Math.Max(oldZdo.GetInt("Container.m_height", 1), (desiredSlots + num - 1) / num);
			oldZdo.Set(SlotsKey, desiredSlots, false);
			SetContainerCustomFields(oldZdo, num, height, "Rusty Backpack");
			ZDOMan.instance.ForceSendZDO(state.PeerId, oldZdo.m_uid);
			return oldZdo;
		}

		private static void MaintainDedicatedBackpack(DedicatedPlayerState state, ZDO playerZdo, ZNetPeer peer, Plugin plugin)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0048: 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_005e: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureDedicatedBackpack(state, playerZdo, plugin))
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(state.BackpackId);
			if (zDO != null)
			{
				zDO.SetDistant(true);
				Vector3 val = playerZdo.GetPosition() + Vector3.down * 0.6f;
				Vector3 val2 = zDO.GetPosition() - val;
				if (((Vector3)(ref val2)).sqrMagnitude > 2.25f)
				{
					MoveDedicatedZdo(zDO, val, peer.m_uid);
				}
				if (zDO.GetOwner() != peer.m_uid)
				{
					zDO.SetOwner(peer.m_uid);
				}
				if (Time.realtimeSinceStartup >= state.NextAssigned)
				{
					state.NextAssigned = Time.realtimeSinceStartup + 5f;
					ZDOMan.instance.ForceSendZDO(peer.m_uid, zDO.m_uid);
					ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "RHSQOL_BackpackAssigned_v2", new object[1] { zDO.m_uid });
				}
			}
		}

		private static void MoveDedicatedZdo(ZDO zdo, Vector3 position, long peerId)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			zdo.SetPosition(position);
			ZDOMan.instance.ForceSendZDO(peerId, zdo.m_uid);
		}

		private static void OpenDedicatedBackpack(DedicatedPlayerState state, ZDO playerZdo, ZNetPeer peer, Plugin plugin)
		{
			//IL_0011: 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_0048: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureDedicatedBackpack(state, playerZdo, plugin))
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(state.BackpackId);
			if (zDO != null)
			{
				zDO.SetDistant(true);
				if (zDO.GetOwner() != peer.m_uid)
				{
					zDO.SetOwner(peer.m_uid);
				}
				MoveDedicatedZdo(zDO, playerZdo.GetPosition() + Vector3.down * 0.6f, peer.m_uid);
				ZDOMan.instance.ForceSendZDO(peer.m_uid, zDO.m_uid);
				ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "RHSQOL_BackpackOpen_v1", new object[1] { zDO.m_uid });
				if (plugin.VerboseLoggingValue)
				{
					plugin.LogBackpackInfo(string.Concat("OPEN-SENT dedicated backpack zdo=", zDO.m_uid, " player=", peer.m_playerName, " attemptsLeft=", state.OpenAttemptsRemaining, "."));
				}
			}
		}

		private static void GetStoredInventorySize(ZDO zdo, int slots, out int width, out int height)
		{
			ServerQoLRules.GetBackpackInventorySize(slots, out width, out height);
			width = Math.Max(1, zdo.GetInt("Container.m_width", width));
			height = Math.Max(1, zdo.GetInt("Container.m_height", height));
		}

		private static Inventory LoadInventoryFromZdo(ZDO zdo, int width, int height)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Inventory val = new Inventory("Rusty Backpack", (Sprite)null, width, height);
			byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null);
			if (byteArray != null && byteArray.Length > 0)
			{
				ZPackage val2 = new ZPackage();
				val2.Load(byteArray);
				val.Load(val2);
			}
			return val;
		}

		private static byte[] SaveInventoryBytes(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 void HandleDedicatedDeath(DedicatedPlayerState state, ZDO playerZdo, ZNetPeer peer, Plugin plugin)
		{
			//IL_0013: 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_004f: 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)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: 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_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: 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_03a0: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = (((ZDOID)(ref state.BackpackId)).IsNone() ? null : ZDOMan.instance.GetZDO(state.BackpackId));
			if (!IsDedicatedBackpackFor(val, state.PlayerId))
			{
				val = FindDedicatedBackpackGlobal(state.PlayerId, plugin);
			}
			if (val == null)
			{
				return;
			}
			if (state.DeathSnapshot == null || state.DeathSnapshotId != val.m_uid)
			{
				plugin.LogBackpackWarning("DEATH owner snapshot unavailable for " + peer.m_playerName + "; keeping the original backpack intact rather than destroying a possibly stale inventory.");
				return;
			}
			int slots = Math.Max(1, val.GetInt(SlotsKey, plugin.BackpackInitialSlotsValue));
			GetStoredInventorySize(val, slots, out var width, out var height);
			Inventory val2;
			if (state.DeathSnapshot != null && state.DeathSnapshotId == val.m_uid)
			{
				val2 = new Inventory("Rusty Backpack", (Sprite)null, width, height);
				ZPackage val3 = new ZPackage();
				val3.Load(state.DeathSnapshot);
				val2.Load(val3);
			}
			else
			{
				val2 = LoadInventoryFromZdo(val, width, height);
			}
			if (val2 == null || val2.NrOfItems() == 0)
			{
				if (plugin.VerboseLoggingValue)
				{
					plugin.LogBackpackInfo("DEATH backpack empty for " + peer.m_playerName + "; no Rusty Backpack tombstone needed.");
				}
				if (val2 != null)
				{
					DestroyDedicatedZdo(val);
					CanonicalBackpacks.Remove(state.PlayerId);
					state.BackpackId = ZDOID.None;
				}
				return;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("Player_tombstone");
			if ((Object)(object)prefab == (Object)null)
			{
				plugin.LogBackpackError("Player_tombstone prefab missing; keeping Rusty Backpack intact after death.");
				return;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			ZDO grave = ((state.DeathLocation == null || ((ZDOID)(ref state.DeathLocation.GraveId)).IsNone()) ? null : ZDOMan.instance.GetZDO(state.DeathLocation.GraveId));
			ZDOID anchor;
			Vector3 val4 = BackpackDeathPlacement.Resolve(state.DeathLocation, state.DeathPoint, grave, state.PlayerId, out anchor);
			if (!BackpackDeathPlacement.Finite(val4))
			{
				plugin.LogBackpackError("Death location invalid; original backpack kept intact.");
				return;
			}
			ZDO val5 = ZDOMan.instance.CreateNewZDO(val4, stableHashCode);
			if (val5 != null)
			{
				val5.SetPrefab(stableHashCode);
				val5.SetRotation(Quaternion.identity);
				val5.Persistent = true;
				ZNetView component = prefab.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					val5.SetType(component.m_type);
					val5.SetDistant(component.m_distant);
				}
				val5.Set(ZDOVars.s_addedDefaultItems, true);
				val5.Set("RHSQOL_RustyBackpack_Grave", true);
				if (!((ZDOID)(ref anchor)).IsNone())
				{
					val5.Set("RHSQOL_RustyBackpack_DeathAnchor", anchor);
				}
				val5.Set(ZDOVars.s_owner, state.PlayerId);
				val5.Set(ZDOVars.s_ownerName, peer.m_playerName + " - Rusty Backpack");
				SetContainerCustomFields(val5, width, height, peer.m_playerName + " - Rusty Backpack");
				val5.Set(ZDOVars.s_items, SaveInventoryBytes(val2));
				val5.SetOwner(peer.m_uid);
				ZDOMan.instance.ForceSendZDO(peer.m_uid, val5.m_uid);
				Inventory val6 = LoadInventoryFromZdo(val5, width, height);
				if (val6.NrOfItems() != val2.NrOfItems())
				{
					DestroyDedicatedZdo(val5);
					plugin.LogBackpackError("Death grave verification failed; original backpack kept intact.");
					return;
				}
				DestroyDedicatedZdo(val);
				CanonicalBackpacks.Remove(state.PlayerId);
				state.BackpackId = ZDOID.None;
				state.OpenAt = -1f;
				plugin.LogBackpackInfo(string.Concat("DEATH dropped Rusty Backpack tombstone for ", peer.m_playerName, " with ", val2.NrOfItems(), " item stack(s). inventoryGrave=", anchor, " position=", val4, "."));
			}
		}

		private static void RememberDeathPoint(DedicatedPlayerState state, ZDO player)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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 (!state.HasDeathPoint)
			{
				state.DeathPoint = player.GetPosition() + Vector3.up;
				state.HasDeathPoint = true;
			}
		}

		private static void DestroyDedicatedZdo(ZDO zdo)
		{
			if (zdo != null)
			{
				zdo.SetOwner(ZDOMan.GetSessionID());
				ZDOMan.instance.DestroyZDO(zdo);
			}
		}

		internal static void NotifyDedicatedPlayerDeath(Player player)
		{
			//IL_009f: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if (!ActivationAllowed(instance) || (Object)(object)player == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !ZNet.instance.IsDedicated() || ZDOMan.instance == null)
			{
				return;
			}
			try
			{
				ZNetView component = ((Component)player).GetComponent<ZNetView>();
				ZDO val = (((Object)(object)component == (Object)null) ? null : component.GetZDO());
				if (val == null || !val.IsValid())
				{
					return;
				}
				long num = val.GetLong(ZDOVars.s_playerID, 0L);
				DedicatedPlayerState dedicatedPlayerState = null;
				foreach (KeyValuePair<long, DedicatedPlayerState> dedicatedState in DedicatedStates)
				{
					if (dedicatedState.Value.CharacterId == val.m_uid || (num != 0 && dedicatedState.Value.PlayerId == num))
					{
						dedicatedPlayerState = dedicatedState.Value;
						break;
					}
				}
				ZNetPeer val2 = null;
				IList<ZNetPeer> list = new List<ZNetPeer>(ZNet.instance.GetPeers());
				for (int i = 0; i < list.Count; i++)
				{
					ZNetPeer val3 = list[i];
					if (val3 != null && ((dedicatedPlayerState != null && val3.m_uid == dedicatedPlayerState.PeerId) || val3.m_characterID == val.m_uid))
					{
						val2 = val3;
						break;
					}
				}
				if (dedicatedPlayerState == null && val2 != null && num != 0)
				{
					DedicatedPlayerState dedicatedPlayerState2 = new DedicatedPlayerState();
					dedicatedPlayerState2.PeerId = val2.m_uid;
					dedicatedPlayerState2.PlayerId = num;
					dedicatedPlayerState2.CharacterId = val.m_uid;
					dedicatedPlayerState2.LastEmoteId = val.GetInt(ZDOVars.s_emoteID, 0);
					dedicatedPlayerState2.LastDead = true;
					dedicatedPlayerState = dedicatedPlayerState2;
					DedicatedStates[val2.m_uid] = dedicatedPlayerState;
				}
				if (dedicatedPlayerState == null || val2 == null)
				{
					instance.LogBackpackWarning("DEATH RPC detected but no tracked peer/state could be resolved for playerId=" + num + ".");
					return;
				}
				dedicatedPlayerState.LastDead = true;
				dedicatedPlayerState.DeathConfirmed = true;
				RememberDeathPoint(dedicatedPlayerState, val);
				dedicatedPlayerState.OpenAt = -1f;
				dedicatedPlayerState.OpenAttemptsRemaining = 0;
				instance.LogBackpackInfo("DEATH RPC detected for " + val2.m_playerName + " playerId=" + dedicatedPlayerState.PlayerId + ".");
				if (dedicatedPlayerState.PendingDeathAt < 0f)
				{
					dedicatedPlayerState.PendingDeathAt = Time.realtimeSinceStartup + 1f;
				}
			}
			catch (Exception ex)
			{
				instance.LogBackpackError("Dedicated death RPC handling failed: " + ex);
			}
		}

		internal static void QueueLocalOpen(Player player, string emote, bool emoteStarted)
		{
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && ActivationAllowed(instance) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsDedicated() && ZNet.instance.IsServer())
			{
				string backpackOpenEmoteValue = instance.BackpackOpenEmoteValue;
				if (string.Equals(emote ?? string.Empty, backpackOpenEmoteValue ?? "wave", StringComparison.OrdinalIgnoreCase))
				{
					openAt = Time.realtimeSinceStartup + 0.15f;
				}
			}
		}

		private static void OpenBackpackNow(Player player, Plugin plugin)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureBackpack(player, plugin) || (Object)(object)backpack == (Object)null || (Object)(object)InventoryGui.instance == (Object)null)
			{
				return;
			}
			FollowPlayer(player);
			try
			{
				backpack.SetInUse(true);
				InventoryGui.instance.Show(backpack, 1);
				if (plugin.VerboseLoggingValue)
				{
					Inventory inventory = backpack.GetInventory();
					plugin.LogBackpackInfo(string.Concat("OPEN local-test backpack zdo=", backpackId, " size=", inventory.GetWidth(), "x", inventory.GetHeight(), " items=", inventory.NrOfItems(), "."));
				}
			}
			catch (Exception ex)
			{
				plugin.LogBackpackError("Open failed: " + ex);
			}
		}

		private static bool EnsureBackpack(Player player, Plugin plugin)
		{
			if ((Object)(object)backpackObject != (Object)null && (Object)(object)backpack != (Object)null)
			{
				return true;
			}
			long playerID = player.GetPlayerID();
			GameObject val = FindExistingBackpack(player, playerID, plugin);
			if ((Object)(object)val != (Object)null)
			{
				BindRuntimeBackpack(val);
				EnsureCapacity(player, plugin);
				return (Object)(object)backpack != (Object)null;
			}
			int desiredSlots = GetDesiredSlots(plugin);
			GameObject val2 = CreateHiddenBackpack(player, playerID, desiredSlots, plugin);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			BindRuntimeBackpack(val2);
			return (Object)(object)backpack != (Object)null;
		}

		private static GameObject FindExistingBackpack(Player player, long playerId, Plugin plugin)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be du