Decompiled source of CrowsNest v0.1.6

BepInEx/plugins/CrowsNest/CrowsNest.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CrowsNest;

internal static class Artwork
{
	private sealed class Part
	{
		internal string Name;

		internal int Kind;

		internal Color Color;

		internal Mesh Mesh;
	}

	private static readonly List<Part> parts = new List<Part>();

	internal static void Load()
	{
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0208: Expected O, but got Unknown
		using (Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("CrowsNest.patched.cnb"))
		{
			using BinaryReader binaryReader = new BinaryReader(stream);
			if (Encoding.ASCII.GetString(binaryReader.ReadBytes(4)) != "CNB1")
			{
				throw new InvalidDataException("Unknown mesh format");
			}
			int num = binaryReader.ReadInt32();
			if (num < 1 || num > 100)
			{
				throw new InvalidDataException("Invalid mesh count");
			}
			for (int i = 0; i < num; i++)
			{
				int num2 = binaryReader.ReadInt32();
				if (num2 < 1 || num2 > 256)
				{
					throw new InvalidDataException("Invalid name");
				}
				Part part = new Part();
				part.Name = Encoding.UTF8.GetString(binaryReader.ReadBytes(num2));
				part.Kind = binaryReader.ReadInt32();
				part.Color = new Color(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
				Part part2 = part;
				int num3 = binaryReader.ReadInt32();
				if (num3 < 3 || num3 > 65000)
				{
					throw new InvalidDataException("Invalid vertex count");
				}
				Vector3[] array = (Vector3[])(object)new Vector3[num3];
				Vector3[] array2 = (Vector3[])(object)new Vector3[num3];
				Vector2[] array3 = (Vector2[])(object)new Vector2[num3];
				for (int j = 0; j < num3; j++)
				{
					ref Vector3 reference = ref array[j];
					reference = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					ref Vector3 reference2 = ref array2[j];
					reference2 = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					ref Vector2 reference3 = ref array3[j];
					reference3 = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
				}
				int num4 = binaryReader.ReadInt32();
				if (num4 < 3 || num4 > 200000 || num4 % 3 != 0)
				{
					throw new InvalidDataException("Invalid triangle count");
				}
				int[] array4 = new int[num4];
				for (int k = 0; k < num4; k++)
				{
					array4[k] = binaryReader.ReadInt32();
					if (array4[k] < 0 || array4[k] >= num3)
					{
						throw new InvalidDataException("Invalid triangle index");
					}
				}
				Mesh val = new Mesh();
				((Object)val).name = "CN_" + part2.Name;
				part2.Mesh = val;
				part2.Mesh.vertices = array;
				part2.Mesh.normals = array2;
				part2.Mesh.uv = array3;
				part2.Mesh.triangles = array4;
				part2.Mesh.RecalculateBounds();
				parts.Add(part2);
			}
			if (stream.Position != stream.Length)
			{
				throw new InvalidDataException("Unexpected mesh data");
			}
		}
		Plugin.Log.LogInfo((object)("Loaded approved C geometry: " + parts.Count + " parts."));
	}

	internal static void Create(Transform root, Ship ship, List<Object> resources)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Expected O, but got Unknown
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Expected O, but got Unknown
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		if ((int)SystemInfo.graphicsDeviceType == 4)
		{
			return;
		}
		Material val = null;
		GameObject val2 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("fermenter") : null);
		if (Object.op_Implicit((Object)(object)val2))
		{
			MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val3 in componentsInChildren)
			{
				Material[] sharedMaterials = ((Renderer)val3).sharedMaterials;
				foreach (Material val4 in sharedMaterials)
				{
					if (Object.op_Implicit((Object)(object)val4) && ((Object)val4).name.StartsWith("fermenter", StringComparison.OrdinalIgnoreCase))
					{
						val = val4;
						break;
					}
				}
			}
		}
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("Native fermenter material not available; keeping vanilla mast interaction.");
		}
		foreach (Part part in parts)
		{
			GameObject val5 = new GameObject(part.Name);
			val5.transform.SetParent(root, false);
			val5.AddComponent<MeshFilter>().sharedMesh = part.Mesh;
			MeshRenderer val6 = val5.AddComponent<MeshRenderer>();
			if (part.Kind == 1)
			{
				((Renderer)val6).sharedMaterial = val;
				continue;
			}
			Material val7 = new Material(val);
			((Object)val7).name = "CN_" + part.Name;
			Texture2D val8 = new Texture2D(2, 2, (TextureFormat)4, false);
			((Object)val8).name = "CN_solid";
			val8.SetPixels((Color[])(object)new Color[4] { part.Color, part.Color, part.Color, part.Color });
			val8.Apply();
			val7.mainTexture = (Texture)(object)val8;
			if (val7.HasProperty("_Color"))
			{
				val7.SetColor("_Color", Color.white);
			}
			if (val7.HasProperty("_BumpMap"))
			{
				val7.SetTexture("_BumpMap", (Texture)null);
			}
			if (val7.HasProperty("_MetallicTex"))
			{
				val7.SetTexture("_MetallicTex", (Texture)null);
			}
			((Renderer)val6).sharedMaterial = val7;
			resources.Add((Object)(object)val7);
			resources.Add((Object)(object)val8);
		}
	}
}
[DefaultExecutionOrder(9990)]
public sealed class ClimbAnimation : MonoBehaviour
{
	private const string ClipPath = "Assets/Characters/Player/model/old_PlayerCharacter/PlayerCharacter_01_3@Climbing Up Wall.fbx";

	internal Nest Owner;

	private static AnimationClip clip;

	private static readonly int state = Animator.StringToHash("Base Layer.HoldMast");

	private Player player;

	private Animator animator;

	private RuntimeAnimatorController original;

	private AnimatorOverrideController temporary;

	private bool rootMotion;

	private bool failed;

	private Transform hips;

	private Vector3 visualPosition;

	private float hipHeight;

	private bool offsetApplied;

	private void Awake()
	{
		player = ((Component)this).GetComponent<Player>();
	}

