Decompiled source of OmniDirectionalMobilityGear v0.1.1

BepInEx/plugins/PeakOdmGear/PeakOdmGear.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Animations.Rigging;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Zorro.Core;

[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("PeakOdmGear")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("PeakOdmGear")]
[assembly: AssemblyTitle("PeakOdmGear")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PeakOdmGear
{
	[BepInPlugin("dev.midor.peak.odmgear", "Omni-Directional Mobility Gear", "0.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private Vector3 testStart;

		private int testStartPulls;

		public const string Id = "dev.midor.peak.odmgear";

		public const string Version = "0.1.0";

		internal static Plugin Instance;

		internal Character? owner;

		internal bool attached;

		internal bool testMode;

		internal int shots;

		internal int pulls;

		internal GameObject? visual;

		internal Collider? anchor;

		internal Vector3 anchorLocal;

		internal float firedAt;

		internal float nextShot;

		private float nextBind;

		private float initialStowUntil;

		private Harmony? harmony;

		private GameObject? driver;

		private LineRenderer? cable;

		private Material? cableMaterial;

		private Transform? claw;

		private Transform? hand;

		private Vector3 clawRest;

		private Quaternion clawRotation;

		private RescueHook? prefab;

		private bool enabledGear = true;

		private bool faulted;

		private string status = "READY";

		internal ConfigEntry<float> range;

		internal ConfigEntry<float> speed;

		private ConfigEntry<bool> showHud;

		private Func<Character, bool> canInput;

		private Action<Character, Vector3, float, float> addForce;

		private IEnumerator IntegrationTest()
		{
			List<string> report = new List<string>();
			string path = Path.Combine(Paths.BepInExRootPath, "ODM-integration.txt");
			File.WriteAllText(path, "RUNNING " + DateTime.UtcNow.ToString("O"));
			GameObject fixture = null;
			GameObject target = null;
			GameObject blocker = null;
			float timeout = Time.realtimeSinceStartup + 90f;
			while (!Object.op_Implicit((Object)(object)Object.FindFirstObjectByType<MainMenu>()) && Time.realtimeSinceStartup < timeout)
			{
				yield return null;
			}
			MainMenu menu = Object.FindFirstObjectByType<MainMenu>();
			if (!Object.op_Implicit((Object)(object)menu))
			{
				FinishTest(path, report, "FAIL: Title menu timeout");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(2f);
			try
			{
				if (faulted)
				{
					throw new Exception("Plugin initialization fault");
				}
				RescueHook val = FindPrefab();
				report.Add("PASS native rescue prefab: " + ((Object)val).name + ", mesh count=" + ((Component)val).GetComponentsInChildren<MeshFilter>(true).Length);
				AccessTools.Method(typeof(MainMenu), "StartSoloSession", (Type[])null, (Type[])null).Invoke(menu, null);
			}
			catch (Exception ex)
			{
				FinishTest(path, report, "FAIL startup: " + ex);
				yield break;
			}
			timeout = Time.realtimeSinceStartup + 90f;
			while ((!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)visual)) && Time.realtimeSinceStartup < timeout)
			{
				yield return null;
			}
			if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)visual))
			{
				FinishTest(path, report, "FAIL: local character/equipment timeout");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(14f);
			ScreenCapture.CaptureScreenshot(Path.Combine(Paths.BepInExRootPath, "ODM-equipped.png"));
			yield return (object)new WaitForSecondsRealtime(1f);
			try
			{
				Character val2 = owner;
				Scene activeScene = SceneManager.GetActiveScene();
				report.Add("PASS automatic equipment: scene=" + ((Scene)(ref activeScene)).name + ", meshes=" + visual.GetComponentsInChildren<MeshRenderer>().Length);
				if (visual.GetComponentsInChildren<Collider>().Length != 0 || visual.GetComponentsInChildren<Item>().Length != 0)
				{
					throw new Exception("Visual contains gameplay components");
				}
				report.Add("PASS hand visual has no inventory item or collision component");
				if (!InputAllowed(val2))
				{
					throw new Exception("Airport player input unavailable");
				}
				fixture = GameObject.CreatePrimitive((PrimitiveType)3);
				((Object)fixture).name = "ODM Temporary Test Platform";
				fixture.layer = LayerMask.NameToLayer("Map");
				fixture.transform.position = new Vector3(2000f, 1998f, 2000f);
				fixture.transform.localScale = new Vector3(80f, 2f, 80f);
				Physics.SyncTransforms();
				AccessTools.MethodDelegate<Action<Character, Vector3, bool>>(AccessTools.Method(typeof(Character), "WarpPlayer", new Type[2]
				{
					typeof(Vector3),
					typeof(bool)
				}, (Type[])null), (object)null, true)(val2, new Vector3(2000f, 2001f, 2000f), arg3: false);
			}
			catch (Exception ex2)
			{
				if (Object.op_Implicit((Object)(object)fixture))
				{
					Object.Destroy((Object)(object)fixture);
				}
				FinishTest(path, report, "FAIL fixture: " + ex2);
				yield break;
			}
			yield return (object)new WaitForSeconds(2f);
			try
			{
				Character val3 = owner;
				Vector3 val4 = val3.Center + Vector3.up * 2f;
				target = GameObject.CreatePrimitive((PrimitiveType)3);
				((Object)target).name = "ODM Integration Target";
				target.layer = LayerMask.NameToLayer("Map");
				target.transform.position = val4 + Vector3.up * 10f;
				target.transform.localScale = Vector3.one * 2f;
				Physics.SyncTransforms();
				Ray ray = default(Ray);
				((Ray)(ref ray))..ctor(val4, Vector3.up);
				if (!FindHit(ray, out var hit) || (Object)(object)((Component)((RaycastHit)(ref hit)).collider).gameObject != (Object)(object)target)
				{
					throw new Exception("Ray did not select test target, hit=" + (object)((RaycastHit)(ref hit)).collider);
				}
				report.Add("PASS actual Unity raycast hit target");
				for (int i = 0; i < 100; i++)
				{
					nextShot = 0f;
					if (!Fire(ray))
					{
						throw new Exception("Repeated shot failed " + i);
					}
					Release("TEST");
				}
				report.Add("PASS 100 consecutive shots with unlimited ammunition");
				blocker = GameObject.CreatePrimitive((PrimitiveType)3);
				blocker.layer = LayerMask.NameToLayer("Map");
				blocker.transform.position = val4 + Vector3.up * 4f;
				Physics.SyncTransforms();
				if (!FindHit(ray, out hit) || (Object)(object)((Component)((RaycastHit)(ref hit)).collider).gameObject != (Object)(object)blocker)
				{
					throw new Exception("Nearest surface did not block rear target");
				}
				report.Add("PASS nearest obstruction wins");
				blocker.SetActive(false);
				Physics.SyncTransforms();
				nextShot = 0f;
				if (!Fire(ray))
				{
					throw new Exception("Motion shot failed");
				}
				testStart = val3.Center;
				testStartPulls = pulls;
			}
			catch (Exception ex3)
			{
				if (Object.op_Implicit((Object)(object)fixture))
				{
					Object.Destroy((Object)(object)fixture);
				}
				if (Object.op_Implicit((Object)(object)target))
				{
					Object.Destroy((Object)(object)target);
				}
				if (Object.op_Implicit((Object)(object)blocker))
				{
					Object.Destroy((Object)(object)blocker);
				}
				FinishTest(path, report, "FAIL setup: " + ex3);
				yield break;
			}
			yield return (object)new WaitForSeconds(0.8f);
			MouseState val7;
			try
			{
				Character val5 = owner;
				float num = Vector3.Distance(val5.Center, testStart);
				float num2 = val5.Center.y - testStart.y;
				if (pulls <= testStartPulls || num2 < 0.2f)
				{
					throw new Exception("No measured upward pull; moved=" + num + " rose=" + num2 + " ticks=" + (pulls - testStartPulls) + " status=" + status);
				}
				report.Add("PASS real local Character force: displacement=" + num.ToString("F2") + ", rise=" + num2.ToString("F2") + ", physics ticks=" + (pulls - testStartPulls));
				Release("TEST COMPLETE");
				if (attached || ((Renderer)cable).enabled)
				{
					throw new Exception("Release left cable active");
				}
				report.Add("PASS release clears attachment and cable");
				nextShot = 0f;
				if (Fire(new Ray(new Vector3(30000f, 30000f, 30000f), Vector3.up)))
				{
					throw new Exception("Miss attached a cable");
				}
				report.Add("PASS miss does not attach");
				Mouse val6 = InputSystem.AddDevice<Mouse>((string)null);
				try
				{
					val7 = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)val6, ((MouseState)(ref val7)).WithButton((MouseButton)0, true), -1.0);
					InputSystem.Update();
					AccessTools.Method(typeof(CharacterInput), "Sample", (Type[])null, (Type[])null).Invoke(val5.input, new object[1] { true });
					if (!val5.input.usePrimaryIsPressed || val5.input.useSecondaryIsPressed)
					{
						throw new Exception("LMB/RMB routing failed");
					}
					report.Add("PASS synthetic LMB through native sampler preserves climb input");
					Camera component = ((Component)MainCamera.instance).GetComponent<Camera>();
					target.transform.position = ((Component)component).transform.position + ((Component)component).transform.forward * 7f;
					Physics.SyncTransforms();
					nextShot = 0f;
					int num3 = shots;
					val7 = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)val6, ((MouseState)(ref val7)).WithButton((MouseButton)1, true), -1.0);
					InputSystem.Update();
					AccessTools.Method(typeof(CharacterInput), "Sample", (Type[])null, (Type[])null).Invoke(val5.input, new object[1] { true });
					if (val5.input.useSecondaryIsPressed || val5.input.useSecondaryWasPressed)
					{
						throw new Exception("RMB native secondary not suppressed");
					}
					report.Add("PASS synthetic RMB suppresses native secondary-use conflict");
					if (shots != num3 + 1 || !attached)
					{
						throw new Exception("RMB did not fire through native input sampler");
					}
					report.Add("PASS synthetic RMB fires aimed hook through native input sampler");
					enabledGear = false;
					val5.input.useSecondaryIsPressed = true;
					Sample(val5.input, movementActive: true);
					if (!val5.input.useSecondaryIsPressed)
					{
						throw new Exception("Disabled gear intercepted normal controls");
					}
					enabledGear = true;
					report.Add("PASS disabled gear restores native input");
					target.SetActive(false);
					PhysicsTick();
					if (attached)
					{
						throw new Exception("Destroyed/disabled anchor did not release");
					}
					report.Add("PASS lost anchor releases cable");
					val7 = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)val6, val7, -1.0);
					InputSystem.Update();
				}
				finally
				{
					InputSystem.RemoveDevice((InputDevice)(object)val6);
				}
				report.Add("INFO physics suite complete; beginning wall-climb test.");
				if (Object.op_Implicit((Object)(object)target))
				{
					Object.Destroy((Object)(object)target);
				}
				if (Object.op_Implicit((Object)(object)blocker))
				{
					Object.Destroy((Object)(object)blocker);
				}
				AccessTools.MethodDelegate<Action<Character, Vector3, bool>>(AccessTools.Method(typeof(Character), "WarpPlayer", new Type[2]
				{
					typeof(Vector3),
					typeof(bool)
				}, (Type[])null), (object)null, true)(val5, new Vector3(2000f, 2001f, 2000f), arg3: false);
			}
			catch (Exception ex4)
			{
				if (Object.op_Implicit((Object)(object)fixture))
				{
					Object.Destroy((Object)(object)fixture);
				}
				if (Object.op_Implicit((Object)(object)target))
				{
					Object.Destroy((Object)(object)target);
				}
				if (Object.op_Implicit((Object)(object)blocker))
				{
					Object.Destroy((Object)(object)blocker);
				}
				FinishTest(path, report, "FAIL motion: " + ex4);
				yield break;
			}
			yield return (object)new WaitForSeconds(2f);
			Mouse climbMouse = null;
			GameObject wall = null;
			try
			{
				Character? obj = owner;
				Camera component2 = ((Component)MainCamera.instance).GetComponent<Camera>();
				Vector3 val8 = Vector3.ProjectOnPlane(obj.data.lookDirection, Vector3.up);
				Vector3 normalized = ((Vector3)(ref val8)).normalized;
				wall = GameObject.CreatePrimitive((PrimitiveType)3);
				((Object)wall).name = "ODM Climb Transfer Test Wall";
				wall.layer = LayerMask.NameToLayer("Map");
				wall.transform.position = ((Component)component2).transform.position + normalized * 0.9f;
				wall.transform.rotation = Quaternion.LookRotation(normalized);
				wall.transform.localScale = new Vector3(8f, 10f, 0.2f);
				Physics.SyncTransforms();
				climbMouse = InputSystem.AddDevice<Mouse>((string)null);
				Mouse obj2 = climbMouse;
				val7 = default(MouseState);
				InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)obj2, ((MouseState)(ref val7)).WithButton((MouseButton)0, true), -1.0);
				InputSystem.Update();
			}
			catch (Exception ex5)
			{
				if (Object.op_Implicit((Object)(object)fixture))
				{
					Object.Destroy((Object)(object)fixture);
				}
				if (Object.op_Implicit((Object)(object)wall))
				{
					Object.Destroy((Object)(object)wall);
				}
				if (climbMouse != null)
				{
					InputSystem.RemoveDevice((InputDevice)(object)climbMouse);
				}
				FinishTest(path, report, "FAIL climb setup: " + ex5);
				yield break;
			}
			yield return (object)new WaitForSeconds(0.5f);
			Character val9 = owner;
			RaycastHit val10 = default(RaycastHit);
			Physics.Raycast(new Ray(((Component)MainCamera.instance).transform.position, val9.data.lookDirection), ref val10, 1.25f, LayerMask.op_Implicit(HelperFunctions.terrainMapMask));
			string[] obj3 = new string[18]
			{
				"INFO climb state primary=",
				val9.input.usePrimaryIsPressed.ToString(),
				" item=",
				((object)val9.data.currentItem)?.ToString(),
				" sincePress=",
				val9.data.sincePressClimb.ToString(),
				" sinceClimb=",
				val9.data.sinceClimb.ToString(),
				" ragdoll=",
				val9.data.currentRagdollControll.ToString(),
				" alive=",
				Ready(val9).ToString(),
				" hit=",
				((object)((RaycastHit)(ref val10)).collider)?.ToString(),
				" mouse=",
				null,
				null,
				null
			};
			Mouse current = Mouse.current;
			obj3[15] = ((current != null) ? ((InputControl)current).name : null);
			obj3[16] = " held=";
			obj3[17] = climbMouse.leftButton.isPressed.ToString();
			report.Add(string.Concat(obj3));
			bool climbed = Object.op_Implicit((Object)(object)owner) && owner.data.isClimbing;
			report.Add((climbed ? "PASS" : "FAIL") + " actual LMB held starts native wall climbing");
			Mouse obj4 = climbMouse;
			val7 = default(MouseState);
			InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)obj4, val7, -1.0);
			yield return (object)new WaitForSeconds(0.3f);
			bool flag = Object.op_Implicit((Object)(object)owner) && !owner.data.isClimbing;
			report.Add((flag ? "PASS" : "FAIL") + " releasing LMB ends native wall climbing");
			InputSystem.RemoveDevice((InputDevice)(object)climbMouse);
			if (Object.op_Implicit((Object)(object)fixture))
			{
				Object.Destroy((Object)(object)fixture);
			}
			if (Object.op_Implicit((Object)(object)wall))
			{
				Object.Destroy((Object)(object)wall);
			}
			report.Add("NOT TESTED: physical mouse clicks, multiplayer, full-run endurance.");
			FinishTest(path, report, (climbed && flag) ? "PASS automated game-engine integration" : "FAIL wall-climb integration");
		}

		private void FinishTest(string path, List<string> report, string outcome)
		{
			Release("READY");
			report.Add(outcome);
			report.Add("gameMvid=" + typeof(Character).Module.ModuleVersionId);
			report.Add("unity=" + Application.unityVersion);
			File.WriteAllLines(path, report);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ODM_TEST " + outcome));
			if (Environment.GetCommandLineArgs().Contains("--odm-test-quit"))
			{
				Application.Quit();
			}
			else
			{
				testMode = false;
			}
		}

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			Instance = this;
			range = ((BaseUnityPlugin)this).Config.Bind<float>("Gear", "Range", 40f, new ConfigDescription("Maximum hook distance in game units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 120f), Array.Empty<object>()));
			speed = ((BaseUnityPlugin)this).Config.Bind<float>("Gear", "PullSpeed", 16f, new ConfigDescription("Target pull speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 30f), Array.Empty<object>()));
			showHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowHud", true, "Show English controls and hook status.");
			try
			{
				canInput = AccessTools.MethodDelegate<Func<Character, bool>>(AccessTools.Method(typeof(Character), "CanDoInput", (Type[])null, (Type[])null), (object)null, true);
				addForce = AccessTools.MethodDelegate<Action<Character, Vector3, float, float>>(AccessTools.Method(typeof(Character), "AddForce", new Type[3]
				{
					typeof(Vector3),
					typeof(float),
					typeof(float)
				}, (Type[])null), (object)null, true);
				harmony = new Harmony("dev.midor.peak.odmgear");
				harmony.PatchAll();
				driver = new GameObject("ODM Gear Runtime");
				Object.DontDestroyOnLoad((Object)(object)driver);
				driver.AddComponent<GearDriver>();
				SceneManager.activeSceneChanged += SceneChanged;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ODM_READY version=0.1.0 gameMvid=" + typeof(Character).Module.ModuleVersionId));
				testMode = Environment.GetCommandLineArgs().Contains("--odm-integration-test");
				if (testMode)
				{
					Application.runInBackground = true;
					((MonoBehaviour)this).StartCoroutine(IntegrationTest());
				}
			}
			catch (Exception e)
			{
				Fail(e);
			}
		}

		internal void Fail(Exception e)
		{
			if (!faulted)
			{
				faulted = true;
				Release("ERROR - check BepInEx log");
				((BaseUnityPlugin)this).Logger.LogError((object)e);
			}
		}

		private void SceneChanged(Scene oldScene, Scene newScene)
		{
			Cleanup();
			nextBind = 0f;
		}

		internal bool Ready(Character? c)
		{
			if (!faulted && enabledGear && Object.op_Implicit((Object)(object)c) && c.IsLocal && Object.op_Implicit((Object)(object)c.data) && !c.data.dead && !c.data.passedOut && !c.data.fullyPassedOut && !c.warping && !c.data.isCarried && !Object.op_Implicit((Object)(object)c.data.carrier) && !Object.op_Implicit((Object)(object)c.data.carrierCondor))
			{
				return !Object.op_Implicit((Object)(object)c.data.grabJoint);
			}
			return false;
		}

		internal bool InputAllowed(Character? c)
		{
			if (Ready(c) && Object.op_Implicit((Object)(object)GUIManager.instance) && canInput(c) && Time.timeScale > 0f)
			{
				if (!testMode)
				{
					return Application.isFocused;
				}
				return true;
			}
			return false;
		}

		internal bool OwnsInput(CharacterInput input)
		{
			if (Object.op_Implicit((Object)(object)owner) && (Object)(object)owner.input == (Object)(object)input)
			{
				return InputAllowed(owner);
			}
			return false;
		}

		internal void Sample(CharacterInput input, bool movementActive)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (!OwnsInput(input) || !movementActive)
			{
				return;
			}
			Mouse current = Mouse.current;
			if (current != null)
			{
				input.useSecondaryWasPressed = false;
				input.useSecondaryIsPressed = false;
				input.useSecondaryWasReleased = false;
				if (Object.op_Implicit((Object)(object)owner.data.currentItem) && (current.leftButton.wasPressedThisFrame || current.rightButton.wasPressedThisFrame))
				{
					owner.refs.items.EquipSlot(Optionable<byte>.None);
				}
				if (!Object.op_Implicit((Object)(object)owner.data.currentItem))
				{
					input.usePrimaryWasPressed = current.leftButton.wasPressedThisFrame;
					input.usePrimaryIsPressed = current.leftButton.isPressed;
					input.usePrimaryWasReleased = current.leftButton.wasReleasedThisFrame;
				}
				if (current.rightButton.wasPressedThisFrame && Object.op_Implicit((Object)(object)MainCamera.instance))
				{
					Fire(((Component)MainCamera.instance).GetComponent<Camera>().ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f)));
				}
			}
		}

		internal void Tick()
		{
			//IL_0105: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			if (faulted)
			{
				return;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)(object)owner && Time.unscaledTime >= nextBind)
			{
				nextBind = Time.unscaledTime + 0.5f;
				Cleanup();
				if (Object.op_Implicit((Object)(object)localCharacter) && localCharacter.refs != null && Object.op_Implicit((Object)(object)localCharacter.refs.ragdoll) && Object.op_Implicit((Object)(object)localCharacter.refs.ikRight))
				{
					owner = localCharacter;
					initialStowUntil = Time.time + 4f;
					CreateVisual();
					ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
					Scene activeScene = SceneManager.GetActiveScene();
					logger.LogInfo((object)("ODM_EQUIPPED " + ((Scene)(ref activeScene)).name));
				}
			}
			if (Object.op_Implicit((Object)(object)owner))
			{
				if (enabledGear && Time.time < initialStowUntil && Object.op_Implicit((Object)(object)owner.data.currentItem))
				{
					owner.refs.items.EquipSlot(Optionable<byte>.None);
					initialStowUntil = 0f;
				}
				if (!testMode && Application.isFocused && Keyboard.current != null && ((ButtonControl)Keyboard.current.f6Key).wasPressedThisFrame)
				{
					enabledGear = !enabledGear;
					Release(enabledGear ? "READY" : "DISABLED");
				}
				if (!InputAllowed(owner) && attached)
				{
					Release("READY");
				}
				if (!testMode && attached && Keyboard.current != null && ((ButtonControl)Keyboard.current.spaceKey).wasPressedThisFrame)
				{
					Release("RELEASED");
				}
				if (Object.op_Implicit((Object)(object)visual))
				{
					visual.SetActive(Ready(owner));
				}
			}
		}

		internal bool FindHit(Ray ray, out RaycastHit hit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			hit = default(RaycastHit);
			float num = float.PositiveInfinity;
			RaycastHit[] array = Physics.RaycastAll(ray, range.Value, LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptDefault), (QueryTriggerInteraction)1);
			Item val2 = default(Item);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) && (!Object.op_Implicit((Object)(object)owner) || !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(((Component)owner).transform)) && (!Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).rigidbody) || !((Component)((RaycastHit)(ref val)).rigidbody).TryGetComponent<Item>(ref val2) || !((Object)(object)val2.holderCharacter == (Object)(object)owner)) && ((RaycastHit)(ref val)).distance < num)
				{
					hit = val;
					num = ((RaycastHit)(ref val)).distance;
				}
			}
			if (Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider) && ((RaycastHit)(ref hit)).distance >= 1f && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Character>()))
			{
				return !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Item>());
			}
			return false;
		}

		internal bool Fire(Ray ray)
		{
			//IL_003a: 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_0159: Unknown result type (might be due to invalid IL or missing references)
			if (!InputAllowed(owner) || Time.time < nextShot)
			{
				return false;
			}
			nextShot = Time.time + 0.22f;
			Release("NO SURFACE IN RANGE");
			if (!FindHit(ray, out var hit))
			{
				return false;
			}
			Character val = owner;
			if (val.data.isRopeClimbing || val.data.isVineClimbing || Object.op_Implicit((Object)(object)val.data.currentClimbHandle))
			{
				status = "RELEASE CLIMB HANDLE FIRST";
				return false;
			}
			if (val.data.isClimbing)
			{
				val.refs.view.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f });
			}
			anchor = ((RaycastHit)(ref hit)).collider;
			anchorLocal = ((Component)anchor).transform.InverseTransformPoint(((RaycastHit)(ref hit)).point);
			attached = true;
			firedAt = Time.time;
			shots++;
			status = "PULLING";
			if (Object.op_Implicit((Object)(object)cable))
			{
				((Renderer)cable).enabled = true;
			}
			if (Object.op_Implicit((Object)(object)prefab))
			{
				SFX_Instance[] rescueShot = prefab.rescueShot;
				foreach (SFX_Instance val2 in rescueShot)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val2.Play(val.Center);
					}
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ODM_FIRE shot=" + shots + " distance=" + ((RaycastHit)(ref hit)).distance.ToString("F1")));
			return true;
		}

		internal void PhysicsTick()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: 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_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			if (!attached)
			{
				return;
			}
			if (!InputAllowed(owner) || !Object.op_Implicit((Object)(object)anchor) || !anchor.enabled || !((Component)anchor).gameObject.activeInHierarchy)
			{
				Release("READY");
				return;
			}
			Character val = owner;
			if (val.data.isClimbingAnything)
			{
				Release("CLIMBING");
				return;
			}
			Vector3 val2 = ((Component)anchor).transform.TransformPoint(anchorLocal) - val.Center;
			if (((Vector3)(ref val2)).magnitude < 1.4f)
			{
				Release("ARRIVED - LMB TO CLIMB");
				return;
			}
			if (((Vector3)(ref val2)).magnitude > range.Value * 1.5f || Time.time - firedAt > 6f)
			{
				Release("READY");
				return;
			}
			RaycastHit[] array = Physics.RaycastAll(val.Center, ((Vector3)(ref val2)).normalized, Mathf.Max(0f, ((Vector3)(ref val2)).magnitude - 0.15f), LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptDefault), (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val3 = array[i];
				if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)(object)anchor) && !((Component)((RaycastHit)(ref val3)).collider).transform.IsChildOf(((Component)val).transform))
				{
					Item componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<Item>();
					if (!((Object)(object)((componentInParent != null) ? componentInParent.holderCharacter : null) == (Object)(object)val))
					{
						Release("CABLE BLOCKED");
						return;
					}
				}
			}
			if (!(Time.time - firedAt < 0.1f))
			{
				float num = Mathf.Min(speed.Value, Mathf.Sqrt(50f * Mathf.Max(0f, ((Vector3)(ref val2)).magnitude - 1f)));
				Vector3 arg = Vector3.ClampMagnitude((((Vector3)(ref val2)).normalized * num - val.data.avarageVelocity) * 7f + Vector3.up * 12f, 90f);
				addForce(val, arg, 1f, 1f);
				val.data.sinceGrounded = 0f;
				pulls++;
			}
		}

		internal void Release(string message)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			attached = false;
			anchor = null;
			status = message;
			if (Object.op_Implicit((Object)(object)cable))
			{
				((Renderer)cable).enabled = false;
			}
			if (Object.op_Implicit((Object)(object)claw))
			{
				claw.localPosition = clawRest;
				claw.localRotation = clawRotation;
			}
		}

		internal void RenderTick()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)visual) || !Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)MainCamera.instance))
			{
				return;
			}
			Character val = owner;
			if (Ready(val) && !Object.op_Implicit((Object)(object)val.data.currentItem) && !val.data.isClimbingAnything)
			{
				Transform transform = ((Component)((Component)MainCamera.instance).GetComponent<Camera>()).transform;
				visual.transform.SetPositionAndRotation(transform.TransformPoint(new Vector3(0.34f, -0.29f, 0.68f)), transform.rotation);
			}
			else if (Object.op_Implicit((Object)(object)hand))
			{
				visual.transform.SetPositionAndRotation(hand.position, hand.rotation * Quaternion.Euler(0f, 90f, 0f));
			}
			if (attached && Object.op_Implicit((Object)(object)anchor) && Object.op_Implicit((Object)(object)cable))
			{
				Vector3 val2 = ((Component)anchor).transform.TransformPoint(anchorLocal);
				Vector3 position = visual.transform.position;
				float num = Mathf.Clamp01((Time.time - firedAt) / 0.1f);
				Vector3 val3 = Vector3.Lerp(position, val2, num);
				cable.SetPosition(0, position);
				cable.SetPosition(1, val3);
				if (Object.op_Implicit((Object)(object)claw))
				{
					claw.position = val3;
					Transform? obj = claw;
					Vector3 val4 = val3 - position;
					obj.rotation = Quaternion.LookRotation(((Vector3)(ref val4)).normalized);
				}
			}
		}

		internal void Pose(CharacterAnimations animations)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)owner) && !((Object)(object)owner.refs.animations != (Object)(object)animations) && Ready(owner) && !Object.op_Implicit((Object)(object)owner.data.currentItem) && !owner.data.isClimbingAnything && Object.op_Implicit((Object)(object)MainCamera.instance))
			{
				CharacterRefs refs = owner.refs;
				refs.ikRig.weight = 1f;
				((RigConstraint<TwoBoneIKConstraintJob, TwoBoneIKConstraintData, TwoBoneIKConstraintJobBinder<TwoBoneIKConstraintData>>)(object)refs.ikRight).weight = 1f;
				Transform transform = ((Component)((Component)MainCamera.instance).GetComponent<Camera>()).transform;
				refs.IKHandTargetRight.SetPositionAndRotation(transform.TransformPoint(new Vector3(0.31f, -0.32f, 0.57f)), transform.rotation * Quaternion.Euler(-30f, -90f, -70f));
			}
		}

		internal RescueHook FindPrefab()
		{
			GameObject[] array = Resources.LoadAll<GameObject>("0_Items");
			for (int i = 0; i < array.Length; i++)
			{
				RescueHook component = array[i].GetComponent<RescueHook>();
				if (Object.op_Implicit((Object)(object)component))
				{
					return component;
				}
			}
			throw new InvalidOperationException("Installed game has no RescueHook prefab in 0_Items.");
		}

		private void CreateVisual()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_00dd: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_019a: 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)
			prefab = FindPrefab();
			hand = ((TwoBoneIKConstraintData)(ref ((RigConstraint<TwoBoneIKConstraintJob, TwoBoneIKConstraintData, TwoBoneIKConstraintJobBinder<TwoBoneIKConstraintData>>)(object)owner.refs.ikRight).data)).tip;
			visual = new GameObject("ODM Right Hand Rescue Launcher");
			CopyMeshes(((Component)prefab).transform, visual.transform, ((Component)prefab).transform);
			visual.transform.localScale = Vector3.one * 0.55f;
			claw = ((IEnumerable<Transform>)visual.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == ((Object)prefab.claw).name));
			if (Object.op_Implicit((Object)(object)claw))
			{
				clawRest = claw.localPosition;
				clawRotation = claw.localRotation;
			}
			GameObject val = new GameObject("ODM Cable");
			val.transform.SetParent(visual.transform, false);
			cable = val.AddComponent<LineRenderer>();
			cable.positionCount = 2;
			cable.useWorldSpace = true;
			cable.startWidth = 0.018f;
			cable.endWidth = 0.012f;
			Shader val2 = Shader.Find("Sprites/Default");
			if (!Object.op_Implicit((Object)(object)val2))
			{
				throw new InvalidOperationException("Cable shader unavailable");
			}
			cableMaterial = new Material(val2);
			((Renderer)cable).sharedMaterial = cableMaterial;
			LineRenderer? obj = cable;
			LineRenderer? obj2 = cable;
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.22f, 0.25f, 0.27f, 1f);
			obj2.endColor = val3;
			obj.startColor = val3;
			((Renderer)cable).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)cable).enabled = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("ODM_VISUAL meshes=" + visual.GetComponentsInChildren<MeshRenderer>().Length + " native=" + ((Object)prefab).name));
		}

		private static void CopyMeshes(Transform source, Transform target, Transform root)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
			MeshRenderer component2 = ((Component)source).GetComponent<MeshRenderer>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2))
			{
				((Component)target).gameObject.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh;
				MeshRenderer obj = ((Component)target).gameObject.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterials = ((Renderer)component2).sharedMaterials;
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			}
			foreach (Transform item in source)
			{
				Transform val = item;
				Transform transform = new GameObject(((Object)val).name).transform;
				transform.SetParent(target, false);
				transform.localPosition = val.localPosition;
				transform.localRotation = val.localRotation;
				transform.localScale = val.localScale;
				CopyMeshes(val, transform, root);
			}
		}

		internal void Draw()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (showHud.Value && Object.op_Implicit((Object)(object)owner))
			{
				GUI.Box(new Rect(16f, 65f, 570f, 65f), "OMNI-DIRECTIONAL MOBILITY GEAR  |  UNLIMITED\nRMB: Fire & pull   LMB: Climb   Space: Release   F6: Toggle\n" + status);
			}
		}

		private void Cleanup()
		{
			Release("READY");
			if (Object.op_Implicit((Object)(object)visual))
			{
				Object.Destroy((Object)(object)visual);
			}
			if (Object.op_Implicit((Object)(object)cableMaterial))
			{
				Object.Destroy((Object)(object)cableMaterial);
			}
			visual = null;
			cable = null;
			claw = null;
			owner = null;
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= SceneChanged;
			Cleanup();
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if (Object.op_Implicit((Object)(object)driver))
			{
				Object.Destroy((Object)(object)driver);
			}
			Instance = null;
		}
	}
	public sealed class GearDriver : MonoBehaviour
	{
		private void Update()
		{
			try
			{
				Plugin.Instance?.Tick();
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}

		private void FixedUpdate()
		{
			try
			{
				Plugin.Instance?.PhysicsTick();
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}

		private void LateUpdate()
		{
			try
			{
				Plugin.Instance?.RenderTick();
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}

		private void OnGUI()
		{
			Plugin.Instance?.Draw();
		}
	}
	[HarmonyPatch(typeof(CharacterInput), "Sample")]
	internal static class InputPatch
	{
		private static void Postfix(CharacterInput __instance, bool playerMovementActive)
		{
			try
			{
				Plugin.Instance?.Sample(__instance, playerMovementActive);
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAnimations), "HandleIK")]
	internal static class HandWeightPatch
	{
		private static void Postfix(CharacterAnimations __instance)
		{
			try
			{
				Plugin.Instance?.Pose(__instance);
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAnimations), "ConfigureIK")]
	internal static class HandPosePatch
	{
		private static void Postfix(CharacterAnimations __instance)
		{
			try
			{
				Plugin.Instance?.Pose(__instance);
			}
			catch (Exception e)
			{
				Plugin.Instance?.Fail(e);
			}
		}
	}
}