Decompiled source of PocketHeads v0.1.1

BepInEx/plugins/PocketHeads/PocketHeads.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Rendering;

[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("PocketHeads")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("PocketHeads")]
[assembly: AssemblyTitle("PocketHeads")]
[assembly: AssemblyVersion("0.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PocketHeads
{
	internal static class GameContract
	{
		internal static void Validate()
		{
			Check(typeof(ItemEquippable), typeof(int), "ownerPlayerId", "inventorySpotIndex");
			Check(typeof(ItemEquippable), typeof(InventorySpot), "equippedSpot");
			Check(typeof(ItemEquippable), typeof(ItemState), "currentState");
			Check(typeof(ItemEquippable), typeof(bool), "stateStart", "isEquipped", "isEquippedPrev", "isEquipping", "isUnequipping", "isForceUnequipping", "wasForceGrabbed");
			Check(typeof(ItemEquippable), typeof(float), "forceGrabTimer", "teleportPositionForcedTimer", "equipTimer", "unequipTimer", "isEquippingTimer", "isUnequippingTimer");
			Check(typeof(PlayerDeathHead), typeof(bool), "triggered", "overrideSpectated", "inExtractionPoint", "inExtractionPointPrevious", "inTruck", "inTruckPrevious");
			Check(typeof(PlayerDeathHead), typeof(float), "triggeredTimer", "inTruckReviveTimer");
			Check(typeof(PlayerAvatar), typeof(bool), "isDisabled");
			Check(typeof(PlayerAvatar), typeof(string), "steamID");
			Check(typeof(PlayerAvatar), typeof(PlayerDeathHead), "playerDeathHead");
			Check(typeof(ItemAttributes), typeof(string), "instanceName", "itemName");
			Check(typeof(ItemAttributes), typeof(bool), "hasIcon");
			Check(typeof(SpectateCamera), typeof(PlayerAvatar), "playerOverride");
			Check(typeof(PhysGrabObject), typeof(List<PhysGrabber>), "playerGrabbing");
		}

		private static void Check(Type type, Type fieldType, params string[] names)
		{
			foreach (string text in names)
			{
				if (AccessTools.Field(type, text)?.FieldType != fieldType)
				{
					throw new NotSupportedException("Pocket Heads is incompatible with this game build: " + type.Name + "." + text + " changed.");
				}
			}
		}
	}
	internal static class HeadPortrait
	{
		internal const int Size = 256;

		private const int PreviewLayer = 31;

		internal static Sprite Capture(PlayerDeathHead head)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: 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_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Expected O, but got Unknown
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			if ((int)SystemInfo.graphicsDeviceType == 4 || !Object.op_Implicit((Object)(object)head.meshParent))
			{
				return null;
			}
			GameObject val = new GameObject("Pocket Heads portrait preview")
			{
				hideFlags = (HideFlags)61
			};
			val.transform.position = new Vector3(-2000f, -2000f, -2000f);
			Dictionary<Transform, Transform> copies = new Dictionary<Transform, Transform> { [((Component)head).transform] = val.transform };
			List<Mesh> list = new List<Mesh>();
			RenderTexture val2 = null;
			Texture2D val3 = null;
			RenderTexture active = RenderTexture.active;
			bool fog = RenderSettings.fog;
			AmbientMode ambientMode = RenderSettings.ambientMode;
			Color ambientLight = RenderSettings.ambientLight;
			float ambientIntensity = RenderSettings.ambientIntensity;
			try
			{
				List<MeshRenderer> list2 = new List<MeshRenderer>();
				Renderer[] componentsInChildren = head.meshParent.GetComponentsInChildren<Renderer>(true);
				MeshFilter val7 = default(MeshFilter);
				foreach (Renderer val4 in componentsInChildren)
				{
					if (!val4.enabled || !ActivePath(((Component)val4).transform, ((Component)head).transform) || ((Object)val4).name == "mesh_eye_noise")
					{
						continue;
					}
					SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val4 is SkinnedMeshRenderer) ? val4 : null);
					Mesh val6;
					if (val5 != null)
					{
						val6 = new Mesh();
						val5.BakeMesh(val6);
						list.Add(val6);
					}
					else
					{
						if (!(val4 is MeshRenderer) || !((Component)val4).TryGetComponent<MeshFilter>(ref val7))
						{
							continue;
						}
						val6 = val7.sharedMesh;
					}
					if (!Object.op_Implicit((Object)(object)val6))
					{
						continue;
					}
					Transform obj = CopyTransform(((Component)val4).transform, ((Component)head).transform, copies);
					((Component)obj).gameObject.AddComponent<MeshFilter>().sharedMesh = val6;
					MeshRenderer val8 = ((Component)obj).gameObject.AddComponent<MeshRenderer>();
					((Renderer)val8).sharedMaterials = val4.sharedMaterials;
					MaterialPropertyBlock val9 = new MaterialPropertyBlock();
					val4.GetPropertyBlock(val9);
					((Renderer)val8).SetPropertyBlock(val9);
					for (int j = 0; j < val4.sharedMaterials.Length; j++)
					{
						val9.Clear();
						val4.GetPropertyBlock(val9, j);
						if (!val9.isEmpty)
						{
							((Renderer)val8).SetPropertyBlock(val9, j);
						}
					}
					((Renderer)val8).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)val8).receiveShadows = false;
					((Renderer)val8).lightProbeUsage = (LightProbeUsage)0;
					((Renderer)val8).reflectionProbeUsage = (ReflectionProbeUsage)0;
					list2.Add(val8);
				}
				if (list2.Count == 0)
				{
					return null;
				}
				Bounds bounds = ((Renderer)list2[0]).bounds;
				foreach (MeshRenderer item in list2)
				{
					((Bounds)(ref bounds)).Encapsulate(((Renderer)item).bounds);
				}
				float num = Mathf.Max(new float[3]
				{
					((Bounds)(ref bounds)).extents.x,
					((Bounds)(ref bounds)).extents.y,
					0.01f
				});
				GameObject val10 = new GameObject("Portrait camera");
				val10.transform.SetParent(val.transform, false);
				Camera obj2 = val10.AddComponent<Camera>();
				((Behaviour)obj2).enabled = false;
				obj2.orthographic = true;
				obj2.orthographicSize = num * 1.8f;
				obj2.aspect = 1f;
				obj2.clearFlags = (CameraClearFlags)2;
				obj2.backgroundColor = Color.clear;
				obj2.cullingMask = int.MinValue;
				obj2.allowHDR = false;
				obj2.allowMSAA = false;
				obj2.useOcclusionCulling = false;
				obj2.nearClipPlane = 0.01f;
				obj2.farClipPlane = (num + ((Bounds)(ref bounds)).extents.z) * 6f + 1f;
				((Component)obj2).transform.position = ((Bounds)(ref bounds)).center + Vector3.forward * (((Bounds)(ref bounds)).extents.z + num * 3f);
				((Component)obj2).transform.rotation = Quaternion.LookRotation(Vector3.back, Vector3.up);
				GameObject val11 = new GameObject("Portrait light");
				val11.transform.SetParent(val.transform, false);
				val11.transform.rotation = Quaternion.Euler(25f, 200f, 0f);
				Light obj3 = val11.AddComponent<Light>();
				obj3.type = (LightType)1;
				obj3.intensity = 0.85f;
				obj3.cullingMask = int.MinValue;
				obj3.shadows = (LightShadows)0;
				RenderSettings.fog = false;
				RenderSettings.ambientMode = (AmbientMode)3;
				RenderSettings.ambientLight = Color.white;
				RenderSettings.ambientIntensity = 1f;
				val2 = (obj2.targetTexture = RenderTexture.GetTemporary(256, 256, 24, (RenderTextureFormat)0));
				obj2.Render();
				RenderTexture.active = val2;
				val3 = new Texture2D(256, 256, (TextureFormat)4, false);
				((Object)val3).name = "Pocket Heads portrait";
				((Texture)val3).filterMode = (FilterMode)1;
				((Texture)val3).wrapMode = (TextureWrapMode)1;
				val3.ReadPixels(new Rect(0f, 0f, 256f, 256f), 0, 0);
				val3.Apply(false, false);
				Texture2D obj4 = Crop(val3);
				Object.Destroy((Object)(object)val3);
				val3 = obj4;
				Sprite result = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f), (float)((Texture)val3).width);
				val3 = null;
				return result;
			}
			finally
			{
				RenderTexture.active = active;
				RenderSettings.fog = fog;
				RenderSettings.ambientMode = ambientMode;
				RenderSettings.ambientLight = ambientLight;
				RenderSettings.ambientIntensity = ambientIntensity;
				val.SetActive(false);
				Object.Destroy((Object)(object)val);
				foreach (Mesh item2 in list)
				{
					Object.Destroy((Object)(object)item2);
				}
				if (Object.op_Implicit((Object)(object)val2))
				{
					RenderTexture.ReleaseTemporary(val2);
				}
				if (Object.op_Implicit((Object)(object)val3))
				{
					Object.Destroy((Object)(object)val3);
				}
			}
		}

		private static Texture2D Crop(Texture2D source)
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_0116: 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)
			Color32[] pixels = source.GetPixels32();
			int num = 256;
			int num2 = 256;
			int num3 = -1;
			int num4 = -1;
			for (int i = 0; i < 256; i++)
			{
				for (int j = 0; j < 256; j++)
				{
					if (pixels[i * 256 + j].a >= 16)
					{
						num = Mathf.Min(num, j);
						num2 = Mathf.Min(num2, i);
						num3 = Mathf.Max(num3, j);
						num4 = Mathf.Max(num4, i);
					}
				}
			}
			if (num3 < 0)
			{
				throw new InvalidOperationException("Head portrait contains no visible pixels.");
			}
			if (num == 0 || num2 == 0 || num3 == 255 || num4 == 255)
			{
				throw new InvalidOperationException("Head portrait extends past the camera frame.");
			}
			int num5 = num3 - num + 1;
			int num6 = num4 - num2 + 1;
			int num7 = Mathf.Max(num5, num6) + 12;
			int num8 = (num7 - num5) / 2;
			int num9 = (num7 - num6) / 2;
			Color32[] array = (Color32[])(object)new Color32[num7 * num7];
			for (int k = 0; k < num6; k++)
			{
				for (int l = 0; l < num5; l++)
				{
					array[(k + num9) * num7 + l + num8] = pixels[(k + num2) * 256 + l + num];
				}
			}
			Texture2D val = new Texture2D(num7, num7, (TextureFormat)4, false)
			{
				name = "Pocket Heads portrait",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1
			};
			val.SetPixels32(array);
			val.Apply(false, false);
			return val;
		}

		private static bool ActivePath(Transform part, Transform root)
		{
			Transform val = part;
			while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)root)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					return false;
				}
				val = val.parent;
			}
			return true;
		}

		private static Transform CopyTransform(Transform source, Transform root, Dictionary<Transform, Transform> copies)
		{
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (copies.TryGetValue(source, out var value))
			{
				return value;
			}
			Transform val = CopyTransform(source.parent, root, copies);
			Transform transform = new GameObject(((Object)source).name)
			{
				layer = 31
			}.transform;
			transform.SetParent(val, false);
			transform.localPosition = source.localPosition;
			transform.localRotation = source.localRotation;
			transform.localScale = source.localScale;
			copies.Add(source, transform);
			return transform;
		}
	}
	internal static class Native
	{
		private static readonly Dictionary<string, FieldInfo> Fields = new Dictionary<string, FieldInfo>();

		private static FieldInfo Field(object target, string name)
		{
			string text = target.GetType().FullName + "." + name;
			if (!Fields.TryGetValue(text, out var value))
			{
				value = AccessTools.Field(target.GetType(), name) ?? throw new MissingFieldException(text);
				Fields.Add(text, value);
			}
			return value;
		}

		internal static T Get<T>(object target, string name)
		{
			return (T)Field(target, name).GetValue(target);
		}

		internal static void Set(object target, string name, object value)
		{
			Field(target, name).SetValue(target, value);
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Start")]
	internal static class AttachPatch
	{
		private static void Postfix(PlayerDeathHead __instance)
		{
			PocketHead.Attach(__instance);
		}
	}
	[HarmonyPatch(typeof(ItemEquippable), "RPC_RequestEquip")]
	internal static class RequestEquipPatch
	{
		private static bool Prefix(ItemEquippable __instance, int spotIndex, int physGrabberPhotonViewID)
		{
			PocketHead component = ((Component)__instance).GetComponent<PocketHead>();
			foreach (PocketHead item in PocketHead.All)
			{
				if (Object.op_Implicit((Object)(object)item) && item.Stored && Native.Get<int>(item.Item, "ownerPlayerId") == physGrabberPhotonViewID && Native.Get<int>(item.Item, "inventorySpotIndex") == spotIndex)
				{
					return false;
				}
			}
			if (!Object.op_Implicit((Object)(object)component))
			{
				return true;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer() || spotIndex < 0 || spotIndex > 2 || !Native.Get<bool>(component.Head, "triggered") || Native.Get<float>(component.Head, "triggeredTimer") > 0f || Native.Get<bool>(component.Head, "overrideSpectated"))
			{
				return false;
			}
			object obj;
			if (!SemiFunc.IsMultiplayer())
			{
				obj = PlayerAvatar.instance;
			}
			else
			{
				PhotonView obj2 = PhotonView.Find(physGrabberPhotonViewID);
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<PlayerAvatar>() : null);
			}
			PlayerAvatar val = (PlayerAvatar)obj;
			if (!Object.op_Implicit((Object)(object)val) || Native.Get<bool>(val, "isDisabled"))
			{
				return false;
			}
			if (!Native.Get<List<PhysGrabber>>(component.Physics, "playerGrabbing").Contains(val.physGrabber))
			{
				return false;
			}
			StatsManager instance = StatsManager.instance;
			if ((spotIndex switch
			{
				1 => instance.playerInventorySpot2, 
				0 => instance.playerInventorySpot1, 
				_ => instance.playerInventorySpot3, 
			}).TryGetValue(Native.Get<string>(val, "steamID"), out var value))
			{
				return value == -1;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ItemEquippable), "RPC_UpdateItemState")]
	internal static class ItemStatePatch
	{
		private static void Prefix(ItemEquippable __instance, int state, int ownerId, PhotonMessageInfo _info)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			PocketHead component = ((Component)__instance).GetComponent<PocketHead>();
			if (Object.op_Implicit((Object)(object)component) && state == 2)
			{
				object obj;
				if (!SemiFunc.IsMultiplayer())
				{
					obj = PlayerAvatar.instance;
				}
				else
				{
					PhotonView obj2 = PhotonView.Find(ownerId);
					obj = ((obj2 != null) ? ((Component)obj2).GetComponent<PlayerAvatar>() : null);
				}
				PlayerAvatar val = (PlayerAvatar)obj;
				if (Object.op_Implicit((Object)(object)val) && SemiFunc.MasterAndOwnerOnlyRPC(_info, val.photonView))
				{
					component.BeforeStore();
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Update")]
	internal static class HeadUpdatePatch
	{
		private static bool Prefix(PlayerDeathHead __instance)
		{
			PocketHead component = ((Component)__instance).GetComponent<PocketHead>();
			if (!Object.op_Implicit((Object)(object)component) || !component.Stored)
			{
				return true;
			}
			component.WhileStored();
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "FixedUpdate")]
	internal static class HeadPhysicsPatch
	{
		private static bool Prefix(PlayerDeathHead __instance)
		{
			return !(((Component)__instance).GetComponent<PocketHead>()?.Stored ?? false);
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Revive")]
	internal static class ExtractionRevivePatch
	{
		private static bool Prefix(PlayerDeathHead __instance)
		{
			return !(((Component)__instance).GetComponent<PocketHead>()?.Stored ?? false);
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "ReviveRPC")]
	internal static class ExternalRevivePatch
	{
		private static void Prefix(PlayerAvatar __instance, PhotonMessageInfo _info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(_info))
			{
				PlayerDeathHead val = Native.Get<PlayerDeathHead>(__instance, "playerDeathHead");
				PocketHead pocketHead = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PocketHead>() : null);
				if (Object.op_Implicit((Object)(object)pocketHead) && pocketHead.Stored)
				{
					pocketHead.PrepareExternalRevive();
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Reset")]
	internal static class ResetHeadPatch
	{
		private static void Prefix(PlayerDeathHead __instance)
		{
			PocketHead component = ((Component)__instance).GetComponent<PocketHead>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.ClearInventoryState();
			}
		}
	}
	[HarmonyPatch(typeof(ItemEquippable), "AnimateUnequip")]
	internal static class RestoreCollidersPatch
	{
		private static IEnumerator Postfix(IEnumerator __result, ItemEquippable __instance)
		{
			PocketHead pocket = ((Component)__instance).GetComponent<PocketHead>();
			while (__result.MoveNext())
			{
				if (Object.op_Implicit((Object)(object)pocket) && !Native.Get<bool>(__instance, "isUnequipping"))
				{
					pocket.RestoreAppearance();
				}
				yield return __result.Current;
			}
			if (Object.op_Implicit((Object)(object)pocket))
			{
				pocket.RestoreAppearance();
			}
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "UpdateState")]
	internal static class SpectateStatePatch
	{
		private static void Prefix(ref State _state)
		{
			if ((int)_state != 2 || !Object.op_Implicit((Object)(object)PlayerAvatar.instance))
			{
				return;
			}
			PlayerDeathHead val = Native.Get<PlayerDeathHead>(PlayerAvatar.instance, "playerDeathHead");
			if (Object.op_Implicit((Object)(object)val))
			{
				PocketHead component = ((Component)val).GetComponent<PocketHead>();
				if (component != null && component.Stored)
				{
					_state = (State)1;
				}
			}
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "StateHead")]
	internal static class LeaveHeadCameraPatch
	{
		private static bool Prefix(SpectateCamera __instance)
		{
			if (!Object.op_Implicit((Object)(object)PlayerAvatar.instance))
			{
				return true;
			}
			PlayerDeathHead val = Native.Get<PlayerDeathHead>(PlayerAvatar.instance, "playerDeathHead");
			PocketHead pocketHead = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PocketHead>() : null);
			if (!Object.op_Implicit((Object)(object)pocketHead) || !pocketHead.Stored)
			{
				return true;
			}
			Native.Set(__instance, "playerOverride", pocketHead.Item.GetOwnerPlayerAvatar());
			AccessTools.Method(typeof(SpectateCamera), "UpdateState", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { (object)(State)1 });
			return false;
		}
	}
	[BepInPlugin("glenc.repo.pocketheads", "Pocket Heads", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "glenc.repo.pocketheads";

		internal static ManualLogSource Log;

		internal static Sprite Icon;

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			GameContract.Validate();
			Icon = CreateIcon();
			new Harmony("glenc.repo.pocketheads").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Pocket Heads 0.1.1 loaded. Each head uses one normal inventory slot. Install on every player.");
		}

		private static Sprite CreateIcon()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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)
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			Color[] array = (Color[])(object)new Color[1024];
			for (int i = 6; i < 27; i++)
			{
				for (int j = 4; j < 28; j++)
				{
					bool flag = j < 6 || j > 25 || i < 8 || i > 24;
					bool flag2 = i >= 16 && i <= 21 && ((j >= 8 && j <= 12) || (j >= 19 && j <= 23));
					bool flag3 = i == 11 && j >= 10 && j <= 21;
					array[i * 32 + j] = (Color)((flag || flag3) ? new Color(0.08f, 0.16f, 0.2f) : (flag2 ? Color.white : new Color(0.24f, 0.8f, 0.72f)));
				}
			}
			val.SetPixels(array);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
		}
	}
	public sealed class PocketHead : MonoBehaviour
	{
		internal static readonly HashSet<PocketHead> All = new HashSet<PocketHead>();

		internal PlayerDeathHead Head;

		internal ItemEquippable Item;

		internal PhysGrabObject Physics;

		private Vector3 originalScale;

		private Collider[] colliders;

		private bool[] colliderStates;

		private Vector3 lastCarrierPosition;

		private float missingCarrierTime;

		private Texture2D portraitTexture;

		internal bool Stored
		{
			get
			{
				if (Object.op_Implicit((Object)(object)Item))
				{
					return Item.IsEquipped();
				}
				return false;
			}
		}

		internal static void Attach(PlayerDeathHead head)
		{
			//IL_0041: 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)
			if (!Object.op_Implicit((Object)(object)((Component)head).GetComponent<PocketHead>()) && !Object.op_Implicit((Object)(object)((Component)head).GetComponent<ItemEquippable>()))
			{
				PocketHead pocketHead = ((Component)head).gameObject.AddComponent<PocketHead>();
				pocketHead.Head = head;
				pocketHead.Physics = ((Component)head).GetComponent<PhysGrabObject>();
				pocketHead.originalScale = ((Component)head).transform.localScale;
				ItemAttributes val = ((Component)head).gameObject.AddComponent<ItemAttributes>();
				((Behaviour)val).enabled = false;
				val.icon = Object.Instantiate<Sprite>(Plugin.Icon);
				Native.Set(val, "instanceName", "");
				Native.Set(val, "itemName", "Teammate's head");
				Native.Set(val, "hasIcon", true);
				pocketHead.Item = ((Component)head).gameObject.AddComponent<ItemEquippable>();
				pocketHead.Item.ItemIcon = val.icon;
				((Component)head).GetComponent<PhotonView>().RefreshRpcMonoBehaviourCache();
				All.Add(pocketHead);
				Plugin.Log.LogDebug((object)("Enabled inventory support on " + ((Object)head).name));
			}
		}

		internal void BeforeStore()
		{
			//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)
			RefreshPortrait();
			colliders = ((Component)this).GetComponentsInChildren<Collider>(true);
			colliderStates = new bool[colliders.Length];
			for (int i = 0; i < colliders.Length; i++)
			{
				colliderStates[i] = colliders[i].enabled;
			}
			lastCarrierPosition = ((Component)this).transform.position;
			Native.Set(Head, "inExtractionPoint", false);
			Native.Set(Head, "inExtractionPointPrevious", false);
			Native.Set(Head, "inTruck", false);
			Native.Set(Head, "inTruckPrevious", false);
			Native.Set(Head, "inTruckReviveTimer", 2f);
		}

		internal void WhileStored()
		{
			Native.Set(Head, "inExtractionPoint", false);
			Native.Set(Head, "inTruck", false);
			if (Object.op_Implicit((Object)(object)Head.mapCustom))
			{
				Head.mapCustom.Hide();
			}
		}

		private void LateUpdate()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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)
			if (!Stored)
			{
				missingCarrierTime = 0f;
				return;
			}
			PlayerAvatar ownerPlayerAvatar = Item.GetOwnerPlayerAvatar();
			if (Object.op_Implicit((Object)(object)ownerPlayerAvatar))
			{
				lastCarrierPosition = ((Component)ownerPlayerAvatar).transform.position + Vector3.up;
			}
			bool flag = !Object.op_Implicit((Object)(object)ownerPlayerAvatar) || Native.Get<bool>(ownerPlayerAvatar, "isDisabled");
			missingCarrierTime = (flag ? (missingCarrierTime + Time.deltaTime) : 0f);
			if (missingCarrierTime > 2f && SemiFunc.IsMasterClientOrSingleplayer())
			{
				missingCarrierTime = 0f;
				if (SemiFunc.IsMultiplayer())
				{
					((Component)this).GetComponent<PhotonView>().RPC("PocketHeadsReleaseOrphan", (RpcTarget)0, new object[1] { lastCarrierPosition });
				}
				else
				{
					PocketHeadsReleaseOrphan(lastCarrierPosition);
				}
			}
		}

		[PunRPC]
		public void PocketHeadsReleaseOrphan(Vector3 position, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info) && Stored)
			{
				ClearInventoryState();
				Physics.OverrideDeactivateReset();
				RestoreAppearance();
				if (SemiFunc.IsMasterClientOrSingleplayer())
				{
					Physics.Teleport(position, Quaternion.identity);
				}
				Plugin.Log.LogInfo((object)"Released a pocketed head after its carrier died or disconnected.");
			}
		}

		internal void RestoreAppearance()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = originalScale;
			if (colliders == null)
			{
				return;
			}
			for (int i = 0; i < colliders.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)colliders[i]))
				{
					colliders[i].enabled = colliderStates[i];
				}
			}
		}

		internal void ClearInventoryState()
		{
			((MonoBehaviour)Item).StopAllCoroutines();
			InventorySpot val = Native.Get<InventorySpot>(Item, "equippedSpot");
			if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.CurrentItem == (Object)(object)Item)
			{
				val.UnequipItem();
			}
			Native.Set(Item, "equippedSpot", null);
			Native.Set(Item, "currentState", (object)(ItemState)0);
			Native.Set(Item, "ownerPlayerId", -1);
			Native.Set(Item, "inventorySpotIndex", -1);
			Native.Set(Item, "stateStart", true);
			string[] array = new string[6] { "isEquipped", "isEquippedPrev", "isEquipping", "isUnequipping", "isForceUnequipping", "wasForceGrabbed" };
			foreach (string name in array)
			{
				Native.Set(Item, name, false);
			}
			array = new string[6] { "forceGrabTimer", "teleportPositionForcedTimer", "equipTimer", "unequipTimer", "isEquippingTimer", "isUnequippingTimer" };
			foreach (string name2 in array)
			{
				Native.Set(Item, name2, 0f);
			}
			RestoreAppearance();
		}

		internal void PrepareExternalRevive()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			PlayerAvatar ownerPlayerAvatar = Item.GetOwnerPlayerAvatar();
			Vector3 val = (Object.op_Implicit((Object)(object)ownerPlayerAvatar) ? (((Component)ownerPlayerAvatar).transform.position + Vector3.up) : lastCarrierPosition);
			ClearInventoryState();
			((Component)this).transform.position = val;
			((Component)this).GetComponent<Rigidbody>().position = val;
			Physics.centerPoint = val;
		}

		private void RefreshPortrait()
		{
			try
			{
				Sprite val = HeadPortrait.Capture(Head);
				if (Object.op_Implicit((Object)(object)val))
				{
					ItemAttributes component = ((Component)this).GetComponent<ItemAttributes>();
					Sprite icon = component.icon;
					component.icon = val;
					Item.ItemIcon = val;
					if (Object.op_Implicit((Object)(object)icon))
					{
						Object.Destroy((Object)(object)icon);
					}
					if (Object.op_Implicit((Object)(object)portraitTexture))
					{
						Object.Destroy((Object)(object)portraitTexture);
					}
					portraitTexture = val.texture;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not render head portrait; keeping previous icon. " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			All.Remove(this);
			if (Object.op_Implicit((Object)(object)portraitTexture))
			{
				Object.Destroy((Object)(object)portraitTexture);
			}
		}
	}
}