	private static AnimationClip LoadClip()
	{
		if (Object.op_Implicit((Object)(object)clip))
		{
			return clip;
		}
		try
		{
			foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
			{
				if (allLoadedAssetBundle.Contains("Assets/Characters/Player/model/old_PlayerCharacter/PlayerCharacter_01_3@Climbing Up Wall.fbx"))
				{
					clip = allLoadedAssetBundle.LoadAsset<AnimationClip>("Assets/Characters/Player/model/old_PlayerCharacter/PlayerCharacter_01_3@Climbing Up Wall.fbx");
					if (Object.op_Implicit((Object)(object)clip))
					{
						break;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)clip) || clip.legacy || !clip.humanMotion)
			{
				Plugin.Log.LogWarning((object)"Native climbing asset is missing or not humanoid.");
				clip = null;
			}
			else
			{
				Plugin.Log.LogInfo((object)("Loaded native climb: " + ((Object)clip).name + " (" + clip.length + " seconds)."));
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Cannot load native climbing animation: " + ex.Message));
		}
		return clip;
	}

	internal bool Prepare()
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)temporary))
		{
			return true;
		}
		if (failed)
		{
			return false;
		}
		try
		{
			animator = ((Component)this).GetComponentInChildren<Animator>();
			AnimationClip val = LoadClip();
			if (!Object.op_Implicit((Object)(object)animator) || !animator.isHuman || !Object.op_Implicit((Object)(object)animator.runtimeAnimatorController) || !Object.op_Implicit((Object)(object)val) || !animator.HasState(0, state))
			{
				throw new InvalidOperationException("Climb clip/current humanoid mast state unavailable");
			}
			original = animator.runtimeAnimatorController;
			temporary = new AnimatorOverrideController(original);
			List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>(temporary.overridesCount);
			temporary.GetOverrides(list);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (Object.op_Implicit((Object)(object)list[i].Key) && ((Object)list[i].Key).name == "Hold The Mast")
				{
					list[i] = new KeyValuePair<AnimationClip, AnimationClip>(list[i].Key, val);
					flag = true;
				}
			}
			if (!flag)
			{
				throw new InvalidOperationException("Native Hold The Mast clip not found in player controller");
			}
			temporary.ApplyOverrides((IList<KeyValuePair<AnimationClip, AnimationClip>>)list);
			rootMotion = animator.applyRootMotion;
			hips = animator.GetBoneTransform((HumanBodyBones)0);
			visualPosition = ((Component)animator).transform.localPosition;
			hipHeight = ((Component)player).transform.InverseTransformPoint(hips.position).y;
			return true;
		}
		catch (Exception ex)
		{
			failed = true;
			Stop();
			Plugin.Log.LogWarning((object)("Climb animation unavailable: " + ex.Message));
			return false;
		}
	}

	private void Update()
	{
		RestoreOffset();
		if (!Object.op_Implicit((Object)(object)Owner) || !Owner.ClimbState(player, out var down, out var elapsed))
		{
			Stop();
		}
		else
		{
			if (!Prepare())
			{
				return;
			}
			if ((Object)(object)animator.runtimeAnimatorController != (Object)(object)temporary)
			{
				if ((Object)(object)animator.runtimeAnimatorController != (Object)(object)original)
				{
					Stop();
					failed = true;
					return;
				}
				animator.applyRootMotion = false;
				animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)temporary;
			}
			float num = Mathf.Repeat(elapsed / Mathf.Max(0.1f, clip.length), 1f);
			animator.Play(state, 0, down ? (1f - num) : num);
		}
	}

	private void LateUpdate()
	{
		//IL_0051: 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_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: 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)
		if (Object.op_Implicit((Object)(object)animator) && Object.op_Implicit((Object)(object)temporary) && !((Object)(object)animator.runtimeAnimatorController != (Object)(object)temporary) && Object.op_Implicit((Object)(object)hips))
		{
			float y = ((Component)player).transform.InverseTransformPoint(hips.position).y;
			Transform transform = ((Component)animator).transform;
			transform.position += ((Component)player).transform.up * (hipHeight - y);
			offsetApplied = true;
		}
	}

	private void RestoreOffset()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (offsetApplied && Object.op_Implicit((Object)(object)animator))
		{
			((Component)animator).transform.localPosition = visualPosition;
		}
		offsetApplied = false;
	}

	internal void Stop()
	{
		RestoreOffset();
		if (Object.op_Implicit((Object)(object)animator) && Object.op_Implicit((Object)(object)temporary) && (Object)(object)animator.runtimeAnimatorController == (Object)(object)temporary)
		{
			bool flag = animator.GetBool("attach_mast");
			animator.runtimeAnimatorController = original;
			animator.applyRootMotion = rootMotion;
			if (flag && ((Behaviour)animator).isActiveAndEnabled)
			{
				animator.SetBool("attach_mast", true);
				animator.Play(state, 0, 0f);
				animator.Update(0f);
			}
		}
		if (Object.op_Implicit((Object)(object)temporary))
		{
			Object.Destroy((Object)(object)temporary);
		}
		temporary = null;
		original = null;
	}

	internal static void ReleaseClip()
	{
		clip = null;
	}

	private void OnDisable()
	{
		Stop();
	}

	private void OnDestroy()
	{
		Stop();
	}
}
internal static class ClimbRules
{
	internal static float Progress(float elapsed, float duration)
	{
		if (duration <= 0f)
		{
			return 1f;
		}
		return Math.Max(0f, Math.Min(1f, elapsed / duration));
	}

	internal static float RouteFraction(float progress, bool down)
	{
		if (!down)
		{
			return progress;
		}
		return 1f - progress;
	}

	internal static bool InCorridor(float x, float y, float z, float deckY)
	{
		if (Math.Abs(x) < 3f && z > -3f && z < 4f && y > deckY - 2f)
		{
			return y < 3f;
		}
		return false;
	}
}
internal static class LeaseRules
{
	internal static readonly long Duration = TimeSpan.FromSeconds(10.0).Ticks;

	internal static readonly long ClockTolerance = TimeSpan.FromSeconds(5.0).Ticks;

	internal static bool Live(long deadline, long now)
	{
		if (deadline > now)
		{
			return deadline - now <= Duration + ClockTolerance;
		}
		return false;
	}

	internal static long Renew(long now)
	{
		return now + Duration;
	}
}
internal static class Native
{
	private static readonly FieldInfo detach = AccessTools.Field(typeof(Player), "m_detachOffset");

	private static readonly FieldInfo altitude = AccessTools.Field(typeof(Character), "m_maxAirAltitude");

	private static readonly FieldInfo lastTouch = AccessTools.Field(typeof(Character), "m_lastGroundTouch");

	private static readonly FieldInfo lastCollider = AccessTools.Field(typeof(Character), "m_lastGroundCollider");

	private static readonly FieldInfo lastBody = AccessTools.Field(typeof(Character), "m_lastGroundBody");

	private static readonly FieldInfo fallTimer = AccessTools.Field(typeof(Character), "m_fallTimer");

	private static readonly FieldInfo animationSync = AccessTools.Field(typeof(Character), "m_zanim");

	private static readonly FieldInfo syncAnimator = AccessTools.Field(typeof(ZSyncAnimation), "m_animator");

	private static readonly Action<Character> resetGround = (Action<Character>)Delegate.CreateDelegate(typeof(Action<Character>), AccessTools.Method(typeof(Character), "ResetGroundContact", (Type[])null, (Type[])null));

	private static Player transferring;

	private static float transferUntil;

	internal static void Validate()
	{
		if (detach == null || detach.FieldType != typeof(Vector3) || altitude == null || altitude.FieldType != typeof(float) || lastTouch == null || lastCollider == null || lastBody == null || fallTimer == null || animationSync == null || syncAnimator == null)
		{
			throw new MissingFieldException("Player attachment API changed");
		}
	}

