Decompiled source of LostAndFound v0.1.2

LostAndFound/lostandfound.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LostAndFound")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2")]
[assembly: AssemblyProduct("LostAndFound")]
[assembly: AssemblyTitle("LostAndFound")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LostAndFound
{
	internal sealed class BinModel : IDisposable
	{
		internal readonly GameObject Root;

		private readonly List<Material> materials = new List<Material>();

		private readonly InteractTrigger trigger;

		internal Vector3 OutletPosition => Root.transform.TransformPoint(new Vector3(0f, -0.15f, -0.57f));

		internal BinModel(Terminal terminal, Transform furniture)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0050: 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_0086: 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_00bb: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			Root = new GameObject("Lost and Found trash can");
			Root.transform.SetParent(furniture, false);
			trigger = ((Component)furniture).GetComponentInChildren<InteractTrigger>(true);
			try
			{
				Material material = Mat(new Color(0.25f, 0.3f, 0.32f));
				Material material2 = Mat(new Color(0.035f, 0.045f, 0.05f));
				Material material3 = Mat(new Color(0.95f, 0.65f, 0.12f));
				Part("Can", (PrimitiveType)2, new Vector3(0f, -0.025f, 0f), new Vector3(0.5f, 0.33f, 0.5f), material);
				Part("Bottom rim", (PrimitiveType)2, new Vector3(0f, -0.35f, 0f), new Vector3(0.54f, 0.025f, 0.54f), material2);
				Part("Lid", (PrimitiveType)2, new Vector3(0f, 0.315f, 0f), new Vector3(0.56f, 0.035f, 0.56f), material3);
				Part("Lid handle", (PrimitiveType)3, new Vector3(0f, 0.375f, 0f), new Vector3(0.16f, 0.04f, 0.05f), material2);
				for (int i = 0; i < 12; i++)
				{
					float num = (float)i * MathF.PI / 6f;
					Part("Can rib", (PrimitiveType)3, new Vector3(Mathf.Sin(num) * 0.246f, -0.035f, Mathf.Cos(num) * 0.246f), new Vector3(0.018f, 0.55f, 0.018f), material2);
				}
				Part("Pedal", (PrimitiveType)3, new Vector3(0f, -0.34f, -0.29f), new Vector3(0.18f, 0.025f, 0.16f), material3);
				trigger.hoverTip = "Empty Lost and Found : [E]";
				trigger.disabledHoverTip = "Lost and Found unavailable";
				trigger.oneHandedItemAllowed = (trigger.twoHandedItemAllowed = true);
				trigger.holdInteraction = false;
				trigger.interactCooldown = true;
				trigger.cooldownTime = 0.5f;
				InteractTrigger[] componentsInChildren = ((Component)terminal).GetComponentsInChildren<InteractTrigger>(true);
				foreach (InteractTrigger val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)(object)trigger && Object.op_Implicit((Object)(object)val.hoverIcon))
					{
						trigger.hoverIcon = val.hoverIcon;
						trigger.disabledHoverIcon = val.hoverIcon;
						break;
					}
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private Material Mat(Color color)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			Shader obj = Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit");
			if (!Object.op_Implicit((Object)(object)obj))
			{
				throw new InvalidOperationException("Cannot find ship model shader.");
			}
			Material val = new Material(obj);
			val.SetColor("_BaseColor", color);
			if (val.HasProperty("_UnlitColor"))
			{
				val.SetColor("_UnlitColor", color);
			}
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", 0.6f);
			}
			materials.Add(val);
			return val;
		}

		private void Part(string name, PrimitiveType type, Vector3 position, Vector3 scale, Material material)
		{
			//IL_0000: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive(type);
			((Object)obj).name = name;
			obj.transform.SetParent(Root.transform, false);
			obj.transform.localPosition = position;
			obj.transform.localScale = scale;
			Collider component = obj.GetComponent<Collider>();
			component.enabled = false;
			Object.Destroy((Object)(object)component);
			((Renderer)obj.GetComponent<MeshRenderer>()).sharedMaterial = material;
		}

		internal void SetReady(bool ready)
		{
			trigger.interactable = ready;
		}

		public void Dispose()
		{
			if (Object.op_Implicit((Object)(object)trigger))
			{
				trigger.interactable = false;
			}
			if (Object.op_Implicit((Object)(object)Root))
			{
				Object.Destroy((Object)(object)Root);
			}
			foreach (Material material in materials)
			{
				if (Object.op_Implicit((Object)(object)material))
				{
					Object.Destroy((Object)(object)material);
				}
			}
			materials.Clear();
		}
	}
	internal sealed class DispenserSnapshot
	{
		internal const int Protocol = 3;

		internal const int Size = 38;

		internal bool Enabled;

		internal bool Available;

		internal ulong NetworkId;

		internal float X;

		internal float Y;

		internal float Z;

		internal float Pitch;

		internal float Yaw;

		internal float Roll;

		internal static bool HasPayload(int bufferLength, int position)
		{
			if (position >= 0 && bufferLength >= position)
			{
				return bufferLength - position == 38;
			}
			return false;
		}

		internal byte[] Encode()
		{
			using MemoryStream memoryStream = new MemoryStream(38);
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(3);
			binaryWriter.Write(Enabled);
			binaryWriter.Write(Available);
			binaryWriter.Write(NetworkId);
			binaryWriter.Write(X);
			binaryWriter.Write(Y);
			binaryWriter.Write(Z);
			binaryWriter.Write(Pitch);
			binaryWriter.Write(Yaw);
			binaryWriter.Write(Roll);
			return memoryStream.ToArray();
		}

		internal static bool TryDecode(byte[] data, out DispenserSnapshot snapshot)
		{
			snapshot = null;
			if (data == null || data.Length != 38 || data[4] > 1 || data[5] > 1)
			{
				return false;
			}
			using MemoryStream input = new MemoryStream(data, writable: false);
			using BinaryReader binaryReader = new BinaryReader(input);
			if (binaryReader.ReadInt32() != 3)
			{
				return false;
			}
			DispenserSnapshot dispenserSnapshot = new DispenserSnapshot
			{
				Enabled = binaryReader.ReadBoolean(),
				Available = binaryReader.ReadBoolean(),
				NetworkId = binaryReader.ReadUInt64(),
				X = binaryReader.ReadSingle(),
				Y = binaryReader.ReadSingle(),
				Z = binaryReader.ReadSingle(),
				Pitch = binaryReader.ReadSingle(),
				Yaw = binaryReader.ReadSingle(),
				Roll = binaryReader.ReadSingle()
			};
			float[] array = new float[6] { dispenserSnapshot.X, dispenserSnapshot.Y, dispenserSnapshot.Z, dispenserSnapshot.Pitch, dispenserSnapshot.Yaw, dispenserSnapshot.Roll };
			foreach (float f in array)
			{
				if (float.IsNaN(f) || float.IsInfinity(f))
				{
					return false;
				}
			}
			snapshot = dispenserSnapshot;
			return true;
		}
	}
	internal static class Furniture
	{
		internal const string UnlockableName = "Lost and Found";

		internal static uint PrefabHash;

		internal static UnlockableItem Item;

		internal static GameObject Prefab;

		internal static void Register()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_0142: 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_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Expected O, but got Unknown
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Expected O, but got Unknown
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Expected O, but got Unknown
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Expected O, but got Unknown
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Expected O, but got Unknown
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Expected O, but got Unknown
			Assembly assembly = ((object)Chainloader.PluginInfos["evaisa.lethallib"].Instance).GetType().Assembly;
			Prefab = (GameObject)assembly.GetType("LethalLib.Modules.NetworkPrefabs").GetMethod("CreateNetworkPrefab", new Type[1] { typeof(string) }).Invoke(null, new object[1] { "achachala.lostandfound.Furniture.v2" });
			PrefabHash = StablePrefabHash("achachala.lostandfound.Furniture.v2");
			typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SetValue(Prefab.GetComponent<NetworkObject>(), PrefabHash);
			int num = LayerMask.NameToLayer("PlaceableShipObjects");
			if (num < 0)
			{
				throw new InvalidOperationException("Missing native PlaceableShipObjects layer.");
			}
			Prefab.layer = num;
			Prefab.tag = "PlaceableObject";
			AudioSource obj = Prefab.AddComponent<AudioSource>();
			obj.playOnAwake = false;
			obj.spatialBlend = 1f;
			obj.rolloffMode = (AudioRolloffMode)1;
			obj.minDistance = 1f;
			obj.maxDistance = 12f;
			AutoParentToShip parentObject = Prefab.AddComponent<AutoParentToShip>();
			PlaceableShipObject val = Prefab.AddComponent<PlaceableShipObject>();
			BoxCollider val2 = Prefab.AddComponent<BoxCollider>();
			val2.size = new Vector3(0.58f, 0.78f, 0.58f);
			GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3);
			Mesh val4 = Object.Instantiate<Mesh>(val3.GetComponent<MeshFilter>().sharedMesh);
			Vector3[] vertices = val4.vertices;
			for (int i = 0; i < vertices.Length; i++)
			{
				vertices[i] = Vector3.Scale(vertices[i], new Vector3(0.55f, 0.77f, 0.55f));
			}
			val4.vertices = vertices;
			val4.RecalculateBounds();
			MeshFilter val5 = Prefab.AddComponent<MeshFilter>();
			val5.sharedMesh = val4;
			MeshRenderer obj2 = Prefab.AddComponent<MeshRenderer>();
			((Renderer)obj2).sharedMaterial = ((Renderer)val3.GetComponent<MeshRenderer>()).sharedMaterial;
			Object.Destroy((Object)(object)val3);
			((Renderer)obj2).enabled = false;
			val.parentObject = parentObject;
			val.mainMesh = val5;
			val.mainTransform = Prefab.transform;
			val.placeObjectCollider = (Collider)(object)val2;
			val.yOffset = 0.39f;
			val.AllowPlacementOnCounters = true;
			val.AllowPlacementOnWalls = false;
			val.overrideWallOffset = true;
			val.wallOffset = 0.18f;
			Prefab.AddComponent<FurnitureMarker>();
			GameObject val6 = new GameObject("Empty bin interaction");
			val6.transform.SetParent(Prefab.transform, false);
			int num2 = LayerMask.NameToLayer("InteractableObject");
			val6.layer = ((num2 >= 0) ? num2 : 9);
			val6.tag = "InteractTrigger";
			val6.AddComponent<BinMarker>();
			val6.AddComponent<BoxCollider>().size = new Vector3(0.56f, 0.76f, 0.56f);
			InteractTrigger obj3 = val6.AddComponent<InteractTrigger>();
			obj3.onInteract = new InteractEvent();
			obj3.onInteractEarly = new InteractEvent();
			obj3.onInteractEarlyOtherClients = new InteractEvent();
			obj3.onStopInteract = new InteractEvent();
			obj3.onCancelAnimation = new InteractEvent();
			obj3.holdingInteractEvent = new InteractEventFloat();
			obj3.interactable = false;
			Item = new UnlockableItem
			{
				unlockableName = "Lost and Found",
				prefabObject = Prefab,
				unlockableType = 1,
				IsPlaceable = true,
				canBeStored = true,
				maxNumber = 1,
				alreadyUnlocked = true,
				spawnPrefab = true
			};
			MethodInfo methodInfo = assembly.GetType("LethalLib.Modules.Unlockables").GetMethods(BindingFlags.Static | BindingFlags.Public).Single((MethodInfo m) => m.Name == "RegisterUnlockable" && m.GetParameters().Length == 3 && m.GetParameters()[0].ParameterType == typeof(UnlockableItem) && m.GetParameters()[1].ParameterType == typeof(int));
			Type parameterType = methodInfo.GetParameters()[2].ParameterType;
			methodInfo.Invoke(null, new object[3]
			{
				Item,
				-1,
				Enum.ToObject(parameterType, 0)
			});
		}

		internal static void Configure()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)Prefab))
			{
				return;
			}
			int num = ResolveItem();
			if (num < 0)
			{
				return;
			}
			PlaceableShipObject component = Prefab.GetComponent<PlaceableShipObject>();
			AutoParentToShip component2 = Prefab.GetComponent<AutoParentToShip>();
			component.unlockableID = (component2.unlockableID = num);
			PlaceableShipObject[] array = Object.FindObjectsOfType<PlaceableShipObject>();
			foreach (PlaceableShipObject val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.placeObjectSFX) && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<FurnitureMarker>()))
				{
					component.placeObjectSFX = val.placeObjectSFX;
					break;
				}
			}
			component2.overrideOffset = true;
			component2.positionOffset = instance.elevatorTransform.InverseTransformPoint(DefaultPosition());
			component2.rotationOffset = instance.elevatorTransform.eulerAngles;
		}

		internal static Vector3 DefaultPosition()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0079: 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_008f: 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_005c: 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)
			Bounds bounds = StartOfRound.Instance.shipInnerRoomBounds.bounds;
			Vector3 center = ((Bounds)(ref bounds)).center;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(center, Vector3.down, ref val, ((Bounds)(ref bounds)).size.y + 5f, LayerMask.GetMask(new string[2] { "Room", "Colliders" }), (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val)).point + Vector3.up * 0.4f;
			}
			return new Vector3(center.x, ((Bounds)(ref bounds)).min.y + 0.4f, center.z);
		}

		internal static uint StablePrefabHash(string name)
		{
			uint num = 2166136261u;
			foreach (char c in name)
			{
				num = (num ^ c) * 16777619;
			}
			return num;
		}

		internal static int ResolveItem()
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.unlockablesList))
			{
				return -1;
			}
			int num = instance.unlockablesList.unlockables.FindIndex((UnlockableItem item) => item != null && string.Equals(item.unlockableName, "Lost and Found", StringComparison.Ordinal));
			if (num >= 0)
			{
				Item = instance.unlockablesList.unlockables[num];
			}
			return num;
		}

		internal static bool BindReplica(FurnitureMarker marker, bool register = true)
		{
			int num = ResolveItem();
			if (num < 0)
			{
				return false;
			}
			PlaceableShipObject component = ((Component)marker).GetComponent<PlaceableShipObject>();
			AutoParentToShip component2 = ((Component)marker).GetComponent<AutoParentToShip>();
			component.unlockableID = (component2.unlockableID = num);
			component.parentObject = component2;
			StartOfRound instance = StartOfRound.Instance;
			if (register && instance.SpawnedShipUnlockables != null)
			{
				instance.SpawnedShipUnlockables[num] = ((Component)marker).gameObject;
			}
			return true;
		}

		internal static FurnitureMarker? Find(ulong? networkId = null)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (!Object.op_Implicit((Object)(object)singleton) || singleton.SpawnManager == null || ResolveItem() < 0)
			{
				return null;
			}
			if (networkId.HasValue)
			{
				if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(networkId.Value, out var value))
				{
					return null;
				}
				FurnitureMarker component = ((Component)value).GetComponent<FurnitureMarker>();
				if (!Object.op_Implicit((Object)(object)component) || !BindReplica(component))
				{
					return null;
				}
				return component;
			}
			foreach (NetworkObject value2 in singleton.SpawnManager.SpawnedObjects.Values)
			{
				if (Object.op_Implicit((Object)(object)value2) && value2.IsSpawned)
				{
					FurnitureMarker component2 = ((Component)value2).GetComponent<FurnitureMarker>();
					if (Object.op_Implicit((Object)(object)component2) && BindReplica(component2))
					{
						return component2;
					}
				}
			}
			return null;
		}
	}
	public sealed class FurnitureMarker : MonoBehaviour
	{
	}
	[HarmonyPatch(typeof(AutoParentToShip), "Awake")]
	internal static class FurnitureAwakePatch
	{
		[HarmonyPrefix]
		private static void Prefix(AutoParentToShip __instance)
		{
			FurnitureMarker component = ((Component)__instance).GetComponent<FurnitureMarker>();
			if (Object.op_Implicit((Object)(object)component))
			{
				Furniture.BindReplica(component, register: false);
			}
		}
	}
	internal static class InventoryTraversal
	{
		internal static HashSet<ulong> Expand<T>(IEnumerable<T> roots, Func<T, ulong?> identity, Func<T, IEnumerable<T>> children)
		{
			HashSet<ulong> hashSet = new HashSet<ulong>();
			Stack<T> stack = new Stack<T>(roots);
			while (stack.Count > 0)
			{
				T arg = stack.Pop();
				ulong? num = identity(arg);
				if (!num.HasValue || !hashSet.Add(num.Value))
				{
					continue;
				}
				foreach (T item in children(arg))
				{
					stack.Push(item);
				}
			}
			return hashSet;
		}

		internal static int Depth(ulong id, Func<ulong, ulong?> parent)
		{
			HashSet<ulong> hashSet = new HashSet<ulong>();
			int num = 0;
			while (hashSet.Add(id))
			{
				ulong? num2 = parent(id);
				if (!num2.HasValue)
				{
					break;
				}
				num++;
				id = num2.Value;
			}
			return num;
		}

		internal static bool AncestorsAllowed(ulong id, Func<ulong, ulong?> parent, Func<ulong, bool> allowed)
		{
			HashSet<ulong> hashSet = new HashSet<ulong> { id };
			do
			{
				ulong? num = parent(id);
				if (!num.HasValue)
				{
					return true;
				}
				id = num.Value;
			}
			while (hashSet.Add(id) && allowed(id));
			return false;
		}
	}
	[BepInPlugin("achachala.lostandfound", "Lost and Found", "0.1.2")]
	[BepInDependency("evaisa.lethallib", "1.2.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "achachala.lostandfound";

		public const string Version = "0.1.2";

		private const string Hello = "achachala.lostandfound.hello.v3";

		private const string Settings = "achachala.lostandfound.settings.v3";

		private const string Dispense = "achachala.lostandfound.dispense.v1";

		internal static Plugin Instance;

		private ConfigEntry<bool> enabledConfig;

		private ConfigEntry<float> cooldownConfig;

		private readonly RequestGate requests = new RequestGate();

		private readonly HashSet<ulong> handshakePeers = new HashSet<ulong>();

		private NetworkManager? network;

		private Terminal? terminal;

		private BinModel? model;

		private FurnitureMarker? furniture;

		private FurnitureMarker? positionedFurniture;

		private Harmony harmony;

		private bool attached;

		private bool haveSettings;

		private bool activeEnabled;

		private float nextUpdate;

		private float nextHello;

		private bool? collidersEnabled;

		private bool hostHasFurniture;

		private ulong hostFurnitureId;

		private Vector3 hostPositionOffset;

		private Vector3 hostRotationOffset;

		private bool applyHostPlacement;

		private float nextDiagnostic;

		private string lastWaitReason = "";

		private uint localSequence;

		private float nextModelAttempt;

		internal RecoveryService Recovery;

		internal bool RecoveryEnabled => enabledConfig.Value;

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			Instance = this;
			enabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Recovery", "Enabled", true, "Host: enable the Lost and Found bin.");
			cooldownConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "SecondsBetweenUses", 0.35f, new ConfigDescription("Host: minimum time between empty-bin requests.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			Recovery = new RecoveryService(this);
			Furniture.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Registered Lost and Found network prefab hash={Furniture.PrefabHash}.");
			harmony = new Harmony("achachala.lostandfound");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Lost and Found 0.1.2 loaded. Install on host AND all clients, with LethalLib.");
		}

		private unsafe void Update()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0614: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0639: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_063f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)(object)network || (attached && (!Object.op_Implicit((Object)(object)singleton) || !singleton.IsListening)))
			{
				Detach();
			}
			if (!Object.op_Implicit((Object)(object)singleton) || !singleton.IsListening || singleton.CustomMessagingManager == null)
			{
				return;
			}
			if (!attached)
			{
				network = singleton;
				singleton.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.hello.v3", new HandleNamedMessageDelegate(ReceiveHello));
				singleton.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.settings.v3", new HandleNamedMessageDelegate(ReceiveSettings));
				singleton.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.dispense.v1", new HandleNamedMessageDelegate(ReceiveDispense));
				Recovery.Attach(singleton);
				singleton.OnClientDisconnectCallback += Disconnected;
				singleton.OnClientConnectedCallback += Connected;
				attached = true;
				nextHello = (nextUpdate = 0f);
			}
			if (singleton.IsServer)
			{
				Recovery.Observe();
			}
			Recovery.ApplyPending();
			if (Time.unscaledTime < nextUpdate)
			{
				return;
			}
			nextUpdate = Time.unscaledTime + 0.25f;
			if (singleton.IsServer)
			{
				activeEnabled = enabledConfig.Value;
				haveSettings = true;
				Recovery.EnsureLoaded();
			}
			else if (singleton.IsConnectedClient && Time.unscaledTime >= nextHello)
			{
				nextHello = Time.unscaledTime + 2f;
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
				try
				{
					int num = 3;
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					singleton.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.hello.v3", 0uL, val, (NetworkDelivery)3);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			if (!Object.op_Implicit((Object)(object)terminal))
			{
				terminal = Object.FindObjectOfType<Terminal>();
			}
			FurnitureMarker furnitureMarker = (singleton.IsServer ? Furniture.Find() : ((haveSettings && hostHasFurniture) ? Furniture.Find(hostFurnitureId) : null));
			if ((Object)(object)furnitureMarker != (Object)(object)furniture)
			{
				DestroyModel();
				furniture = furnitureMarker;
				collidersEnabled = null;
			}
			if (!singleton.IsServer && Object.op_Implicit((Object)(object)furnitureMarker) && applyHostPlacement && Furniture.BindReplica(furnitureMarker))
			{
				PlaceableShipObject component = ((Component)furnitureMarker).GetComponent<PlaceableShipObject>();
				ShipBuildModeManager instance = ShipBuildModeManager.Instance;
				if (!Object.op_Implicit((Object)(object)instance) || !instance.InBuildMode || AccessTools.Field(typeof(ShipBuildModeManager), "placingObject").GetValue(instance) != component)
				{
					AutoParentToShip component2 = ((Component)furnitureMarker).GetComponent<AutoParentToShip>();
					component2.overrideOffset = true;
					component2.disableObject = false;
					component2.positionOffset = hostPositionOffset;
					component2.rotationOffset = hostRotationOffset;
					component2.MoveToOffset();
					if (!((Component)furnitureMarker).gameObject.activeSelf)
					{
						((Component)furnitureMarker).gameObject.SetActive(true);
					}
					Furniture.Item.inStorage = false;
					applyHostPlacement = false;
				}
			}
			if (!singleton.IsServer && (!haveSettings || !hostHasFurniture || !Object.op_Implicit((Object)(object)furniture)))
			{
				string text = ((!haveSettings) ? "waiting for host handshake (confirm every player uses 0.1.2)" : ((!hostHasFurniture) ? "host reports no deployed Lost and Found" : $"waiting for network object {hostFurnitureId}; check matching mods/dependencies and prefab registration"));
				if (Time.unscaledTime >= nextDiagnostic || text != lastWaitReason)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Lost and Found client: " + text));
					nextDiagnostic = Time.unscaledTime + 20f;
					lastWaitReason = text;
				}
			}
			if (!singleton.IsServer && Object.op_Implicit((Object)(object)furnitureMarker) && hostHasFurniture)
			{
				Furniture.Item.inStorage = false;
			}
			bool flag = haveSettings && activeEnabled && (singleton.IsServer ? (!Furniture.Item.inStorage) : hostHasFurniture);
			if (Object.op_Implicit((Object)(object)furniture) && collidersEnabled != flag)
			{
				Collider[] componentsInChildren = ((Component)furniture).GetComponentsInChildren<Collider>(true);
				for (int num = 0; num < componentsInChildren.Length; num++)
				{
					componentsInChildren[num].enabled = flag;
				}
				collidersEnabled = flag;
			}
			if (!flag || !Object.op_Implicit((Object)(object)terminal) || !Object.op_Implicit((Object)(object)furniture))
			{
				DestroyModel();
				return;
			}
			if (model == null || !Object.op_Implicit((Object)(object)model.Root))
			{
				if (Time.unscaledTime < nextModelAttempt)
				{
					return;
				}
				try
				{
					model = new BinModel(terminal, ((Component)furniture).transform);
					((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Created movable ship Lost and Found bin on {0}, object={1}, unlockable={2}.", singleton.IsServer ? "host" : "client", ((Component)furniture).GetComponent<NetworkObject>().NetworkObjectId, Furniture.ResolveItem()));
				}
				catch (Exception ex)
				{
					nextModelAttempt = Time.unscaledTime + 10f;
					((BaseUnityPlugin)this).Logger.LogError((object)("Could not build Lost and Found; will retry in 10 seconds: " + ex));
					return;
				}
			}
			if (singleton.IsServer && (Object)(object)positionedFurniture != (Object)(object)furniture && Object.op_Implicit((Object)(object)ShipBuildModeManager.Instance) && Object.op_Implicit((Object)(object)GameNetworkManager.Instance) && Object.op_Implicit((Object)(object)GameNetworkManager.Instance.localPlayerController))
			{
				string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
				if (!ES3.Load<bool>("LostAndFound.CenteredPlacementV1", currentSaveFileName, false) || !Furniture.Item.hasBeenMoved)
				{
					NetworkObject component3 = ((Component)furniture).GetComponent<NetworkObject>();
					Vector3 val2 = Furniture.DefaultPosition();
					Vector3 eulerAngles = StartOfRound.Instance.elevatorTransform.eulerAngles;
					PlaceableShipObject component4 = ((Component)furniture).GetComponent<PlaceableShipObject>();
					ShipBuildModeManager.Instance.PlaceShipObject(val2, eulerAngles, component4, false);
					ShipBuildModeManager.Instance.PlaceShipObjectServerRpc(val2, eulerAngles, new NetworkObjectReference(component3), (int)GameNetworkManager.Instance.localPlayerController.playerClientId);
					ES3.Save<bool>("LostAndFound.CenteredPlacementV1", true, currentSaveFileName);
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Placed Lost and Found bin in the centre of the ship; subsequent furniture moves are preserved.");
				}
				positionedFurniture = furniture;
			}
			model.SetReady(ready: true);
		}

		internal void ConfigureFurniture()
		{
			Furniture.Configure();
		}

		internal void LogInfo(string message)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)message);
		}

		internal void Error(string message, Exception error)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)(message + ": " + error));
		}

		private void Connected(ulong client)
		{
			if (Object.op_Implicit((Object)(object)network) && network.IsServer && client != network.LocalClientId)
			{
				SendState(client);
			}
		}

		private unsafe void SendState(ulong client)
		{
			//IL_0074: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || !network.IsServer || !network.ConnectedClients.ContainsKey(client))
			{
				return;
			}
			FurnitureMarker furnitureMarker = Furniture.Find();
			bool flag = Object.op_Implicit((Object)(object)furnitureMarker) && !Furniture.Item.inStorage;
			AutoParentToShip val = (flag ? ((Component)furnitureMarker).GetComponent<AutoParentToShip>() : null);
			Vector3 val2 = (Object.op_Implicit((Object)(object)val) ? val.positionOffset : Vector3.zero);
			Vector3 val3 = (Object.op_Implicit((Object)(object)val) ? val.rotationOffset : Vector3.zero);
			byte[] array = new DispenserSnapshot
			{
				Enabled = enabledConfig.Value,
				Available = flag,
				NetworkId = (flag ? ((Component)furnitureMarker).GetComponent<NetworkObject>().NetworkObjectId : 0),
				X = val2.x,
				Y = val2.y,
				Z = val2.z,
				Pitch = val3.x,
				Yaw = val3.y,
				Roll = val3.z
			}.Encode();
			FastBufferWriter val4 = default(FastBufferWriter);
			((FastBufferWriter)(ref val4))..ctor(38, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val4)).WriteBytesSafe(array, array.Length, 0);
				network.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.settings.v3", client, val4, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val4))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private void ReceiveHello(ulong sender, FastBufferReader reader)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || !network.IsServer || !network.ConnectedClients.ContainsKey(sender) || !((FastBufferReader)(ref reader)).TryBeginRead(4))
			{
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (num == 3)
			{
				if (handshakePeers.Add(sender))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Client {sender} acknowledged Lost and Found protocol {num}.");
				}
				SendState(sender);
				Recovery.SendPending(sender);
			}
		}

		private void ReceiveSettings(ulong sender, FastBufferReader reader)
		{
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || network.IsServer || sender != 0L || !DispenserSnapshot.HasPayload(((FastBufferReader)(ref reader)).Length, ((FastBufferReader)(ref reader)).Position) || !((FastBufferReader)(ref reader)).TryBeginRead(38))
			{
				return;
			}
			int length = ((FastBufferReader)(ref reader)).Length;
			int position = ((FastBufferReader)(ref reader)).Position;
			byte[] array = new byte[38];
			((FastBufferReader)(ref reader)).ReadBytesSafe(ref array, array.Length, 0);
			if (DispenserSnapshot.TryDecode(array, out DispenserSnapshot snapshot))
			{
				bool enabled = snapshot.Enabled;
				bool available = snapshot.Available;
				ulong networkId = snapshot.NetworkId;
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(snapshot.X, snapshot.Y, snapshot.Z);
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(snapshot.Pitch, snapshot.Yaw, snapshot.Roll);
				if (!haveSettings)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Received Lost and Found host handshake: available={available}, object={networkId}, frame={length}, payloadOffset={position}.");
				}
				bool flag = !haveSettings || available != hostHasFurniture || networkId != hostFurnitureId || val != hostPositionOffset || val2 != hostRotationOffset;
				activeEnabled = enabled;
				hostHasFurniture = available;
				hostFurnitureId = networkId;
				hostPositionOffset = val;
				hostRotationOffset = val2;
				applyHostPlacement |= flag;
				haveSettings = true;
			}
		}

		internal unsafe void Interact(PlayerControllerB player)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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 (!Object.op_Implicit((Object)(object)network) || !attached || !haveSettings || !activeEnabled || !Object.op_Implicit((Object)(object)player) || !((NetworkBehaviour)player).IsOwner)
			{
				return;
			}
			uint sequence = ++localSequence;
			if (network.IsServer)
			{
				ExecuteDispense(network.LocalClientId, sequence);
			}
			else if (network.IsConnectedClient)
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe<uint>(ref sequence, default(ForPrimitives));
					network.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.dispense.v1", 0uL, val, (NetworkDelivery)3);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
		}

		private void ReceiveDispense(ulong sender, FastBufferReader reader)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)network) && network.IsServer && ((FastBufferReader)(ref reader)).TryBeginRead(4))
			{
				uint sequence = default(uint);
				((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref sequence, default(ForPrimitives));
				ExecuteDispense(sender, sequence);
			}
		}

		private void ExecuteDispense(ulong sender, uint sequence)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || !network.IsServer || !enabledConfig.Value || !network.ConnectedClients.ContainsKey(sender) || !Object.op_Implicit((Object)(object)StartOfRound.Instance) || model == null || !Object.op_Implicit((Object)(object)model.Root) || !Object.op_Implicit((Object)(object)furniture) || Furniture.Item.inStorage || ((Component)furniture).GetComponent<PlaceableShipObject>().inUse)
			{
				return;
			}
			PlayerControllerB val = null;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val2 in allPlayerScripts)
			{
				if (Object.op_Implicit((Object)(object)val2) && val2.actualClientId == sender && val2.isPlayerControlled)
				{
					val = val2;
					break;
				}
			}
			if (Object.op_Implicit((Object)(object)val) && !val.isPlayerDead && val.isInHangarShipRoom)
			{
				Vector3 val3 = ((Component)val).transform.position - model.Root.transform.position;
				if (!(((Vector3)(ref val3)).sqrMagnitude > 9f) && !StartOfRound.Instance.shipIsLeaving && requests.TryAccept(sender, sequence, Time.unscaledTime, cooldownConfig.Value))
				{
					Recovery.Empty(model.OutletPosition);
				}
			}
		}

		private void Disconnected(ulong client)
		{
			requests.Remove(client);
			handshakePeers.Remove(client);
			if (Object.op_Implicit((Object)(object)network) && client == network.LocalClientId)
			{
				Detach();
			}
		}

		private void DestroyModel()
		{
			model?.Dispose();
			model = null;
		}

		private void Detach()
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)network))
			{
				network.OnClientDisconnectCallback -= Disconnected;
				network.OnClientConnectedCallback -= Connected;
				if (network.CustomMessagingManager != null)
				{
					network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.hello.v3");
					network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.settings.v3");
					network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.dispense.v1");
				}
			}
			Recovery?.Detach();
			DestroyModel();
			furniture = (positionedFurniture = null);
			collidersEnabled = null;
			network = null;
			terminal = null;
			attached = (haveSettings = (activeEnabled = false));
			requests.Clear();
			handshakePeers.Clear();
			localSequence = 0u;
			((MonoBehaviour)this).StopAllCoroutines();
			hostHasFurniture = (applyHostPlacement = false);
			hostFurnitureId = 0uL;
			hostPositionOffset = (hostRotationOffset = Vector3.zero);
			nextDiagnostic = 0f;
			lastWaitReason = "";
		}

		private void OnDestroy()
		{
			Detach();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	public sealed class BinMarker : MonoBehaviour
	{
	}
	[HarmonyPatch(typeof(InteractTrigger), "Interact")]
	internal static class InteractionPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(InteractTrigger __instance, Transform __0)
		{
			if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<BinMarker>()))
			{
				return true;
			}
			if (__instance.interactable && Object.op_Implicit((Object)(object)__0) && Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.Interact(((Component)__0).GetComponent<PlayerControllerB>());
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Terminal), "Awake")]
	internal static class TerminalFurniturePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Terminal __instance)
		{
			Plugin.Instance.ConfigureFurniture();
		}
	}
	internal sealed class DeathClaims
	{
		private readonly Dictionary<ulong, ulong> claims = new Dictionary<ulong, ulong>();

		internal void MarkDeath(ulong player, IEnumerable<ulong> items)
		{
			foreach (ulong item in items)
			{
				claims[item] = player;
			}
		}

		internal void Recovered(ulong item)
		{
			claims.Remove(item);
		}

		internal bool CanCollect(ulong item, bool ownerDead, bool held, bool inShip, bool eligible)
		{
			return claims.ContainsKey(item) && ownerDead && !held && eligible;
		}

		internal KeyValuePair<ulong, ulong>[] Snapshot()
		{
			KeyValuePair<ulong, ulong>[] array = new KeyValuePair<ulong, ulong>[claims.Count];
			int num = 0;
			foreach (KeyValuePair<ulong, ulong> claim in claims)
			{
				array[num++] = claim;
			}
			return array;
		}

		internal void Clear()
		{
			claims.Clear();
		}
	}
	[Serializable]
	public sealed class RecoveredItem
	{
		public string Name = "";

		public string Prefab = "";

		public int ItemId;

		public int Data;

		public bool HasBattery;

		public float Charge;

		public int ScrapValue;

		public bool UsedUp;
	}
	internal sealed class RecoveryService
	{
		private const string SaveKey = "LostAndFound.Items.v1";

		private const string RestoreMessage = "achachala.lostandfound.restored.v1";

		private const string DeathMessage = "achachala.lostandfound.death.v1";

		private const string BagRemoveMessage = "achachala.lostandfound.bag-remove.v1";

		private readonly Plugin plugin;

		private NetworkManager? network;

		private string? saveFile;

		private bool loadFailed;

		private readonly List<RecoveredItem> contents = new List<RecoveredItem>();

		private readonly DeathClaims claims = new DeathClaims();

		private readonly Dictionary<ulong, HashSet<ulong>> inventory = new Dictionary<ulong, HashSet<ulong>>();

		private readonly Dictionary<ulong, ulong> lastHolder = new Dictionary<ulong, ulong>();

		private readonly Dictionary<ulong, HashSet<ulong>> deathReports = new Dictionary<ulong, HashSet<ulong>>();

		private readonly HashSet<ulong> capturedDeaths = new HashSet<ulong>();

		private readonly Dictionary<ulong, RestoredItem> restored = new Dictionary<ulong, RestoredItem>();

		private readonly Dictionary<ulong, float> pending = new Dictionary<ulong, float>();

		private readonly Dictionary<ulong, string> applied = new Dictionary<ulong, string>();

		private bool Host
		{
			get
			{
				if (Object.op_Implicit((Object)(object)network) && network.IsServer)
				{
					return network.IsListening;
				}
				return false;
			}
		}

		internal RecoveryService(Plugin owner)
		{
			plugin = owner;
		}

		internal void Attach(NetworkManager manager)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			network = manager;
			manager.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.restored.v1", new HandleNamedMessageDelegate(ReceiveRestored));
			manager.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.death.v1", new HandleNamedMessageDelegate(ReceiveDeath));
			manager.CustomMessagingManager.RegisterNamedMessageHandler("achachala.lostandfound.bag-remove.v1", new HandleNamedMessageDelegate(ReceiveBagRemove));
		}

		internal void EnsureLoaded()
		{
			if (!Host || !Object.op_Implicit((Object)(object)GameNetworkManager.Instance))
			{
				return;
			}
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (string.IsNullOrEmpty(currentSaveFileName) || currentSaveFileName == saveFile)
			{
				return;
			}
			contents.Clear();
			EndRound();
			saveFile = currentSaveFileName;
			loadFailed = false;
			try
			{
				string[] array = ES3.Load<string[]>("LostAndFound.Items.v1", currentSaveFileName, Array.Empty<string>());
				for (int i = 0; i < array.Length; i++)
				{
					RecoveredItem recoveredItem = JsonUtility.FromJson<RecoveredItem>(array[i]);
					if (recoveredItem == null || string.IsNullOrEmpty(recoveredItem.Name))
					{
						throw new InvalidOperationException("Invalid saved recovery record.");
					}
					contents.Add(recoveredItem);
				}
				plugin.LogInfo($"Loaded {contents.Count} Lost and Found items.");
			}
			catch (Exception error)
			{
				loadFailed = true;
				plugin.Error("Lost and Found save could not be loaded; recovery is paused to preserve it", error);
			}
		}

		private void Save()
		{
			if (saveFile == null || loadFailed)
			{
				throw new InvalidOperationException("Recovery save is not ready.");
			}
			ES3.Save<string[]>("LostAndFound.Items.v1", ((IEnumerable<RecoveredItem>)contents).Select((Func<RecoveredItem, string>)JsonUtility.ToJson).ToArray(), saveFile);
		}

		private static HashSet<ulong> ExpandItems(IEnumerable<GrabbableObject> roots)
		{
			return InventoryTraversal.Expand(roots, (GrabbableObject item) => (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)((NetworkBehaviour)item).NetworkObject) || !((NetworkBehaviour)item).NetworkObject.IsSpawned) ? ((ulong?)null) : new ulong?(((NetworkBehaviour)item).NetworkObjectId), delegate(GrabbableObject item)
			{
				BeltBagItem val = (BeltBagItem)(object)((item is BeltBagItem) ? item : null);
				return (val == null || val.objectsInBag == null) ? Enumerable.Empty<GrabbableObject>() : val.objectsInBag;
			});
		}

		private static HashSet<ulong> ReadInventory(PlayerControllerB player)
		{
			return ExpandItems((player.ItemSlots ?? Array.Empty<GrabbableObject>()).Concat((IEnumerable<GrabbableObject>)(object)new GrabbableObject[1] { player.ItemOnlySlot }));
		}

		internal unsafe void CaptureDeath(PlayerControllerB player)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || !Object.op_Implicit((Object)(object)player))
			{
				return;
			}
			if (!Host)
			{
				if (!((NetworkBehaviour)player).IsOwner || !network.IsConnectedClient || capturedDeaths.Contains(player.actualClientId))
				{
					return;
				}
				capturedDeaths.Add(player.actualClientId);
				ulong[] array = ReadInventory(player).Take(4096).ToArray();
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(4 + array.Length * 8, (Allocator)2, -1);
				try
				{
					int num = array.Length;
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					ulong[] array2 = array;
					for (num = 0; num < array2.Length; num++)
					{
						ulong num2 = array2[num];
						((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref num2, default(ForPrimitives));
					}
					network.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.death.v1", 0uL, val, (NetworkDelivery)4);
					return;
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			if (deathReports.TryGetValue(player.actualClientId, out HashSet<ulong> value))
			{
				claims.MarkDeath(player.actualClientId, value);
				deathReports.Remove(player.actualClientId);
			}
			if (!capturedDeaths.Contains(player.actualClientId))
			{
				HashSet<ulong> hashSet = ReadInventory(player);
				if (inventory.TryGetValue(player.actualClientId, out HashSet<ulong> value2))
				{
					hashSet.UnionWith(value2);
				}
				claims.MarkDeath(player.actualClientId, hashSet);
				capturedDeaths.Add(player.actualClientId);
			}
		}

		private void ReceiveDeath(ulong sender, FastBufferReader reader)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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)
			if (!Host || !network.ConnectedClients.ContainsKey(sender) || !((FastBufferReader)(ref reader)).TryBeginRead(4))
			{
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (num < 0 || num > 4096 || !((FastBufferReader)(ref reader)).TryBeginRead(num * 8))
			{
				return;
			}
			HashSet<ulong> hashSet = new HashSet<ulong>();
			ulong num2 = default(ulong);
			for (int i = 0; i < num; i++)
			{
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num2, default(ForPrimitives));
				if (network.SpawnManager.SpawnedObjects.TryGetValue(num2, out var value) && ((lastHolder.TryGetValue(num2, out var value2) && value2 == sender) || value.OwnerClientId == sender))
				{
					hashSet.Add(num2);
				}
			}
			deathReports[sender] = hashSet;
		}

		internal void Observe()
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!Host || !Object.op_Implicit((Object)(object)instance) || instance.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!Object.op_Implicit((Object)(object)val) || val.isPlayerDead || !val.isPlayerControlled)
				{
					continue;
				}
				HashSet<ulong> hashSet = ReadInventory(val);
				foreach (ulong item in hashSet)
				{
					claims.Recovered(item);
					lastHolder[item] = val.actualClientId;
				}
				inventory[val.actualClientId] = hashSet;
			}
			allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val2 in allPlayerScripts)
			{
				if (Object.op_Implicit((Object)(object)val2) && val2.isPlayerDead)
				{
					CaptureDeath(val2);
				}
			}
		}

		internal void Recovered(NetworkObjectReference reference, ulong holder)
		{
			NetworkObject val = default(NetworkObject);
			if (!Host || !((NetworkObjectReference)(ref reference)).TryGet(ref val, (NetworkManager)null))
			{
				return;
			}
			GrabbableObject component = ((Component)val).GetComponent<GrabbableObject>();
			foreach (ulong item in ExpandItems((IEnumerable<GrabbableObject>)(object)new GrabbableObject[1] { component }))
			{
				claims.Recovered(item);
				lastHolder[item] = holder;
			}
		}

		private static bool Eligible(GrabbableObject item)
		{
			if (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)item.itemProperties) || !Object.op_Implicit((Object)(object)item.itemProperties.spawnPrefab))
			{
				return false;
			}
			if (!item.itemProperties.isScrap)
			{
				return true;
			}
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (Object.op_Implicit((Object)(object)val) && val.buyableItemsList != null)
			{
				return val.buyableItemsList.Contains(item.itemProperties);
			}
			return false;
		}

		private static RecoveredItem Snapshot(GrabbableObject item)
		{
			return new RecoveredItem
			{
				Name = item.itemProperties.itemName,
				Prefab = ((Object)item.itemProperties.spawnPrefab).name,
				ItemId = item.itemProperties.itemId,
				Data = item.GetItemDataToSave(),
				HasBattery = (item.insertedBattery != null),
				Charge = ((item.insertedBattery != null) ? item.insertedBattery.charge : 0f),
				ScrapValue = item.scrapValue,
				UsedUp = item.itemUsedUp
			};
		}

		private Dictionary<ulong, BeltBagItem> BagParents()
		{
			Dictionary<ulong, BeltBagItem> dictionary = new Dictionary<ulong, BeltBagItem>();
			foreach (NetworkObject value in network.SpawnManager.SpawnedObjects.Values)
			{
				if (!Object.op_Implicit((Object)(object)value) || !value.IsSpawned)
				{
					continue;
				}
				BeltBagItem component = ((Component)value).GetComponent<BeltBagItem>();
				if (!Object.op_Implicit((Object)(object)component) || component.objectsInBag == null)
				{
					continue;
				}
				foreach (GrabbableObject item in component.objectsInBag)
				{
					if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((NetworkBehaviour)item).NetworkObject) && ((NetworkBehaviour)item).NetworkObject.IsSpawned)
					{
						dictionary[((NetworkBehaviour)item).NetworkObjectId] = component;
					}
				}
			}
			return dictionary;
		}

		private static int BagDepth(ulong id, Dictionary<ulong, BeltBagItem> parents)
		{
			BeltBagItem value;
			return InventoryTraversal.Depth(id, (ulong key) => (!parents.TryGetValue(key, out value)) ? ((ulong?)null) : new ulong?(((NetworkBehaviour)value).NetworkObjectId));
		}

		private static bool OwnerDead(ulong owner)
		{
			return StartOfRound.Instance.allPlayerScripts.Any((PlayerControllerB p) => Object.op_Implicit((Object)(object)p) && p.actualClientId == owner && p.isPlayerDead);
		}

		private bool CanRecoverAncestors(ulong id, Dictionary<ulong, BeltBagItem> parents, Dictionary<ulong, ulong> owners)
		{
			ulong value;
			return InventoryTraversal.AncestorsAllowed(id, (ulong key) => (!parents.TryGetValue(key, out value)) ? ((ulong?)null) : new ulong?(((NetworkBehaviour)value).NetworkObjectId), delegate(ulong parentId)
			{
				BeltBagItem val = ((IEnumerable<BeltBagItem>)parents.Values).FirstOrDefault((Func<BeltBagItem, bool>)((BeltBagItem bag) => Object.op_Implicit((Object)(object)bag) && ((NetworkBehaviour)bag).NetworkObjectId == parentId));
				if (!Object.op_Implicit((Object)(object)val) || !((NetworkBehaviour)val).NetworkObject.IsSpawned || !owners.TryGetValue(parentId, out value) || !OwnerDead(value))
				{
					return false;
				}
				bool held = !parents.ContainsKey(parentId) && (((GrabbableObject)val).isHeld || ((GrabbableObject)val).isHeldByEnemy || Object.op_Implicit((Object)(object)((GrabbableObject)val).playerHeldBy));
				return claims.CanCollect(parentId, ownerDead: true, held, inShip: false, eligible: true);
			});
		}

		internal void Collect()
		{
			if (!Host || !plugin.RecoveryEnabled || !Object.op_Implicit((Object)(object)StartOfRound.Instance))
			{
				return;
			}
			EnsureLoaded();
			if (saveFile == null || loadFailed)
			{
				return;
			}
			Observe();
			int num = 0;
			Dictionary<ulong, BeltBagItem> parents = BagParents();
			Dictionary<ulong, ulong> dictionary = claims.Snapshot().ToDictionary((KeyValuePair<ulong, ulong> pair) => pair.Key, (KeyValuePair<ulong, ulong> pair) => pair.Value);
			foreach (KeyValuePair<ulong, ulong> item2 in dictionary.OrderByDescending((KeyValuePair<ulong, ulong> pair) => BagDepth(pair.Key, parents)))
			{
				if (!network.SpawnManager.SpawnedObjects.TryGetValue(item2.Key, out var value) || !Object.op_Implicit((Object)(object)value))
				{
					continue;
				}
				GrabbableObject component = ((Component)value).GetComponent<GrabbableObject>();
				BeltBagItem value2;
				bool flag = parents.TryGetValue(item2.Key, out value2);
				if (!Object.op_Implicit((Object)(object)component) || !CanRecoverAncestors(item2.Key, parents, dictionary) || !claims.CanCollect(item2.Key, OwnerDead(item2.Value), !flag && (component.isHeld || component.isHeldByEnemy || Object.op_Implicit((Object)(object)component.playerHeldBy)), inShip: false, Eligible(component)))
				{
					continue;
				}
				BeltBagItem val = (BeltBagItem)(object)((component is BeltBagItem) ? component : null);
				if (val != null && val.objectsInBag != null)
				{
					val.objectsInBag.RemoveAll((GrabbableObject child) => !Object.op_Implicit((Object)(object)child));
					if (val.objectsInBag.Count > 0)
					{
						plugin.LogInfo("Leaving belt bag in place because some contents could not be recovered.");
						continue;
					}
				}
				string itemName = component.itemProperties.itemName;
				try
				{
					RecoveredItem item = Snapshot(component);
					contents.Add(item);
					try
					{
						Save();
					}
					catch
					{
						contents.Remove(item);
						throw;
					}
					int num2 = ((flag && Object.op_Implicit((Object)(object)value2) && value2.objectsInBag != null) ? value2.objectsInBag.IndexOf(component) : (-1));
					if (num2 >= 0)
					{
						value2.objectsInBag.RemoveAt(num2);
					}
					try
					{
						value.Despawn(true);
					}
					catch
					{
						if (num2 >= 0 && Object.op_Implicit((Object)(object)value2) && Object.op_Implicit((Object)(object)component))
						{
							value2.objectsInBag.Insert(Math.Min(num2, value2.objectsInBag.Count), component);
						}
						contents.Remove(item);
						Save();
						throw;
					}
					claims.Recovered(item2.Key);
					num++;
					if (flag && Object.op_Implicit((Object)(object)value2))
					{
						BroadcastBagRemove(((NetworkBehaviour)value2).NetworkObjectId, item2.Key);
					}
				}
				catch (Exception error)
				{
					plugin.Error("Could not collect " + itemName, error);
				}
			}
			if (num > 0)
			{
				plugin.LogInfo($"Lost and Found collected {num} items at departure; {contents.Count} awaiting retrieval.");
			}
		}

		private unsafe void BroadcastBagRemove(ulong bagId, ulong itemId)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref bagId, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref itemId, default(ForPrimitives));
				foreach (ulong connectedClientsId in network.ConnectedClientsIds)
				{
					if (connectedClientsId != network.LocalClientId)
					{
						network.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.bag-remove.v1", connectedClientsId, val, (NetworkDelivery)3);
					}
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private void ReceiveBagRemove(ulong sender, FastBufferReader reader)
		{
			//IL_0023: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (Host || sender != 0L || !((FastBufferReader)(ref reader)).TryBeginRead(16))
			{
				return;
			}
			ulong key = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref key, default(ForPrimitives));
			ulong itemId = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref itemId, default(ForPrimitives));
			if (!Object.op_Implicit((Object)(object)network) || !network.SpawnManager.SpawnedObjects.TryGetValue(key, out var value))
			{
				return;
			}
			BeltBagItem component = ((Component)value).GetComponent<BeltBagItem>();
			if (Object.op_Implicit((Object)(object)component) && component.objectsInBag != null)
			{
				component.objectsInBag.RemoveAll((GrabbableObject item) => !Object.op_Implicit((Object)(object)item) || ((NetworkBehaviour)item).NetworkObjectId == itemId);
			}
		}

		private static Item? Resolve(RecoveredItem record)
		{
			Item[] array = StartOfRound.Instance.allItemsList.itemsList.Where((Item i) => Object.op_Implicit((Object)(object)i) && Object.op_Implicit((Object)(object)i.spawnPrefab) && i.itemName == record.Name && ((Object)i.spawnPrefab).name == record.Prefab).ToArray();
			if (array.Length == 1)
			{
				return array[0];
			}
			return ((IEnumerable<Item>)array).FirstOrDefault((Func<Item, bool>)((Item i) => i.itemId == record.ItemId));
		}

		internal void Empty(Vector3 outlet)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			if (!Host)
			{
				return;
			}
			EnsureLoaded();
			if (loadFailed || saveFile == null)
			{
				return;
			}
			int num = 0;
			RecoveredItem[] array = contents.ToArray();
			foreach (RecoveredItem recoveredItem in array)
			{
				Item val = Resolve(recoveredItem);
				if (!Object.op_Implicit((Object)(object)val))
				{
					plugin.LogInfo("Keeping unavailable item in Lost and Found: " + recoveredItem.Name);
					continue;
				}
				GameObject val2 = null;
				bool flag = false;
				try
				{
					Vector3 val3 = outlet + new Vector3((float)(num % 3 - 1) * 0.1f, (float)(num / 9) * 0.025f, (float)(num / 3 % 3) * 0.1f);
					val2 = Object.Instantiate<GameObject>(val.spawnPrefab, val3, Quaternion.Euler(val.restingRotation), StartOfRound.Instance.elevatorTransform);
					GrabbableObject component = val2.GetComponent<GrabbableObject>();
					NetworkObject component2 = val2.GetComponent<NetworkObject>();
					if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2))
					{
						throw new InvalidOperationException("Recovered prefab lacks native item/network components.");
					}
					component.isInShipRoom = (component.isInElevator = true);
					component2.Spawn(false);
					RestoredItem restoredItem = new RestoredItem
					{
						Id = component2.NetworkObjectId,
						Ticket = Guid.NewGuid().ToString("N"),
						Item = recoveredItem,
						Position = StartOfRound.Instance.elevatorTransform.InverseTransformPoint(val3)
					};
					contents.Remove(recoveredItem);
					try
					{
						Save();
					}
					catch
					{
						contents.Add(recoveredItem);
						throw;
					}
					flag = true;
					num++;
					restored[restoredItem.Id] = restoredItem;
					pending[restoredItem.Id] = Time.unscaledTime + 0.2f;
					foreach (ulong connectedClientsId in network.ConnectedClientsIds)
					{
						if (connectedClientsId != network.LocalClientId)
						{
							Send(connectedClientsId, restoredItem);
						}
					}
				}
				catch (Exception error)
				{
					if (Object.op_Implicit((Object)(object)val2) && !flag)
					{
						NetworkObject component3 = val2.GetComponent<NetworkObject>();
						if (Object.op_Implicit((Object)(object)component3) && component3.IsSpawned)
						{
							component3.Despawn(true);
						}
						else
						{
							Object.Destroy((Object)(object)val2);
						}
					}
					plugin.Error(flag ? ("Returned item but state broadcast failed: " + recoveredItem.Name) : ("Could not return item; kept in bin: " + recoveredItem.Name), error);
				}
			}
			plugin.LogInfo($"Lost and Found returned {num} items; {contents.Count} remaining.");
		}

		private unsafe void Send(ulong client, RestoredItem state)
		{
			//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)
			byte[] bytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson((object)state));
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(bytes.Length + 4, (Allocator)2, -1);
			try
			{
				int num = bytes.Length;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteBytesSafe(bytes, bytes.Length, 0);
				network.CustomMessagingManager.SendNamedMessage("achachala.lostandfound.restored.v1", client, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal void SendPending(ulong client)
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (!Host)
			{
				return;
			}
			KeyValuePair<ulong, RestoredItem>[] array = restored.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<ulong, RestoredItem> keyValuePair = array[i];
				if (!network.SpawnManager.SpawnedObjects.ContainsKey(keyValuePair.Key))
				{
					restored.Remove(keyValuePair.Key);
					continue;
				}
				GrabbableObject component = ((Component)network.SpawnManager.SpawnedObjects[keyValuePair.Key]).GetComponent<GrabbableObject>();
				if (Object.op_Implicit((Object)(object)component) && !component.isHeld && !Object.op_Implicit((Object)(object)component.playerHeldBy))
				{
					RestoredItem state = new RestoredItem
					{
						Id = keyValuePair.Key,
						Ticket = keyValuePair.Value.Ticket,
						Item = Snapshot(component),
						Position = StartOfRound.Instance.elevatorTransform.InverseTransformPoint(((Component)component).transform.position)
					};
					Send(client, state);
				}
			}
		}

		private void ReceiveRestored(ulong sender, FastBufferReader reader)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (Host || sender != 0L || !((FastBufferReader)(ref reader)).TryBeginRead(4))
			{
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (num < 1 || num > 16384 || !((FastBufferReader)(ref reader)).TryBeginRead(num))
			{
				return;
			}
			byte[] bytes = new byte[num];
			((FastBufferReader)(ref reader)).ReadBytesSafe(ref bytes, num, 0);
			try
			{
				RestoredItem restoredItem = JsonUtility.FromJson<RestoredItem>(Encoding.UTF8.GetString(bytes));
				if (restoredItem != null && restoredItem.Item != null && (!applied.TryGetValue(restoredItem.Id, out string value) || !(value == restoredItem.Ticket)))
				{
					restored[restoredItem.Id] = restoredItem;
					if (!pending.ContainsKey(restoredItem.Id))
					{
						pending[restoredItem.Id] = Time.unscaledTime + 0.2f;
					}
				}
			}
			catch (Exception error)
			{
				plugin.Error("Invalid recovered item state", error);
			}
		}

		internal void ApplyPending()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)network) || !Object.op_Implicit((Object)(object)StartOfRound.Instance))
			{
				return;
			}
			KeyValuePair<ulong, float>[] array = pending.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<ulong, float> keyValuePair = array[i];
				if (Time.unscaledTime < keyValuePair.Value)
				{
					continue;
				}
				if (!network.SpawnManager.SpawnedObjects.TryGetValue(keyValuePair.Key, out var value))
				{
					if (Time.unscaledTime > keyValuePair.Value + 30f)
					{
						pending.Remove(keyValuePair.Key);
					}
					continue;
				}
				GrabbableObject component = ((Component)value).GetComponent<GrabbableObject>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					pending.Remove(keyValuePair.Key);
					continue;
				}
				try
				{
					RestoredItem restoredItem = restored[keyValuePair.Key];
					RecoveredItem item = restoredItem.Item;
					component.LoadItemSaveData(item.Data);
					component.itemUsedUp = item.UsedUp;
					if (item.HasBattery)
					{
						component.insertedBattery = new Battery(item.Charge <= 0f, Mathf.Clamp01(item.Charge));
					}
					component.SetScrapValue(item.ScrapValue);
					if (!component.isHeld && !Object.op_Implicit((Object)(object)component.playerHeldBy))
					{
						((Component)component).transform.SetParent(StartOfRound.Instance.elevatorTransform, true);
						((Component)component).transform.localPosition = restoredItem.Position;
						component.parentObject = null;
						component.isInShipRoom = (component.isInElevator = true);
						component.isInFactory = false;
						component.FallToGround(false, true, default(Vector3));
					}
					applied[keyValuePair.Key] = restoredItem.Ticket;
				}
				catch (Exception error)
				{
					plugin.Error("Could not restore all saved state for recovered item", error);
				}
				pending.Remove(keyValuePair.Key);
			}
		}

		internal void EndRound()
		{
			claims.Clear();
			inventory.Clear();
			capturedDeaths.Clear();
			lastHolder.Clear();
			deathReports.Clear();
		}

		internal void Reset()
		{
			if (!Host)
			{
				return;
			}
			EnsureLoaded();
			if (loadFailed)
			{
				return;
			}
			contents.Clear();
			EndRound();
			try
			{
				Save();
			}
			catch (Exception error)
			{
				plugin.Error("Could not clear recovery after ship reset", error);
			}
		}

		internal void Detach()
		{
			if (Object.op_Implicit((Object)(object)network) && network.CustomMessagingManager != null)
			{
				network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.restored.v1");
				network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.death.v1");
				network.CustomMessagingManager.UnregisterNamedMessageHandler("achachala.lostandfound.bag-remove.v1");
			}
			network = null;
			saveFile = null;
			contents.Clear();
			EndRound();
			restored.Clear();
			pending.Clear();
			applied.Clear();
			loadFailed = false;
		}
	}
	[Serializable]
	public sealed class RestoredItem
	{
		public ulong Id;

		public string Ticket = "";

		public RecoveredItem Item;

		public Vector3 Position;
	}
	[HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")]
	internal static class LocalDeathPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerControllerB __instance)
		{
			Plugin.Instance.Recovery.CaptureDeath(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "KillPlayerClientRpc")]
	internal static class RemoteDeathPatch
	{
		[HarmonyPrefix]
		private static void Prefix(int playerId)
		{
			StartOfRound instance = StartOfRound.Instance;
			if (Object.op_Implicit((Object)(object)instance) && playerId >= 0 && playerId < instance.allPlayerScripts.Length)
			{
				Plugin.Instance.Recovery.CaptureDeath(instance.allPlayerScripts[playerId]);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItems")]
	internal static class DeathDropPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerControllerB __instance)
		{
			if (__instance.isPlayerDead)
			{
				Plugin.Instance.Recovery.CaptureDeath(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
	internal static class DeparturePatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix()
		{
			Plugin.Instance.Recovery.Collect();
		}
	}
	[HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")]
	internal static class CleanupPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix()
		{
			Plugin.Instance.Recovery.Collect();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ReviveDeadPlayers")]
	internal static class RevivalPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			Plugin.Instance.Recovery.EndRound();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
	internal static class ShipResetPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			Plugin.Instance.Recovery.Reset();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
	internal static class RecoveredPickupPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerControllerB __instance, bool grabValidated, NetworkObjectReference grabbedObject)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (grabValidated)
			{
				Plugin.Instance.Recovery.Recovered(grabbedObject, __instance.actualClientId);
			}
		}
	}
	internal sealed class RequestGate
	{
		private readonly Dictionary<ulong, (uint sequence, double time)> accepted = new Dictionary<ulong, (uint, double)>();

		internal bool TryAccept(ulong client, uint sequence, double now, double cooldown)
		{
			if (sequence == 0 || double.IsNaN(now) || double.IsInfinity(now))
			{
				return false;
			}
			if (accepted.TryGetValue(client, out (uint, double) value) && (sequence <= value.Item1 || now - value.Item2 < cooldown))
			{
				return false;
			}
			accepted[client] = (sequence, now);
			return true;
		}

		internal void Remove(ulong client)
		{
			accepted.Remove(client);
		}

		internal void Clear()
		{
			accepted.Clear();
		}
	}
}