	internal static void SetExit(Player p, Vector3 offset)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		detach.SetValue(p, offset);
	}

	internal static void BeginTransfer(Player p)
	{
		transferring = p;
		transferUntil = Time.time + 0.5f;
		ClearGround(p);
	}

	internal static bool ProtectFall(Player p)
	{
		if (Object.op_Implicit((Object)(object)p))
		{
			return TransferRules.Protect((Object)(object)p == (Object)(object)Player.m_localPlayer, (Object)(object)Nest.LocalRider(p) != (Object)null, (Object)(object)p == (Object)(object)transferring, Time.time, transferUntil);
		}
		return false;
	}

	internal static void ClearGround(Player p)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		resetGround((Character)(object)p);
		lastTouch.SetValue(p, 1f);
		lastCollider.SetValue(p, null);
		lastBody.SetValue(p, null);
		fallTimer.SetValue(p, 0f);
		altitude.SetValue(p, ((Component)p).transform.position.y);
	}

	internal static void SyncAttached(Player p)
	{
		//IL_0028: 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_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: 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)
		Transform attachPoint = p.GetAttachPoint();
		if (!Object.op_Implicit((Object)(object)attachPoint))
		{
			return;
		}
		Rigidbody component = ((Component)p).GetComponent<Rigidbody>();
		Rigidbody componentInParent = ((Component)attachPoint).GetComponentInParent<Rigidbody>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.position = attachPoint.position;
			component.rotation = attachPoint.rotation;
			if (!component.isKinematic)
			{
				component.linearVelocity = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.GetPointVelocity(attachPoint.position) : Vector3.zero);
				component.angularVelocity = Vector3.zero;
			}
		}
		ClearGround(p);
	}

	internal static void ResetFall(Player p, Vector3 velocity)
	{
		//IL_001c: 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_0036: Unknown result type (might be due to invalid IL or missing references)
		BeginTransfer(p);
		Rigidbody component = ((Component)p).GetComponent<Rigidbody>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.position = ((Component)p).transform.position;
			if (!component.isKinematic)
			{
				component.linearVelocity = velocity;
				component.angularVelocity = Vector3.zero;
			}
		}
		((Character)p).ResetCloth();
	}

	internal static void ReleaseMastAnimation(Player p)
	{
		if (!Object.op_Implicit((Object)(object)p) || (Object)(object)p != (Object)(object)Player.m_localPlayer || ((Character)p).IsAttached())
		{
			return;
		}
		object? value = animationSync.GetValue(p);
		ZSyncAnimation val = (ZSyncAnimation)((value is ZSyncAnimation) ? value : null);
		if (Object.op_Implicit((Object)(object)val))
		{
			object? value2 = syncAnimator.GetValue(val);
			Animator val2 = (Animator)((value2 is Animator) ? value2 : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				val2.SetBool("attach_mast", true);
				val.SetBool("attach_mast", false);
				Plugin.Log.LogInfo((object)"Released local and network mast animation.");
			}
		}
	}
}
public sealed class Nest : MonoBehaviour
{
	private const string UserKey = "gomisan.cn.user";

	private const string TokenKey = "gomisan.cn.token";

	private const string LeaseKey = "gomisan.cn.lease";

	private const string Request = "CN_Request";

	private const string Reply = "CN_Reply";

	private const string Pulse = "CN_Pulse";

	private const string Release = "CN_Release";

	private const string ClimbKey = "gomisan.cn.climb";

	private const string ClimbTimeKey = "gomisan.cn.climbTime";

	private static readonly Vector3 Stand = new Vector3(0f, 0.06f, 0.67f);

	private static Nest active;

	private static Nest pending;

	private static int nextToken = Environment.TickCount;

	private readonly List<Object> resources = new List<Object>();

	private Ship ship;

	private ZNetView view;

	private Chair mast;

	private GameObject root;

	private Transform attach;

	private Vector3 deckPoint;

	private BoxCollider onboard;

	private Vector3 originalSize;

	private Vector3 originalCenter;

	private bool ready;

	private bool registered;

	private int token;

	private ZDOID localId;

	private float requestedAt;

	private float lastPulse;

	private float attachedAt;

	private Vector3 returnLocal;

	private float lastPoseCheck;

	private Vector3[] route;

	private float routeLength;

	private float travelStarted;

	private float travelDuration;

	private int travel;

	private Quaternion deckRotation;

	private readonly List<Collider> ignored = new List<Collider>();

	private Collider riderCollider;

	private string detachReason;

	private static long Now
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return 0L;
			}
			return ZNet.instance.GetTime().Ticks;
		}
	}

	private bool Valid
	{
		get
		{
			if (ready && Object.op_Implicit((Object)(object)view))
			{
				return view.IsValid();
			}
			return false;
		}
	}

	private bool Occupied
	{
		get
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (Valid && view.GetZDO().GetZDOID("gomisan.cn.user") != ZDOID.None)
			{
				return LeaseRules.Live(view.GetZDO().GetLong("gomisan.cn.lease", 0L), Now);
			}
			return false;
		}
	}

	internal Vector3 RimForward => root.transform.forward;

	internal Vector3 RimUp => root.transform.up;

	internal static bool Supported(Ship s)
	{
		ZNetView component = ((Component)s).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
		{
			return false;
		}
		int prefab = component.GetZDO().GetPrefab();
		if (prefab != StringExtensionMethods.GetStableHashCode("VikingShip"))
		{
			return prefab == StringExtensionMethods.GetStableHashCode("VikingShip_Ashlands");
		}
		return true;
	}

	internal static Nest ForMast(Chair chair)
	{
		Nest componentInParent = ((Component)chair).GetComponentInParent<Nest>();
		if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.ready || !((Object)(object)componentInParent.mast == (Object)(object)chair))
		{
			return null;
		}
		return componentInParent;
	}

	internal static Nest LocalRider(Player player)
	{
		if (!Object.op_Implicit((Object)(object)player) || !((Object)(object)player == (Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)active) || !((Object)(object)player.GetAttachPoint() == (Object)(object)active.attach))
		{
			return null;
		}
		return active;
	}

	internal static void LeaveLocal()
	{
		Player localPlayer = Player.m_localPlayer;
		Nest nest = LocalRider(localPlayer);
		if (Object.op_Implicit((Object)(object)nest))
		{
			nest.Detach(localPlayer, "logout/plugin shutdown");
		}
		if (Object.op_Implicit((Object)(object)pending))
		{
			pending.ReleaseLocal(pending.token);
			pending = null;
		}
	}

	internal void Initialize(Ship target)
	{
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Expected O, but got Unknown
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: 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_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0313: Unknown result type (might be due to invalid IL or missing references)
		//IL_0318: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0349: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_037a: Unknown result type (might be due to invalid IL or missing references)
		//IL_043f: Unknown result type (might be due to invalid IL or missing references)
		ship = target;
		view = ((Component)target).GetComponent<ZNetView>();
		Chair[] componentsInChildren = ((Component)target).GetComponentsInChildren<Chair>(true);
		foreach (Chair val in componentsInChildren)
		{
			if (val.m_attachAnimation == "attach_mast" && ((Component)val).gameObject.activeInHierarchy)
			{
				mast = val;
				break;
			}
		}
		if (!Object.op_Implicit((Object)(object)mast))
		{
			throw new InvalidOperationException("No native mast holdfast was found.");
		}
		bool flag = view.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode("VikingShip_Ashlands");
		Vector3 localPosition = (flag ? new Vector3(0f, 15.75f, 0.03f) : new Vector3(0f, 9.35f, 0.4f));
		deckPoint = ((Component)ship).transform.InverseTransformPoint(mast.m_attachPoint.position);
		root = new GameObject("CN_PatchedNest");
		root.transform.SetParent(((Component)ship).transform, false);
		root.transform.localPosition = localPosition;
		Artwork.Create(root.transform, ship, resources);
		attach = new GameObject("LookoutAttach").transform;
		attach.SetParent(root.transform, false);
		attach.localPosition = Stand;
		attach.localRotation = Quaternion.identity;
		Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
		Vector3 centerOfMass = component.centerOfMass;
		Vector3 inertiaTensor = component.inertiaTensor;
		Quaternion inertiaTensorRotation = component.inertiaTensorRotation;
		int num = LayerMask.NameToLayer("piece");
		root.layer = ((num >= 0) ? num : ((Component)ship).gameObject.layer);
		BoxCollider val2 = root.AddComponent<BoxCollider>();
		val2.center = new Vector3(0f, 0.55f, 0f);
		val2.size = new Vector3(2.12f, 1.12f, 2.12f);
		root.AddComponent<NestInteraction>().Owner = this;
		component.centerOfMass = centerOfMass;
		component.inertiaTensor = inertiaTensor;
		component.inertiaTensorRotation = inertiaTensorRotation;
		Transform val3 = ((Component)ship).transform.Find("OnboardTrigger");
		if (!Object.op_Implicit((Object)(object)val3))
		{
			throw new InvalidOperationException("No onboard trigger found.");
		}
		onboard = ((Component)val3).GetComponent<BoxCollider>();
		if (!Object.op_Implicit((Object)(object)onboard) || !((Collider)onboard).isTrigger)
		{
			throw new InvalidOperationException("Unexpected onboard trigger layout.");
		}
		originalSize = onboard.size;
		originalCenter = onboard.center;
		float num2 = originalCenter.y - originalSize.y * 0.5f;
		float y = ((Component)onboard).transform.InverseTransformPoint(root.transform.TransformPoint(new Vector3(0f, 2.2f, 0f))).y;
		Vector3 size = originalSize;
		size.y = Mathf.Max(originalSize.y, y - num2);
		Vector3 center = originalCenter;
		center.y = num2 + size.y * 0.5f;
		onboard.size = size;
		onboard.center = center;
		view.Register<ZDOID, int>("CN_Request", (Action<long, ZDOID, int>)OnRequest);
		view.Register<int, bool>("CN_Reply", (Action<long, int, bool>)OnReply);
		view.Register<ZDOID, int>("CN_Pulse", (Action<long, ZDOID, int>)OnPulse);
		view.Register<ZDOID, int>("CN_Release", (Action<long, ZDOID, int>)OnRelease);
		registered = true;
		ready = true;
		Plugin.Log.LogInfo((object)("Added patched crow's nest to " + (flag ? "Drakkar" : "Longship") + " " + view.GetZDO().m_uid));
	}

	private bool Match(ZDOID id, int n)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if (view.GetZDO().GetZDOID("gomisan.cn.user") == id)
		{
			return view.GetZDO().GetInt("gomisan.cn.token", 0) == n;
		}
		return false;
	}

	private Player Authenticate(long sender, ZDOID id)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
		{
			return null;
		}
		GameObject val = ZNetScene.instance.FindInstance(id);
		if (!Object.op_Implicit((Object)(object)val))
		{
			return null;
		}
		ZNetView component = val.GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || component.GetZDO().GetOwner() != sender)
		{
			return null;
		}
		return val.GetComponent<Player>();
	}

	private bool NearDeck(Player p, float distance)
	{
		//IL_001e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)p) && !((Character)p).IsDead() && !((Character)p).IsTeleporting())
		{
			return Vector3.Distance(((Component)p).transform.position, ((Component)ship).transform.TransformPoint(deckPoint)) <= distance;
		}
		return false;
	}

	private bool CanEnter(Player p)
	{
		if (Valid && Object.op_Implicit((Object)(object)p) && (Object)(object)p == (Object)(object)Player.m_localPlayer && !((Character)p).IsAttached() && !((Character)p).IsEncumbered() && p.GetDoodadController() == null && NearDeck(p, 3f))
		{
			return (Object)(object)((Character)p).GetStandingOnShip() == (Object)(object)ship;
		}
		return false;
	}

	internal string Hover(bool top)
	{
		if (!ready)
		{
			return "";
		}
		Player localPlayer = Player.m_localPlayer;
		if (top)
		{
			if (!((Object)(object)LocalRider(localPlayer) == (Object)(object)this))
			{
				return "Crow's nest";
			}
			if (travel == 0)
			{
				return Localization.instance.Localize("Crow's nest\n[<color=yellow><b>$KEY_Use</b></color>] Climb down");
			}
			return "Crow's nest\nClimbing...";
		}
		if ((Object)(object)pending == (Object)(object)this)
		{
			return "Crow's nest\nWaiting for ship...";
		}
		if (Occupied)
		{
			return "Crow's nest\n<color=#aaaaaa>Occupied</color>";
		}
		return Localization.instance.Localize("Crow's nest\n[<color=yellow><b>$KEY_Use</b></color>] Climb to crow's nest");
	}

	internal void Enter(Player p)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: 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)
		if (!CanEnter(p) || Object.op_Implicit((Object)(object)active) || Object.op_Implicit((Object)(object)pending))
		{
			return;
		}
		if (Occupied)
		{
			Say(p, "Crow's nest is occupied.");
			return;
		}
		localId = ((Component)p).GetComponent<ZNetView>().GetZDO().m_uid;
		token = ++nextToken;
		if (token == 0)
		{
			token = ++nextToken;
		}
		returnLocal = ((Component)ship).transform.InverseTransformPoint(((Component)p).transform.position) + Vector3.up * 0.1f;
		deckRotation = Quaternion.Inverse(root.transform.rotation) * ((Component)p).transform.rotation;
		requestedAt = Time.time;
		pending = this;
		view.InvokeRPC("CN_Request", new object[2] { localId, token });
	}

	private void OnRequest(long sender, ZDOID id, int n)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (Valid && view.IsOwner())
		{
			Player val = Authenticate(sender, id);
			bool flag = n != 0 && NearDeck(val, 4f) && !((Character)val).IsAttached() && (!Occupied || Match(id, n));
			if (flag)
			{
				ZDO zDO = view.GetZDO();
				zDO.Set("gomisan.cn.user", id);
				zDO.Set("gomisan.cn.token", n);
				zDO.Set("gomisan.cn.lease", LeaseRules.Renew(Now));
			}
			view.InvokeRPC(sender, "CN_Reply", new object[2] { n, flag });
		}
	}

	private void OnReply(long sender, int n, bool allowed)
	{
		//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_015d: Unknown result type (might be due to invalid IL or missing references)
		if (!Valid || sender != view.GetZDO().GetOwner())
		{
			return;
		}
		if ((Object)(object)pending != (Object)(object)this || n != token)
		{
			if (allowed)
			{
				ReleaseLocal(n);
			}
			return;
		}
		pending = null;
		Player localPlayer = Player.m_localPlayer;
		if (!allowed)
		{
			Say(localPlayer, "Crow's nest is occupied or unavailable.");
			return;
		}
		if (!CanEnter(localPlayer))
		{
			ReleaseLocal(n);
			return;
		}
		ClimbAnimation climbAnimation = ((Component)localPlayer).GetComponent<ClimbAnimation>();
		if (!Object.op_Implicit((Object)(object)climbAnimation))
		{
			climbAnimation = ((Component)localPlayer).gameObject.AddComponent<ClimbAnimation>();
		}
		climbAnimation.Owner = this;
		if (!climbAnimation.Prepare())
		{
			ReleaseLocal(n);
			Say(localPlayer, "Climbing animation unavailable; see BepInEx log.");
			return;
		}
		active = this;
		attachedAt = (lastPulse = Time.time);
		try
		{
			BuildRoute();
			StartTravel(localPlayer, 1);
			Native.BeginTransfer(localPlayer);
			((Character)localPlayer).AttachStart(attach, root, true, false, true, "attach_mast", attach.InverseTransformPoint(((Component)ship).transform.TransformPoint(returnLocal)), (Transform)null);
			if ((Object)(object)localPlayer.GetAttachPoint() != (Object)(object)attach)
			{
				StopTravel(localPlayer);
				active = null;
				ReleaseLocal(n);
			}
			else
			{
				IgnoreShipSolids(localPlayer);
				EnsurePose(localPlayer);
				Say(localPlayer, "Crow's nest: look down at the basket and Use to climb down.");
				Plugin.Log.LogInfo((object)("Lookout attached: " + localId));
			}
		}
		catch
		{
			if (Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)localPlayer.GetAttachPoint() == (Object)(object)attach)
			{
				((Character)localPlayer).AttachStop();
			}
			StopTravel(localPlayer);
			RestoreShipSolids();
			active = null;
			ReleaseLocal(n);
			throw;
		}
	}

	private void OnPulse(long sender, ZDOID id, int n)
	{
		//IL_0016: 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 (Valid && view.IsOwner() && Match(id, n))
		{
			Player val = Authenticate(sender, id);
			if (Object.op_Implicit((Object)(object)val) && !((Character)val).IsDead() && InClimbCorridor(val))
			{
				view.GetZDO().Set("gomisan.cn.lease", LeaseRules.Renew(Now));
			}
		}
	}

	private void OnRelease(long sender, ZDOID id, int n)
	{
		//IL_0016: 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_0040: Unknown result type (might be due to invalid IL or missing references)
		if (Valid && view.IsOwner() && Match(id, n) && Object.op_Implicit((Object)(object)Authenticate(sender, id)))
		{
			view.GetZDO().Set("gomisan.cn.user", ZDOID.None);
			view.GetZDO().Set("gomisan.cn.lease", 0L);
			view.GetZDO().Set("gomisan.cn.token", 0);
		}
	}

	private void ReleaseLocal(int n)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)view) && view.IsValid() && localId != ZDOID.None)
		{
			view.InvokeRPC("CN_Release", new object[2] { localId, n });
		}
	}

	private void Update()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		if (Valid && Time.time - lastPoseCheck > 0.5f)
		{
			lastPoseCheck = Time.time;
			if (Occupied && Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				GameObject val = ZNetScene.instance.FindInstance(view.GetZDO().GetZDOID("gomisan.cn.user"));
				if (Object.op_Implicit((Object)(object)val))
				{
					EnsurePose(val.GetComponent<Player>());
				}
			}
		}
		if ((Object)(object)pending == (Object)(object)this && Time.time - requestedAt > 5f)
		{
			ReleaseLocal(token);
			pending = null;
			Say(Player.m_localPlayer, "No reply from ship owner. The peer controlling this ship needs Crow's Nest.");
		}
		if ((Object)(object)active != (Object)(object)this)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			RestoreShipSolids();
			ReleaseLocal(token);
			active = null;
			return;
		}
		if ((Object)(object)localPlayer.GetAttachPoint() != (Object)(object)attach)
		{
			StopTravel(localPlayer);
			ReleasePose(localPlayer);
			RestoreShipSolids();
			ReleaseLocal(token);
			active = null;
			return;
		}
		if (!Valid || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting())
		{
			Detach(localPlayer, (!Valid) ? "ship unavailable" : (((Character)localPlayer).IsDead() ? "player dead" : "teleport"));
			return;
		}
		if (Time.time - lastPulse >= 2f)
		{
			lastPulse = Time.time;
			view.InvokeRPC("CN_Pulse", new object[2] { localId, token });
		}
		if (Time.time - attachedAt > 4f && (!Occupied || !Match(localId, token)))
		{
			ZDO zDO = view.GetZDO();
			Plugin.Log.LogWarning((object)string.Concat("Reservation invalid: owner=", zDO.GetOwner(), " user=", zDO.GetZDOID("gomisan.cn.user"), " token=", zDO.GetInt("gomisan.cn.token", 0), " remaining=", ((double)(zDO.GetLong("gomisan.cn.lease", 0L) - Now) / 10000000.0).ToString("F3"), "s pulseAge=", (Time.time - lastPulse).ToString("F3"), "s"));
			Detach(localPlayer, "reservation invalid");
			Say(localPlayer, "Lookout reservation ended; returned to deck.");
		}
	}

	private void EnsurePose(Player p)
	{
		if (Object.op_Implicit((Object)(object)p) && IsOccupant(p))
		{
			RimPose rimPose = ((Component)p).GetComponent<RimPose>();
			if (!Object.op_Implicit((Object)(object)rimPose))
			{
				rimPose = ((Component)p).gameObject.AddComponent<RimPose>();
			}
			rimPose.Owner = this;
			ClimbAnimation climbAnimation = ((Component)p).GetComponent<ClimbAnimation>();
			if (!Object.op_Implicit((Object)(object)climbAnimation))
			{
				climbAnimation = ((Component)p).gameObject.AddComponent<ClimbAnimation>();
			}
			climbAnimation.Owner = this;
		}
	}

	internal bool CanPose(Player p)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if (!IsOccupant(p) || Vector3.Distance(((Component)p).transform.position, root.transform.TransformPoint(Stand)) > 0.65f)
		{
			return false;
		}
		ZNetView component = ((Component)p).GetComponent<ZNetView>();
		if (Object.op_Implicit((Object)(object)component) && component.IsValid())
		{
			return component.GetZDO().GetInt("gomisan.cn.climb", 0) == 0;
		}
		return false;
	}

	private bool IsOccupant(Player p)
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if (!Valid || !Object.op_Implicit((Object)(object)p) || ((Character)p).IsDead() || !Object.op_Implicit((Object)(object)attach))
		{
			return false;
		}
		if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
		{
			return (Object)(object)LocalRider(p) == (Object)(object)this;
		}
		ZNetView component = ((Component)p).GetComponent<ZNetView>();
		if (Object.op_Implicit((Object)(object)component) && component.IsValid() && Occupied)
		{
			return view.GetZDO().GetZDOID("gomisan.cn.user") == component.GetZDO().m_uid;
		}
		return false;
	}

	internal Vector3 RimTarget(bool left)
	{
		//IL_0024: 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)
		return root.transform.TransformPoint(new Vector3(left ? (-0.32f) : 0.32f, 1.085f, 0.9575f));
	}

	internal Vector3 ElbowHint(bool left)
	{
		//IL_0024: 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)
		return root.transform.TransformPoint(new Vector3(left ? (-0.55f) : 0.55f, 1.12f, 0.32f));
	}

	internal void PrepareDescent(Player p)
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		if (detachReason == null)
		{
			Plugin.Log.LogWarning((object)("External nest detach: " + new StackTrace(2, fNeedFileInfo: false)));
		}
		else
		{
			Plugin.Log.LogInfo((object)("Nest detach reason: " + detachReason));
		}
		if (Object.op_Implicit((Object)(object)attach) && Object.op_Implicit((Object)(object)ship))
		{
			Native.SetExit(p, attach.InverseTransformPoint(((Component)ship).transform.TransformPoint(returnLocal)));
		}
	}

	internal void FinishDescent(Player p)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)p.GetAttachPoint() == (Object)(object)attach))
		{
			StopTravel(p);
			ReleasePose(p);
			RestoreShipSolids();
			attach.localPosition = Stand;
			attach.localRotation = Quaternion.identity;
			Rigidbody val = (Object.op_Implicit((Object)(object)ship) ? ((Component)ship).GetComponent<Rigidbody>() : null);
			Native.ResetFall(p, Object.op_Implicit((Object)(object)val) ? val.GetPointVelocity(((Component)p).transform.position) : Vector3.zero);
			ReleaseLocal(token);
			if ((Object)(object)active == (Object)(object)this)
			{
				active = null;
			}
			detachReason = null;
			Plugin.Log.LogInfo((object)("Lookout returned to deck: " + localId));
		}
	}

	private bool InClimbCorridor(Player p)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = root.transform.InverseTransformPoint(((Component)p).transform.position);
		float y = root.transform.InverseTransformPoint(((Component)ship).transform.TransformPoint(deckPoint)).y;
		return ClimbRules.InCorridor(val.x, val.y, val.z, y);
	}

	internal bool ClimbState(Player p, out bool down, out float elapsed)
	{
		down = false;
		elapsed = 0f;
		if (!IsOccupant(p))
		{
			return false;
		}
		ZNetView component = ((Component)p).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
		{
			return false;
		}
		int num = component.GetZDO().GetInt("gomisan.cn.climb", 0);
		if (num != 1 && num != 2)
		{
			return false;
		}
		down = num == 2;
		elapsed = Mathf.Max(0f, (float)((double)(Now - component.GetZDO().GetLong("gomisan.cn.climbTime", Now)) / 10000000.0));
		return true;
	}

	private void BuildRoute()
	{
		//IL_0017: 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_0026: 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)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: 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)
		Vector3 val = root.transform.InverseTransformPoint(((Component)ship).transform.TransformPoint(returnLocal));
		route = (Vector3[])(object)new Vector3[7]
		{
			val,
			new Vector3(0f, val.y, 0.4f),
			new Vector3(0f, -3f, 0.4f),
			new Vector3(0f, -2.75f, 1.48f),
			new Vector3(0f, 1.25f, 1.48f),
			new Vector3(0f, 1.25f, Stand.z),
			Stand
		};
		routeLength = 0f;
		for (int i = 1; i < route.Length; i++)
		{
			routeLength += Vector3.Distance(route[i - 1], route[i]);
		}
		travelDuration = Mathf.Max(2f, routeLength / 1.55f);
	}

	private void StartTravel(Player p, int direction)
	{
		travel = direction;
		travelStarted = Time.time;
		ZDO zDO = ((Component)p).GetComponent<ZNetView>().GetZDO();
		zDO.Set("gomisan.cn.climbTime", Now);
		zDO.Set("gomisan.cn.climb", direction);
		PositionOnRoute((direction != 1) ? 1 : 0);
		Plugin.Log.LogInfo((object)("Lookout climbing " + ((direction == 1) ? "up" : "down") + ": " + travelDuration.ToString("F1") + " seconds."));
	}

	internal void Advance(Player p)
	{
		//IL_006e: 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)
		if (travel == 0 || route == null)
		{
			return;
		}
		float num = ClimbRules.Progress(Time.time - travelStarted, travelDuration);
		PositionOnRoute(ClimbRules.RouteFraction(num, travel == 2));
		if (!(num < 1f))
		{
			bool flag = travel == 2;
			StopTravel(p);
			if (flag)
			{
				Detach(p, "completed climb down");
				return;
			}
			attach.localPosition = Stand;
			attach.localRotation = Quaternion.identity;
			Plugin.Log.LogInfo((object)"Lookout reached basket.");
		}
	}

	private void PositionOnRoute(float fraction)
	{
		//IL_0023: 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_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Clamp01(fraction) * routeLength;
		for (int i = 1; i < route.Length; i++)
		{
			float num2 = Vector3.Distance(route[i - 1], route[i]);
			if (num <= num2 || i == route.Length - 1)
			{
				float num3 = ((num2 > 0.001f) ? Mathf.Clamp01(num / num2) : 1f);
				attach.localPosition = Vector3.Lerp(route[i - 1], route[i], num3);
				Quaternion val = Quaternion.Euler(0f, 180f, 0f);
				attach.localRotation = ((i == 1) ? Quaternion.Slerp(deckRotation, val, num3) : ((i >= route.Length - 2) ? Quaternion.Slerp(val, Quaternion.identity, ((float)(i - (route.Length - 2)) + num3) * 0.5f) : val));
				break;
			}
			num -= num2;
		}
	}

	internal void RequestDescent(Player p)
	{
		if (!((Object)(object)LocalRider(p) != (Object)(object)this) && travel == 0)
		{
			ClimbAnimation component = ((Component)p).GetComponent<ClimbAnimation>();
			if (!Object.op_Implicit((Object)(object)component) || !component.Prepare())
			{
				Say(p, "Climb animation unavailable; returning safely to deck.");
				Detach(p, "descent animation unavailable");
			}
			else
			{
				StartTravel(p, 2);
			}
		}
	}

	private void StopTravel(Player p)
	{
		travel = 0;
		if (Object.op_Implicit((Object)(object)p))
		{
			ZNetView component = ((Component)p).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner())
			{
				component.GetZDO().Set("gomisan.cn.climb", 0);
			}
			ClimbAnimation component2 = ((Component)p).GetComponent<ClimbAnimation>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.Stop();
			}
		}
	}

	private static void ReleasePose(Player p)
	{
		RimPose component = ((Component)p).GetComponent<RimPose>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.Release();
		}
		Native.ReleaseMastAnimation(p);
	}

	private void Detach(Player p, string reason)
	{
		detachReason = reason;
		((Character)p).AttachStop();
	}

	private void IgnoreShipSolids(Player p)
	{
		riderCollider = (Collider)(object)((Component)p).GetComponent<CapsuleCollider>();
		if (!Object.op_Implicit((Object)(object)riderCollider))
		{
			return;
		}
		Collider[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Collider>();
		foreach (Collider val in componentsInChildren)
		{
			if (Object.op_Implicit((Object)(object)val) && !val.isTrigger && (Object)(object)val != (Object)(object)riderCollider && !Physics.GetIgnoreCollision(riderCollider, val))
			{
				Physics.IgnoreCollision(riderCollider, val, true);
				ignored.Add(val);
			}
		}
	}

	private void RestoreShipSolids()
	{
		if (Object.op_Implicit((Object)(object)riderCollider))
		{
			foreach (Collider item in ignored)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					Physics.IgnoreCollision(riderCollider, item, false);
				}
			}
		}
		ignored.Clear();
		riderCollider = null;
	}

	private static void Say(Player p, string text)
	{
		if (Object.op_Implicit((Object)(object)p))
		{
			((Character)p).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
	}

	private void OnDestroy()
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)active == (Object)(object)this && Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)localPlayer.GetAttachPoint() == (Object)(object)attach)
			{
				Detach(localPlayer, "ship object destroyed/unloaded");
			}
			if ((Object)(object)pending == (Object)(object)this)
			{
				ReleaseLocal(token);
				pending = null;
			}
			if ((Object)(object)active == (Object)(object)this)
			{
				active = null;
			}
			if (Object.op_Implicit((Object)(object)onboard))
			{
				onboard.size = originalSize;
				onboard.center = originalCenter;
			}
			if (registered && Object.op_Implicit((Object)(object)view))
			{
				view.Unregister("CN_Request");
				view.Unregister("CN_Reply");
				view.Unregister("CN_Pulse");
				view.Unregister("CN_Release");
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Crow's nest cleanup: " + ex.Message));
		}
		RestoreShipSolids();
		if (Object.op_Implicit((Object)(object)root))
		{
			Object.Destroy((Object)(object)root);
		}
		foreach (Object resource in resources)
		{
			if (Object.op_Implicit(resource))
			{
				Object.Destroy(resource);
			}
		}
	}
}
public sealed class NestInteraction : MonoBehaviour, Hoverable, Interactable
{
	internal Nest Owner;

	public string GetHoverText()
	{
		if (!Object.op_Implicit((Object)(object)Owner))
		{
			return "";
		}
		return Owner.Hover(top: true);
	}

	public string GetHoverName()
	{
		return "Crow's nest";
	}

	public float GetHoverOffset()
	{
		return 0f;
	}

	public bool Interact(Humanoid user, bool hold, bool alt)
	{
		Player val = (Player)(object)((user is Player) ? user : null);
		if (!hold && Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)Owner) && (Object)(object)Nest.LocalRider(val) == (Object)(object)Owner)
		{
			Owner.RequestDescent(val);
		}
		return false;
	}

	public bool UseItem(Humanoid user, ItemData item)
	{
		return false;
	}
}
[BepInPlugin("gomisan.CrowsNest", "Crow's Nest", "0.1.6")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Id = "gomisan.CrowsNest";

	public const string Version = "0.1.6";

	internal static ManualLogSource Log;

	private Harmony harmony;

	private void Awake()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			Native.Validate();
			Artwork.Load();
			harmony = new Harmony("gomisan.CrowsNest");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Crow's Nest 0.1.6 ready: patched barrel / Longship + Drakkar.");
		}
		catch (Exception ex)
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Crow's Nest disabled during initialization: " + ex));
			((Behaviour)this).enabled = false;
		}
	}

	private void OnDestroy()
	{
		Nest.LeaveLocal();
		ClimbAnimation.ReleaseClip();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch(typeof(Ship), "Start")]
internal static class ShipStartPatch
{
	private static void Postfix(Ship __instance)
	{
		if (!Nest.Supported(__instance) || Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Nest>()))
		{
			return;
		}
		try
		{
			((Component)__instance).gameObject.AddComponent<Nest>().Initialize(__instance);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Could not add crow's nest to " + ((Object)__instance).name + ": " + ex));
			Nest component = ((Component)__instance).GetComponent<Nest>();
			if (Object.op_Implicit((Object)(object)component))
			{
				Object.Destroy((Object)(object)component);
			}
		}
	}
}
[HarmonyPatch(typeof(Chair), "GetHoverText")]
internal static class MastHoverPatch
{
	private static bool Prefix(Chair __instance, ref string __result)
	{
		Nest nest = Nest.ForMast(__instance);
		if (!Object.op_Implicit((Object)(object)nest))
		{
			return true;
		}
		__result = nest.Hover(top: false);
		return false;
	}
}
[HarmonyPatch(typeof(Chair), "Interact")]
internal static class MastInteractPatch
{
	private static bool Prefix(Chair __instance, Humanoid __0, bool __1, ref bool __result)
	{
		Nest nest = Nest.ForMast(__instance);
		if (!Object.op_Implicit((Object)(object)nest))
		{
			return true;
		}
		if (!__1)
		{
			nest.Enter((Player)(object)((__0 is Player) ? __0 : null));
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Player), "AttachStop")]
internal static class DetachPatch
{
	private static void Prefix(Player __instance, out Nest __state)
	{
		__state = Nest.LocalRider(__instance);
		if (Object.op_Implicit((Object)(object)__state))
		{
			__state.PrepareDescent(__instance);
		}
	}

	private static void Postfix(Player __instance, Nest __state)
	{
		if (Object.op_Implicit((Object)(object)__state))
		{
			__state.FinishDescent(__instance);
		}
	}
}
[HarmonyPatch(typeof(Player), "SetControls")]
internal static class LookoutControlsPatch
{
	private static void Prefix(Player __instance, ref bool ___m_autoRun, ref Vector3 __0, ref bool __1, ref bool __2, ref bool __3, ref bool __4, ref bool __5, ref bool __6, ref bool __7, ref bool __8, ref bool __9, ref bool __10, ref bool __11)
	{
		//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)
		if (Object.op_Implicit((Object)(object)Nest.LocalRider(__instance)))
		{
			___m_autoRun = false;
			__0 = Vector3.zero;
			__1 = (__2 = (__3 = (__4 = (__5 = (__6 = (__7 = (__8 = (__9 = (__10 = (__11 = false))))))))));
		}
	}
}
[HarmonyPatch(typeof(Player), "OnDeath")]
internal static class DeathPatch
{
	private static void Prefix(Player __instance)
	{
		if (Object.op_Implicit((Object)(object)Nest.LocalRider(__instance)))
		{
			Plugin.Log.LogError((object)"Unexpected death while attached to crow's nest. Inspect preceding damage diagnostics.");
			((Character)__instance).AttachStop();
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdateAttach")]
internal static class AttachmentPhysicsPatch
{
	private static void Prefix(Player __instance)
	{
		Nest nest = Nest.LocalRider(__instance);
		if (Object.op_Implicit((Object)(object)nest))
		{
			nest.Advance(__instance);
		}
	}

	private static void Postfix(Player __instance)
	{
		if (Object.op_Implicit((Object)(object)Nest.LocalRider(__instance)))
		{
			Native.SyncAttached(__instance);
		}
	}
}
[HarmonyPatch(typeof(Character), "AddRootMotion")]
internal static class ClimbRootMotionPatch
{
	private static bool Prefix(Character __instance)
	{
		return !Object.op_Implicit((Object)(object)Nest.LocalRider((Player)(object)((__instance is Player) ? __instance : null)));
	}
}
[HarmonyPatch(typeof(Character), "UpdateGroundContact")]
internal static class AttachedGroundPatch
{
	private static void Prefix(Character __instance)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (Object.op_Implicit((Object)(object)Nest.LocalRider(val)))
		{
			Native.ClearGround(val);
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class TransferDamagePatch
{
	private static bool Prefix(Character __instance, HitData __0)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Invalid comparison between Unknown and I4
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (!Object.op_Implicit((Object)(object)val) || __0 == null || !Native.ProtectFall(val))
		{
			return true;
		}
		if ((int)__0.m_hitType == 3)
		{
			Plugin.Log.LogWarning((object)("Suppressed artificial fall damage during crow's nest attachment/transfer: " + __0.GetTotalDamage()));
			return false;
		}
		Plugin.Log.LogWarning((object)string.Concat("Damage during crow's nest attachment/transfer (not suppressed): ", __0.m_hitType, " amount=", __0.GetTotalDamage()));
		return true;
	}
}
[HarmonyPatch(typeof(Game), "Logout")]
internal static class LogoutPatch
{
	private static void Prefix()
	{
		Nest.LeaveLocal();
	}
}
[HarmonyPatch(typeof(Game), "OnApplicationQuit")]
internal static class QuitPatch
{
	private static void Prefix()
	{
		Nest.LeaveLocal();
	}
}
[DefaultExecutionOrder(10000)]
public sealed class RimPose : MonoBehaviour
{
	private sealed class Arm
	{
		internal Transform Upper;

		internal Transform Lower;

		internal Transform Hand;

		internal Transform Middle;

		internal Transform Index;

		internal Transform Pinky;

		internal Quaternion U;

		internal Quaternion L;

		internal Quaternion H;

		internal bool Saved;

		internal void Restore()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (Saved)
			{
				if (Object.op_Implicit((Object)(object)Upper))
				{
					Upper.localRotation = U;
				}
				if (Object.op_Implicit((Object)(object)Lower))
				{
					Lower.localRotation = L;
				}
				if (Object.op_Implicit((Object)(object)Hand))
				{
					Hand.localRotation = H;
				}
				Saved = false;
			}
		}
	}

	internal Nest Owner;

	private Player player;

	private Arm left;

	private Arm right;

	private bool attempted;

	private bool reachReported;

	private void Awake()
	{
		player = ((Component)this).GetComponent<Player>();
	}

	private Arm FindArm(string side)
	{
		Transform val = ((Component)this).transform.Find("Visual/Armature/Hips/Spine/Spine1/Spine2/" + side + "Shoulder/" + side + "Arm");
		if (!Object.op_Implicit((Object)(object)val))
		{
			return null;
		}
		Transform val2 = val.Find(side + "ForeArm");
		if (!Object.op_Implicit((Object)(object)val2))
		{
			return null;
		}
		Transform val3 = val2.Find(side + "Hand");
		if (!Object.op_Implicit((Object)(object)val3))
		{
			return null;
		}
		Arm arm = new Arm();
		arm.Upper = val;
		arm.Lower = val2;
		arm.Hand = val3;
		arm.Middle = val3.Find(side + "HandMiddle1");
		arm.Index = val3.Find(side + "HandIndex1");
		arm.Pinky = val3.Find(side + "HandPinky1");
		return arm;
	}

	private void Update()
	{
		Restore();
	}

	private void Restore()
	{
		if (left != null)
		{
			left.Restore();
		}
		if (right != null)
		{
			right.Restore();
		}
	}

	internal void Release()
	{
		Restore();
		Owner = null;
	}

	private void LateUpdate()
	{
		if (!Object.op_Implicit((Object)(object)Owner) || !Owner.CanPose(player))
		{
			Restore();
			return;
		}
		if (!attempted)
		{
			attempted = true;
			left = FindArm("Left");
			right = FindArm("Right");
			if (left == null || right == null)
			{
				Plugin.Log.LogWarning((object)"Crow's nest arm pose unavailable for this player rig.");
			}
		}
		Apply(left, isLeft: true);
		Apply(right, isLeft: false);
	}

	private void Apply(Arm a, bool isLeft)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//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_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: 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_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: 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_02c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c9: 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_02d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0342: Unknown result type (might be due to invalid IL or missing references)
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0350: Unknown result type (might be due to invalid IL or missing references)
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_035a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0374: 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_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0388: Unknown result type (might be due to invalid IL or missing references)
		//IL_038d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03da: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f2: 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_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: 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_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: 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_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: 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_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: 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_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		if (a == null || !Object.op_Implicit((Object)(object)a.Upper) || !Object.op_Implicit((Object)(object)a.Lower) || !Object.op_Implicit((Object)(object)a.Hand))
		{
			return;
		}
		a.U = a.Upper.localRotation;
		a.L = a.Lower.localRotation;
		a.H = a.Hand.localRotation;
		a.Saved = true;
		Quaternion rotation = a.Hand.rotation;
		Vector3 val = Vector3.zero;
		if (Object.op_Implicit((Object)(object)a.Middle) && Object.op_Implicit((Object)(object)a.Index) && Object.op_Implicit((Object)(object)a.Pinky))
		{
			Vector3 val2 = a.Middle.position - a.Hand.position;
			Vector3 val3 = Vector3.Cross(val2, a.Index.position - a.Pinky.position) * (float)(isLeft ? 1 : (-1));
			if (((Vector3)(ref val2)).sqrMagnitude > 1E-05f && ((Vector3)(ref val3)).sqrMagnitude > 1E-08f)
			{
				Quaternion val4 = Quaternion.LookRotation(Owner.RimForward - Owner.RimUp * 0.15f, Owner.RimUp) * Quaternion.Inverse(Quaternion.LookRotation(val2, val3));
				val = val4 * (val2 * 0.5f - ((Vector3)(ref val3)).normalized * 0.025f);
				rotation = val4 * a.Hand.rotation;
			}
		}
		Vector3 position = a.Upper.position;
		Vector3 val5 = Owner.RimTarget(isLeft) - val;
		Vector3 val6 = val5 - position;
		float num = Vector3.Distance(position, a.Lower.position);
		float num2 = Vector3.Distance(a.Lower.position, a.Hand.position);
		if (!(num < 0.001f) && !(num2 < 0.001f) && !(((Vector3)(ref val6)).sqrMagnitude < 0.0001f))
		{
			if (!reachReported && ((Vector3)(ref val6)).magnitude > num + num2 + 0.025f)
			{
				reachReported = true;
				Plugin.Log.LogWarning((object)("Rim contact beyond arm reach by " + (((Vector3)(ref val6)).magnitude - num - num2).ToString("F3") + "m; report the player pose screenshot."));
			}
			float num3 = Mathf.Clamp(((Vector3)(ref val6)).magnitude, Mathf.Abs(num - num2) + 0.001f, num + num2 - 0.001f);
			((Vector3)(ref val6)).Normalize();
			val5 = position + val6 * num3;
			Vector3 val7 = Vector3.ProjectOnPlane(Owner.ElbowHint(isLeft) - position, val6);
			Vector3 normalized = ((Vector3)(ref val7)).normalized;
			if (((Vector3)(ref normalized)).sqrMagnitude < 0.1f)
			{
				Vector3 val8 = Vector3.ProjectOnPlane(-Owner.RimUp, val6);
				normalized = ((Vector3)(ref val8)).normalized;
			}
			float num4 = (num * num - num2 * num2 + num3 * num3) / (2f * num3);
			float num5 = Mathf.Sqrt(Mathf.Max(0f, num * num - num4 * num4));
			Vector3 val9 = position + val6 * num4 + normalized * num5;
			a.Upper.rotation = Quaternion.FromToRotation(a.Lower.position - position, val9 - position) * a.Upper.rotation;
			a.Lower.rotation = Quaternion.FromToRotation(a.Hand.position - a.Lower.position, val5 - a.Lower.position) * a.Lower.rotation;
			a.Hand.rotation = rotation;
		}
	}

	private void OnDisable()
	{
		Restore();
	}

	private void OnDestroy()
	{
		Restore();
	}
}
internal static class TransferRules
{
	internal static bool Protect(bool local, bool attached, bool sameTransferPlayer, float now, float until)
	{
		if (local)
		{
			if (!attached)
			{
				if (sameTransferPlayer)
				{
					return now < until;
				}
				return false;
			}
			return true;
		}
		return false;
	}
}