Decompiled source of Tow Tuner v0.2.4

BepInEx/plugins/Robin-TowTuner/RepoTowTuner.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RepoTowTuner")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.4.0")]
[assembly: AssemblyInformationalVersion("0.2.4")]
[assembly: AssemblyProduct("RepoTowTuner")]
[assembly: AssemblyTitle("RepoTowTuner")]
[assembly: AssemblyVersion("0.2.4.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 RepoTowTuner
{
	internal static class TowCartGrip
	{
		private sealed class Pending
		{
			internal PhysGrabObject Item;

			internal TowGripWindow Window;

			internal Vector3 LocalPoint;
		}

		internal sealed class Pulse
		{
			internal PhysGrabber Grabber;

			internal float Previous;

			internal bool CheckArea;
		}

		private static readonly FieldRef<PhysGrabber, PhysGrabObject> GrabbedItem = AccessTools.FieldRefAccess<PhysGrabber, PhysGrabObject>("grabbedPhysGrabObject");

		private static readonly Dictionary<PhysGrabber, Pending> pending = new Dictionary<PhysGrabber, Pending>();

		private static bool Enabled
		{
			get
			{
				if (TowRuntime.Host && TowRuntime.Ready)
				{
					return TowRuntime.Compatible;
				}
				return false;
			}
		}

		internal static bool Holds(PhysGrabber? grabber, PhysGrabObject item)
		{
			if (Object.op_Implicit((Object)(object)grabber) && grabber.grabbed)
			{
				return (Object)(object)GrabbedItem.Invoke(grabber) == (Object)(object)item;
			}
			return false;
		}

		internal static bool HasPlayer(PhysGrabObject item)
		{
			if (Object.op_Implicit((Object)(object)item))
			{
				if (!item.playerGrabbing.Any((PhysGrabber p) => Object.op_Implicit((Object)(object)p)))
				{
					if (Object.op_Implicit((Object)(object)GameDirector.instance))
					{
						return SemiFunc.PlayerGetList().Any((PlayerAvatar p) => Object.op_Implicit((Object)(object)p) && Holds(p.physGrabber, item));
					}
					return false;
				}
				return true;
			}
			return false;
		}

		internal static void ClearPending()
		{
			pending.Clear();
		}

		internal static void Begin(PhysGrabber grabber, PhysGrabObject item)
		{
			if (Enabled && !grabber.isLocal)
			{
				pending[grabber] = new Pending
				{
					Item = item,
					Window = new TowGripWindow(Time.unscaledTime)
				};
			}
		}

		internal static void PointReceived(PhysGrabber grabber, PhysGrabObject item, Vector3 localPoint)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled && pending.TryGetValue(grabber, out Pending value) && !((Object)(object)value.Item != (Object)(object)item) && Holds(grabber, item) && !float.IsNaN(((Vector3)(ref localPoint)).sqrMagnitude) && !float.IsInfinity(((Vector3)(ref localPoint)).sqrMagnitude) && value.Window.WaitingForPoint(Time.unscaledTime))
			{
				value.LocalPoint = localPoint;
				value.Window.ConfirmPoint(Time.unscaledTime);
			}
		}

		internal static void Cancel(PhysGrabber? grabber, PhysGrabObject item)
		{
			if (Object.op_Implicit((Object)(object)grabber) && pending.TryGetValue(grabber, out Pending value) && (Object)(object)value.Item == (Object)(object)item)
			{
				pending.Remove(grabber);
			}
		}

		internal static List<Pulse>? BeforeNative(PhysGrabObjectGrabArea area, bool steering)
		{
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled)
			{
				return null;
			}
			PhysGrabObject component = ((Component)area).GetComponent<PhysGrabObject>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)((Component)component).GetComponent<PhysGrabCart>()))
			{
				return null;
			}
			List<Pulse> list = new List<Pulse>();
			KeyValuePair<PhysGrabber, Pending>[] array = pending.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<PhysGrabber, Pending> keyValuePair = array[i];
				PhysGrabber key = keyValuePair.Key;
				Pending value = keyValuePair.Value;
				if (!Object.op_Implicit((Object)(object)key) || !Object.op_Implicit((Object)(object)value.Item) || !value.Window.Alive(Time.unscaledTime) || !Holds(key, value.Item))
				{
					pending.Remove(key);
				}
				else
				{
					if ((Object)(object)value.Item != (Object)(object)component || !component.playerGrabbing.Contains(key))
					{
						continue;
					}
					bool flag = (steering ? value.Window.ForSteering(Time.unscaledTime) : value.Window.ForArea(Time.unscaledTime));
					if (!flag && (steering || !value.Window.WaitingForPoint(Time.unscaledTime)))
					{
						continue;
					}
					if (steering && !area.listOfAllGrabbers.Contains(key))
					{
						pending.Remove(key);
						continue;
					}
					list.Add(new Pulse
					{
						Grabber = key,
						Previous = key.initialPressTimer,
						CheckArea = flag
					});
					if (!steering && flag)
					{
						key.physGrabPoint.position = ((Component)component).transform.TransformPoint(value.LocalPoint);
					}
					key.initialPressTimer = (flag ? Mathf.Max(0.1f, key.initialPressTimer) : 0f);
				}
			}
			return list;
		}

		internal static void AfterArea(PhysGrabObjectGrabArea area, List<Pulse>? pulses)
		{
			if (pulses == null)
			{
				return;
			}
			foreach (Pulse pulse in pulses)
			{
				if (pulse.CheckArea && pending.TryGetValue(pulse.Grabber, out Pending value))
				{
					value.Window.CheckedArea(area.listOfAllGrabbers.Contains(pulse.Grabber));
				}
			}
		}

		internal static void Restore(List<Pulse>? pulses, bool complete)
		{
			if (pulses == null)
			{
				return;
			}
			foreach (Pulse pulse in pulses)
			{
				if (Object.op_Implicit((Object)(object)pulse.Grabber))
				{
					pulse.Grabber.initialPressTimer = pulse.Previous;
				}
				if (complete && pending.TryGetValue(pulse.Grabber, out Pending value))
				{
					value.Window.Complete();
				}
			}
		}

		internal static void ReleaseTow(PhysGrabObject item)
		{
			if (!TowRuntime.Host || !Object.op_Implicit((Object)(object)item))
			{
				return;
			}
			PhysGrabCart component = ((Component)item).GetComponent<PhysGrabCart>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			foreach (TowVehicle vehicle in TowRuntime.Vehicles)
			{
				if (Object.op_Implicit((Object)(object)vehicle) && (Object)(object)vehicle.AttachedCart == (Object)(object)component)
				{
					vehicle.Detach();
				}
			}
		}

		internal static bool HandleAimed(PlayerAvatar player, PhysGrabCart? cart)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_010c: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)cart) || !Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.localCamera) || cart.grabMesh == null)
			{
				return false;
			}
			Transform overrideTransform = player.localCamera.GetOverrideTransform();
			MeshRenderer val = cart.grabMesh.Where((MeshRenderer r) => Object.op_Implicit((Object)(object)r)).OrderBy(delegate(MeshRenderer r)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				Bounds bounds2 = ((Renderer)r).bounds;
				return Mathf.Abs(Vector3.Dot(((Bounds)(ref bounds2)).center - ((Component)cart).transform.position, ((Component)cart).transform.right));
			}).FirstOrDefault();
			if (Object.op_Implicit((Object)(object)val) && ((Renderer)val).enabled && ((Component)val).gameObject.activeInHierarchy)
			{
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.sharedMesh))
				{
					return false;
				}
				Ray val2 = default(Ray);
				((Ray)(ref val2))..ctor(((Component)val).transform.InverseTransformPoint(overrideTransform.position), ((Component)val).transform.InverseTransformVector(overrideTransform.forward));
				Bounds bounds = component.sharedMesh.bounds;
				float num = default(float);
				if (!((Bounds)(ref bounds)).IntersectRay(val2, ref num))
				{
					return false;
				}
				Vector3 val3 = ((Component)val).transform.TransformPoint(((Ray)(ref val2)).GetPoint(num));
				if (Vector3.Distance(overrideTransform.position, val3) <= 3f)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabLinkRPC")]
	internal static class CartGrabLinkHandoff
	{
		private static void Prefix(PhysGrabObject __instance, int playerPhotonID, out bool __state)
		{
			__state = false;
			if (TowRuntime.Host && TowRuntime.Ready && TowRuntime.Compatible && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<PhysGrabCart>()))
			{
				PhotonView val = PhotonView.Find(playerPhotonID);
				PhysGrabber val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabber>() : null);
				__state = Object.op_Implicit((Object)(object)val2) && !val2.isLocal && !TowCartGrip.Holds(val2, __instance);
			}
		}

		private static void Postfix(PhysGrabObject __instance, int playerPhotonID, PhotonMessageInfo _info, bool __state)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!TowRuntime.Host || !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<PhysGrabCart>()))
			{
				return;
			}
			PhotonView val = PhotonView.Find(playerPhotonID);
			PhysGrabber grabber = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabber>() : null);
			if (TowCartGrip.Holds(grabber, __instance) && SemiFunc.OwnerOnlyRPC(_info, val))
			{
				TowCartGrip.ReleaseTow(__instance);
				if (__state)
				{
					TowCartGrip.Begin(grabber, __instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC")]
	internal static class RemoteCartGrabRegistered
	{
		private static void Postfix(PhysGrabObject __instance, int photonViewID, PhotonMessageInfo _info)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (TowRuntime.Host && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<PhysGrabCart>()) && SemiFunc.MasterOnlyRPC(_info))
			{
				PhotonView val = PhotonView.Find(photonViewID);
				PhysGrabber val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabber>() : null);
				if (Object.op_Implicit((Object)(object)val2) && __instance.playerGrabbing.Contains(val2))
				{
					TowCartGrip.ReleaseTow(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabPointSyncRPC")]
	internal static class RemoteCartPointReceived
	{
		private static void Postfix(PhysGrabObject __instance, int playerPhotonID, Vector3 localPointInBox, PhotonMessageInfo _info)
		{
			//IL_0036: 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 (TowRuntime.Host && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<PhysGrabCart>()))
			{
				PhotonView val = PhotonView.Find(playerPhotonID);
				PhysGrabber val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabber>() : null);
				if (Object.op_Implicit((Object)(object)val2) && SemiFunc.OwnerOnlyRPC(_info, val))
				{
					TowCartGrip.PointReceived(val2, __instance, localPointInBox);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerRemoveRPC")]
	internal static class RemoteCartGripEnded
	{
		private static void Postfix(PhysGrabObject __instance, int photonViewID, PhotonMessageInfo _info)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (TowRuntime.Host && SemiFunc.MasterOnlyRPC(_info))
			{
				PhotonView val = PhotonView.Find(photonViewID);
				TowCartGrip.Cancel(Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabber>() : null, __instance);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObjectGrabArea), "Update")]
	internal static class RemoteCartAreaActivation
	{
		private static void Prefix(PhysGrabObjectGrabArea __instance, out List<TowCartGrip.Pulse>? __state)
		{
			__state = TowCartGrip.BeforeNative(__instance, steering: false);
		}

		private static void Postfix(PhysGrabObjectGrabArea __instance, List<TowCartGrip.Pulse>? __state)
		{
			TowCartGrip.AfterArea(__instance, __state);
		}

		private static void Finalizer(List<TowCartGrip.Pulse>? __state)
		{
			TowCartGrip.Restore(__state, complete: false);
		}
	}
	[HarmonyPatch(typeof(PhysGrabCart), "CartSteer")]
	internal static class RemoteCartSteerActivation
	{
		private static void Prefix(PhysGrabCart __instance, out List<TowCartGrip.Pulse>? __state)
		{
			PhysGrabObjectGrabArea component = ((Component)__instance).GetComponent<PhysGrabObjectGrabArea>();
			__state = (Object.op_Implicit((Object)(object)component) ? TowCartGrip.BeforeNative(component, steering: true) : null);
		}

		private static void Finalizer(List<TowCartGrip.Pulse>? __state)
		{
			TowCartGrip.Restore(__state, complete: true);
		}
	}
	[HarmonyPatch(typeof(PhysGrabCart), "FixedUpdate")]
	internal static class CartPhysicsHandoff
	{
		private static void Prefix(PhysGrabCart __instance)
		{
			if (TowRuntime.Host)
			{
				PhysGrabObject component = ((Component)__instance).GetComponent<PhysGrabObject>();
				if (TowCartGrip.HasPlayer(component))
				{
					TowCartGrip.ReleaseTow(component);
				}
			}
		}
	}
	public sealed class TowCartHitch : MonoBehaviour
	{
		private Transform hardware;

		private Transform eye;

		private Material steel;

		private Material glow;

		private LineRenderer ring;

		private PhysGrabCart cart;

		public Vector3 EyePosition => eye.position;

		public Transform Hardware => hardware;

		public bool Highlighted { get; private set; }

		public static TowCartHitch Ensure(PhysGrabCart cart)
		{
			return ((Component)cart).GetComponent<TowCartHitch>() ?? ((Component)cart).gameObject.AddComponent<TowCartHitch>();
		}

		private void Awake()
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_0189: 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)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: 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_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: 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)
			//IL_0239: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			cart = ((Component)this).GetComponent<PhysGrabCart>();
			steel = new Material(Shader.Find("Standard"))
			{
				color = new Color(0.3f, 0.33f, 0.23f)
			};
			steel.SetFloat("_Glossiness", 0.32f);
			glow = new Material(steel);
			glow.EnableKeyword("_EMISSION");
			glow.SetColor("_EmissionColor", new Color(0.25f, 1.1f, 0.025f));
			Transform val = (Object.op_Implicit((Object)(object)cart.cartGrabPoint) ? cart.cartGrabPoint : cart.handlePoint);
			MeshRenderer val2 = cart.grabMesh?.Where((MeshRenderer r) => Object.op_Implicit((Object)(object)r)).OrderBy(delegate(MeshRenderer r)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: 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)
				Bounds bounds2 = ((Renderer)r).bounds;
				return Mathf.Abs(Vector3.Dot(((Bounds)(ref bounds2)).center - ((Component)this).transform.position, ((Component)this).transform.right));
			}).FirstOrDefault();
			? val3;
			if (!Object.op_Implicit((Object)(object)val2))
			{
				val3 = (Object.op_Implicit((Object)(object)val) ? val.position : (((Component)this).transform.position + ((Component)this).transform.up * 0.6f));
			}
			else
			{
				Bounds bounds = ((Renderer)val2).bounds;
				val3 = ((Bounds)(ref bounds)).center;
			}
			Vector3 val4 = (Vector3)val3;
			hardware = new GameObject("Tow cart mounting bracket").transform;
			hardware.SetParent(((Component)this).transform, false);
			hardware.position = val4 - ((Component)this).transform.right * 0.3f + ((Component)this).transform.up * 0.12f - ((Component)this).transform.forward * 0.065f;
			Part("Bolted mounting plate", new Vector3(0f, -0.1f, 0.09f), new Vector3(0.18f, 0.085f, 0.1f));
			Part("Eye support", new Vector3(0f, -0.1f, -0.015f), new Vector3(0.045f, 0.055f, 0.14f));
			for (int num = -1; num <= 1; num += 2)
			{
				((Component)TowPresentation.Primitive("Hitch bolt", (PrimitiveType)2, hardware, new Vector3((float)num * 0.06f, -0.1f, 0.032f), new Vector3(0.028f, 0.008f, 0.028f), steel)).transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			}
			eye = new GameObject("Tow attachment eye").transform;
			eye.SetParent(hardware, false);
			eye.localPosition = new Vector3(0f, -0.1f, -0.085f);
			Vector3[] array = (Vector3[])(object)new Vector3[13];
			for (int num2 = 0; num2 < array.Length; num2++)
			{
				float num3 = MathF.PI * 2f * (float)num2 / 12f;
				array[num2] = new Vector3(Mathf.Sin(num3) * 0.085f, Mathf.Cos(num3) * 0.06f, 0f);
			}
			TowPresentation.Stroke("Steel attachment eye", eye, array, 0.024f, steel);
			ring = ((Component)eye).GetComponentInChildren<LineRenderer>();
		}

		private void Part(string name, Vector3 position, Vector3 size)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			TowPresentation.Primitive(name, (PrimitiveType)3, hardware, position, size, steel);
		}

		private void LateUpdate()
		{
			bool flag = TowRuntime.Ready && TowRuntime.Compatible;
			((Component)hardware).gameObject.SetActive(flag);
			Highlighted = flag && TowInteractions.Gripping && (Object)(object)TowInteractions.Target == (Object)(object)cart;
			bool flag2 = TowRuntime.Vehicles.Any((TowVehicle v) => Object.op_Implicit((Object)(object)v) && v.Active && (Object)(object)v.AttachedCart == (Object)(object)cart);
			((Renderer)ring).sharedMaterial = ((Highlighted || flag2) ? glow : steel);
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)hardware))
			{
				Object.Destroy((Object)(object)((Component)hardware).gameObject);
			}
			if (Object.op_Implicit((Object)(object)steel))
			{
				Object.Destroy((Object)(object)steel);
			}
			if (Object.op_Implicit((Object)(object)glow))
			{
				Object.Destroy((Object)(object)glow);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabCart), "Start")]
	internal static class AddCartHitch
	{
		private static void Postfix(PhysGrabCart __instance)
		{
			TowCartHitch.Ensure(__instance);
		}
	}
	public sealed class TowGripWindow
	{
		public const float Timeout = 3f;

		private readonly float started;

		private bool point;

		private bool area;

		private bool done;

		public TowGripWindow(float now)
		{
			started = now;
		}

		public bool Alive(float now)
		{
			if (!done && now >= started)
			{
				return now - started <= 3f;
			}
			return false;
		}

		public bool WaitingForPoint(float now)
		{
			if (Alive(now))
			{
				return !point;
			}
			return false;
		}

		public bool ForArea(float now)
		{
			if (Alive(now) && point)
			{
				return !area;
			}
			return false;
		}

		public bool ForSteering(float now)
		{
			if (Alive(now))
			{
				return area;
			}
			return false;
		}

		public void ConfirmPoint(float now)
		{
			if (Alive(now))
			{
				point = true;
			}
		}

		public void CheckedArea(bool accepted)
		{
			if (accepted)
			{
				area = true;
			}
			else
			{
				done = true;
			}
		}

		public void Complete()
		{
			done = true;
		}
	}
	public static class TowInteractions
	{
		private static TowVehicle? carrying;

		private static int tickFrame = -1;

		private static float beganAt;

		private static float targetAt;

		private static bool consumeGrabUntilRelease;

		public static bool ConsumingButtonGrab => consumeGrabUntilRelease;

		public static bool Gripping => Object.op_Implicit((Object)(object)carrying);

		public static Vector3 LocalTip { get; private set; }

		public static PhysGrabCart? Target { get; private set; }

		internal static bool CursorCaptured()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			return (int)Cursor.lockState == 1;
		}

		public static bool Aimed(PlayerAvatar player, Vector3 point, float radius, TowVehicle vehicle, PhysGrabCart? cart = null)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0078: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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)
			if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.localCamera))
			{
				return false;
			}
			Transform overrideTransform = player.localCamera.GetOverrideTransform();
			Vector3 val = point - overrideTransform.position;
			float num = Vector3.Dot(val, overrideTransform.forward);
			if (!(num < 0f) && !(num > 3f))
			{
				Vector3 val2 = val - overrideTransform.forward * num;
				if (!(((Vector3)(ref val2)).magnitude > radius))
				{
					return !Physics.RaycastAll(overrideTransform.position, ((Vector3)(ref val)).normalized, Mathf.Max(0f, ((Vector3)(ref val)).magnitude - 0.06f), -1, (QueryTriggerInteraction)1).Any((RaycastHit h) => (Object)(object)((RaycastHit)(ref h)).rigidbody != (Object)(object)vehicle.Vehicle.rb && (!Object.op_Implicit((Object)(object)cart) || (Object)(object)((RaycastHit)(ref h)).rigidbody != (Object)(object)((Component)cart).GetComponent<Rigidbody>()) && !((RaycastHit)(ref h)).transform.IsChildOf(((Component)player).transform) && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref h)).collider).GetComponentInParent<PlayerTumble>()) && ((Component)((RaycastHit)(ref h)).collider).gameObject.layer != LayerMask.NameToLayer("Player"));
				}
			}
			return false;
		}

		public static void Tick()
		{
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			if (tickFrame == Time.frameCount)
			{
				return;
			}
			tickFrame = Time.frameCount;
			PlayerAvatar p = SemiFunc.PlayerGetLocal();
			if (!Object.op_Implicit((Object)(object)p) || !TowRuntime.Ready || !TowRuntime.Compatible || !CursorCaptured() || !SemiFunc.NoTextInputsActive() || Time.timeScale <= 0f)
			{
				CancelLocal();
				return;
			}
			TowRuntime instance = TowRuntime.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return;
			}
			if (consumeGrabUntilRelease)
			{
				p.physGrabber.OverrideGrabDisable(0.12f);
				if (!SemiFunc.InputHold((InputKey)10))
				{
					consumeGrabUntilRelease = false;
				}
				return;
			}
			if (Object.op_Implicit((Object)(object)carrying))
			{
				TowVehicle v = carrying;
				p.physGrabber.OverrideGrabDisable(0.12f);
				if (!v.Active || !v.NearRear(p) || Object.op_Implicit((Object)(object)ItemVehicle.GetVehicleForPlayer(p)) || Time.unscaledTime - beganAt > 25f || (Time.unscaledTime - beganAt > 1.5f && !v.IsHeldBy(p)))
				{
					CancelLocal();
					return;
				}
				Transform cam = p.localCamera.GetOverrideTransform();
				if (!Object.op_Implicit((Object)(object)Target) || !(Time.unscaledTime - targetAt <= 0.4f) || !v.CanAttach(Target, ((Component)v).transform.TransformPoint(v.RearAnchor)) || !Aimed(p, TowVehicle.Hitch(Target), 0.55f, v, Target))
				{
					Target = (from c in Object.FindObjectsOfType<PhysGrabCart>()
						where v.CanAttach(c, ((Component)v).transform.TransformPoint(v.RearAnchor)) && Aimed(p, TowVehicle.Hitch(c), 0.36f, v, c)
						orderby Vector3.Distance(cam.position, TowVehicle.Hitch(c))
						select c).FirstOrDefault();
				}
				if (Object.op_Implicit((Object)(object)Target) && Aimed(p, TowVehicle.Hitch(Target), 0.36f, v, Target))
				{
					targetAt = Time.unscaledTime;
				}
				LocalTip = (Object.op_Implicit((Object)(object)Target) ? TowVehicle.Hitch(Target) : CarryTip(p, v));
				if (!SemiFunc.InputHold((InputKey)10))
				{
					if (Object.op_Implicit((Object)(object)Target))
					{
						instance.Request(v, 4, TowRuntime.Multiplayer ? ((Component)Target).GetComponent<PhotonView>().ViewID : 0, Target);
					}
					else
					{
						instance.Request(v, 5, 0);
					}
					carrying = null;
					Target = null;
				}
				return;
			}
			TowVehicle towVehicle = TowRuntime.Vehicles.FirstOrDefault((TowVehicle towVehicle4) => Object.op_Implicit((Object)(object)towVehicle4) && (Object)(object)towVehicle4.Driver == (Object)(object)p);
			TowVehicle towVehicle2 = TowRuntime.Vehicles.FirstOrDefault((TowVehicle towVehicle4) => Object.op_Implicit((Object)(object)towVehicle4) && towVehicle4.Active && towVehicle4.Presentation.ButtonAimed(p));
			bool flag = SemiFunc.InputDown((InputKey)10);
			if (Object.op_Implicit((Object)(object)towVehicle2) && (flag || SemiFunc.InputDown((InputKey)2)))
			{
				if (!Object.op_Implicit((Object)(object)towVehicle) && !p.physGrabber.grabbed && flag)
				{
					consumeGrabUntilRelease = true;
					p.physGrabber.OverrideGrabDisable(0.15f);
				}
				if (towVehicle2.CanUseSwitch(p))
				{
					instance.Request(towVehicle2, 1, (!towVehicle2.BoostEnabled) ? 1 : 0);
				}
			}
			else
			{
				if (Object.op_Implicit((Object)(object)towVehicle) || p.physGrabber.grabbed || !SemiFunc.InputDown((InputKey)10))
				{
					return;
				}
				TowVehicle towVehicle3 = (from towVehicle4 in TowRuntime.Vehicles
					where Object.op_Implicit((Object)(object)towVehicle4) && towVehicle4.Active && towVehicle4.HookActor == 0 && !TowCartGrip.HandleAimed(p, towVehicle4.AttachedCart) && Aimed(p, towVehicle4.Presentation.HookPosition, 0.14f, towVehicle4, towVehicle4.AttachedCart)
					orderby Vector3.Distance(towVehicle4.Presentation.HookPosition, ((Component)p).transform.position)
					select towVehicle4).FirstOrDefault();
				if (!Object.op_Implicit((Object)(object)towVehicle3))
				{
					return;
				}
				p.physGrabber.OverrideGrabDisable(0.15f);
				if (towVehicle3.HasCart)
				{
					consumeGrabUntilRelease = true;
					instance.Request(towVehicle3, 0, 0);
					return;
				}
				carrying = towVehicle3;
				beganAt = Time.unscaledTime;
				Target = null;
				targetAt = -100f;
				LocalTip = towVehicle3.Presentation.HookPosition;
				instance.Request(towVehicle3, 3, 0);
				if (TowRuntime.Host && !towVehicle3.IsHeldBy(p))
				{
					carrying = null;
				}
			}
		}

		public static Vector3 CarryTip(PlayerAvatar player, TowVehicle vehicle)
		{
			//IL_0013: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00be: 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)
			Transform overrideTransform = player.localCamera.GetOverrideTransform();
			float num = 1.1f;
			RaycastHit[] array = Physics.RaycastAll(overrideTransform.position, overrideTransform.forward, num, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if ((Object)(object)((RaycastHit)(ref val)).rigidbody != (Object)(object)vehicle.Vehicle.rb && !((RaycastHit)(ref val)).transform.IsChildOf(((Component)player).transform) && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<PlayerTumble>()))
				{
					num = Mathf.Min(num, Mathf.Max(0.25f, ((RaycastHit)(ref val)).distance - 0.08f));
				}
			}
			return overrideTransform.position + overrideTransform.forward * num - overrideTransform.up * 0.1f;
		}

		public static Vector3 TipFor(TowVehicle v, PlayerAvatar holder)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)carrying == (Object)(object)v))
			{
				return CarryTip(holder, v);
			}
			return LocalTip;
		}

		public static void CancelLocal()
		{
			if (Object.op_Implicit((Object)(object)carrying) && Object.op_Implicit((Object)(object)TowRuntime.Instance) && TowRuntime.Ready)
			{
				TowRuntime.Instance.Request(carrying, 5, 0);
			}
			carrying = null;
			Target = null;
			consumeGrabUntilRelease = false;
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "Update")]
	internal static class HookGrabInput
	{
		private static void Prefix(PhysGrabber __instance)
		{
			if ((Object)(object)__instance == (Object)(object)PhysGrabber.instance && TowRuntime.Ready)
			{
				TowInteractions.Tick();
			}
		}
	}
	[HarmonyPatch(typeof(ItemVehicle), "Update")]
	internal static class VehicleInputScope
	{
		internal static ItemVehicle? Current;

		private static void Prefix(ItemVehicle __instance, out ItemVehicle? __state)
		{
			__state = Current;
			Current = __instance;
		}

		private static void Finalizer(ItemVehicle? __state)
		{
			Current = __state;
		}
	}
	[HarmonyPatch(typeof(SemiFunc), "InputDown")]
	internal static class PowerButtonConsumesHonk
	{
		private static void Postfix(InputKey key, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)key == 2 && Object.op_Implicit((Object)(object)VehicleInputScope.Current) && TowRuntime.Ready)
			{
				TowVehicle component = ((Component)VehicleInputScope.Current).GetComponent<TowVehicle>();
				PlayerAvatar val = SemiFunc.PlayerGetLocal();
				if (Object.op_Implicit((Object)(object)component) && component.Active && Object.op_Implicit((Object)(object)val) && !((Object)(object)component.Driver != (Object)(object)val) && component.Presentation.ButtonAimed(val))
				{
					__result = false;
				}
			}
		}
	}
	internal static class TowPatches
	{
		internal static readonly FieldRef<ItemVehicle, float> Hyper = AccessTools.FieldRefAccess<ItemVehicle, float>("hyperSpeedOverTime");

		private static readonly FieldRef<ItemVehicle, float> BoostTimer = AccessTools.FieldRefAccess<ItemVehicle, float>("driftBoostActiveTimer");

		private static readonly FieldRef<ItemVehicle, float> BoostForce = AccessTools.FieldRefAccess<ItemVehicle, float>("driftBoostActiveForce");

		private static readonly FieldRef<ItemVehicle, float> ExitTimer = AccessTools.FieldRefAccess<ItemVehicle, float>("driftExitDelayTimer");

		private static readonly FieldRef<ItemVehicle, int> PendingLevel = AccessTools.FieldRefAccess<ItemVehicle, int>("driftExitPendingBoostLevel");

		private static readonly FieldRef<ItemVehicle, bool> PendingRestore = AccessTools.FieldRefAccess<ItemVehicle, bool>("driftExitPendingSpeedRestore");

		private static readonly FieldRef<ItemVehicle, int> BoostLevel = AccessTools.FieldRefAccess<ItemVehicle, int>("driftBoostLevel");

		private static readonly FieldRef<ItemVehicle, float> BoostProgress = AccessTools.FieldRefAccess<ItemVehicle, float>("driftBoostProgress");

		internal static TowVehicle? Control(ItemVehicle vehicle)
		{
			return ((Component)vehicle).GetComponent<TowVehicle>();
		}

		internal static bool BoostOff(ItemVehicle vehicle)
		{
			TowVehicle towVehicle = Control(vehicle);
			if (Object.op_Implicit((Object)(object)towVehicle) && towVehicle.Active)
			{
				return !towVehicle.BoostEnabled;
			}
			return false;
		}

		internal static void ClearBoost(ItemVehicle vehicle)
		{
			Hyper.Invoke(vehicle) = 0f;
			BoostTimer.Invoke(vehicle) = 0f;
			BoostForce.Invoke(vehicle) = 0f;
			ExitTimer.Invoke(vehicle) = 0f;
			PendingLevel.Invoke(vehicle) = 0;
			PendingRestore.Invoke(vehicle) = false;
			BoostLevel.Invoke(vehicle) = 0;
			BoostProgress.Invoke(vehicle) = 0f;
		}
	}
	[HarmonyPatch(typeof(ItemVehicle), "Start")]
	internal static class AddTowControls
	{
		private static void Postfix(ItemVehicle __instance)
		{
			if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<TowVehicle>()))
			{
				((Component)__instance).gameObject.AddComponent<TowVehicle>();
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabCart), "AutoTurnOff")]
	internal static class TowedCartHandling
	{
		private static readonly FieldRef<PhysGrabCart, bool> CartActive = AccessTools.FieldRefAccess<PhysGrabCart, bool>("cartActive");

		internal static void Release(PhysGrabCart cart)
		{
			PhysGrabObjectGrabArea component = ((Component)cart).GetComponent<PhysGrabObjectGrabArea>();
			PhysGrabObject item = ((Component)cart).GetComponent<PhysGrabObject>();
			if (!Object.op_Implicit((Object)(object)component) || !component.listOfAllGrabbers.Any((PhysGrabber p) => TowCartGrip.Holds(p, item)))
			{
				CartActive.Invoke(cart) = false;
			}
		}

		private static void Postfix(PhysGrabCart __instance)
		{
			if (TowRuntime.Host)
			{
				PhysGrabObject component = ((Component)__instance).GetComponent<PhysGrabObject>();
				if (TowCartGrip.HasPlayer(component))
				{
					TowCartGrip.ReleaseTow(component);
				}
				else if (TowRuntime.Vehicles.Any((TowVehicle v) => Object.op_Implicit((Object)(object)v) && v.Active && (Object)(object)v.AttachedCart == (Object)(object)__instance && v.HasJoint))
				{
					CartActive.Invoke(__instance) = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemVehicle), "ApplyVehicleMovement")]
	internal static class HyperControl
	{
		private static void Prefix(ItemVehicle __instance, out float? __state)
		{
			__state = null;
			if (TowPatches.BoostOff(__instance))
			{
				TowPatches.ClearBoost(__instance);
				__state = __instance.hyperAcceleration;
				__instance.hyperAcceleration = 0f;
			}
		}

		private static void Finalizer(ItemVehicle __instance, float? __state)
		{
			if (__state.HasValue)
			{
				__instance.hyperAcceleration = __state.Value;
				TowPatches.Hyper.Invoke(__instance) = 0f;
			}
		}
	}
	[HarmonyPatch]
	internal static class ExtraBoostControl
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[6] { "ApplyRampBoost", "ApplyDriftBoost", "UpdateDriftBoostActive", "UpdateDriftExitDelay", "UpdateDriftBoostProgress", "DriftBoostEffects" };
			foreach (string text in array)
			{
				yield return AccessTools.Method(typeof(ItemVehicle), text, (Type[])null, (Type[])null);
			}
		}

		private static bool Prefix(ItemVehicle __instance)
		{
			if (!TowPatches.BoostOff(__instance))
			{
				return true;
			}
			TowPatches.ClearBoost(__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemVehicle), "ApplyVelocityLimits")]
	internal static class GovernorBrake
	{
		private static void Postfix(ItemVehicle __instance)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_006a: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			TowVehicle towVehicle = TowPatches.Control(__instance);
			if (Object.op_Implicit((Object)(object)towVehicle) && towVehicle.Active && TowRuntime.Host && Object.op_Implicit((Object)(object)towVehicle.Driver) && !__instance.rb.isKinematic)
			{
				Rigidbody rb = __instance.rb;
				Vector3 velocity = rb.velocity;
				Vector3 val = rb.GetAccumulatedForce(Time.fixedDeltaTime) * (Time.fixedDeltaTime / rb.mass);
				(float, float) tuple = TowRules.GovernorCorrection(velocity.x, velocity.z, val.x, val.z, towVehicle.SpeedLimit, Time.fixedDeltaTime);
				rb.AddForce(new Vector3(tuple.Item1, 0f, tuple.Item2), (ForceMode)2);
			}
		}
	}
	[BepInPlugin("robin.repotowtuner", "Tow Tuner", "0.2.4")]
	public sealed class TowPlugin : BaseUnityPlugin
	{
		public const string Id = "robin.repotowtuner";

		public const string Name = "Tow Tuner";

		public const string Version = "0.2.4";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> DefaultSpeed;

		internal static ConfigEntry<bool> DefaultBoost;

		internal static ConfigEntry<bool> WheelEnabled;

		private void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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_00f7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			WheelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "ScrollSpeed", true, "Driver only: scroll up/down to change the speed limit by 5 displayed km/h.");
			DefaultSpeed = ((BaseUnityPlugin)this).Config.Bind<int>("Vehicle", "DefaultSpeedLimit", 45, new ConfigDescription("Displayed km/h. New scooters start full. The dashboard segments show the limit, the small marker shows current speed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 45), Array.Empty<object>()));
			DefaultBoost = ((BaseUnityPlugin)this).Config.Bind<bool>("Vehicle", "DefaultBoostEnabled", true, "New scooters start with boost ON. Driver uses the physical power button, not a keyboard shortcut.");
			ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("Migration", "DashboardDefaults", 0, "Internal one-time migration from the prototype defaults.");
			if (val.Value < 2)
			{
				DefaultSpeed.Value = 45;
				DefaultBoost.Value = true;
				val.Value = 2;
			}
			new Harmony("robin.repotowtuner").PatchAll(typeof(TowPlugin).Assembly);
			GameObject val2 = new GameObject("Tow Tuner Session")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<TowRuntime>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Tow Tuner 0.2.4: dashboard speed gauge, physical power button and drag-to-connect hook. No screen overlay or H/B shortcuts.");
		}
	}
	public sealed class TowPresentation : MonoBehaviour
	{
		private TowVehicle owner;

		private Transform panel;

		private Transform button;

		private Transform marker;

		private Transform hook;

		private Transform dock;

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

		private readonly List<Renderer> bars = new List<Renderer>();

		private Material green;

		private Material darkGreen;

		private Material amber;

		private Material metal;

		private Material casing;

		private Material white;

		private Renderer lamp;

		private float halfHeight;

		private float pressAt = -100f;

		private Vector3 buttonHome;

		private bool lastBoost;

		private bool lastAttached;

		private int lastHolder;

		private bool initialized;

		public Vector3 ButtonPosition
		{
			get
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)button))
				{
					return ((Component)this).transform.position;
				}
				return button.position;
			}
		}

		public Transform Panel => panel;

		public Vector3 SocketPosition
		{
			get
			{
				//IL_002a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)dock))
				{
					return ((Component)this).transform.TransformPoint(owner.RearAnchor);
				}
				return dock.position;
			}
		}

		public int DisplayedSegments { get; private set; }

		public bool Highlighted { get; private set; }

		public Vector3 HookPosition
		{
			get
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: 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_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)owner.AttachedCart))
				{
					return ((Component)owner.AttachedCart).transform.TransformPoint(owner.CartAnchor);
				}
				PlayerAvatar hookHolder = owner.HookHolder;
				if (Object.op_Implicit((Object)(object)hookHolder))
				{
					return TowInteractions.TipFor(owner, hookHolder);
				}
				return SocketPosition - (Object.op_Implicit((Object)(object)dock) ? dock.forward : ((Component)this).transform.forward) * 0.11f;
			}
		}

		public bool ButtonAimed(PlayerAvatar player)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0059: 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_0072: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.localCamera) || !Object.op_Implicit((Object)(object)button))
			{
				return false;
			}
			Transform overrideTransform = player.localCamera.GetOverrideTransform();
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(button.InverseTransformPoint(overrideTransform.position), button.InverseTransformDirection(overrideTransform.forward));
			Bounds val2 = new Bounds(Vector3.zero, new Vector3(0.12f, 0.13f, 0.08f));
			float num = default(float);
			if (((Bounds)(ref val2)).IntersectRay(val, ref num) && num <= 3f)
			{
				return TowInteractions.Aimed(player, ButtonPosition, 0.12f, owner);
			}
			return false;
		}

		public void Initialize(TowVehicle vehicle)
		{
			//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)
			//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_006c: 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_00a5: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: 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_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: 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_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: 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_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0553: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0602: Unknown result type (might be due to invalid IL or missing references)
			//IL_0607: Unknown result type (might be due to invalid IL or missing references)
			//IL_0651: Unknown result type (might be due to invalid IL or missing references)
			//IL_0656: Unknown result type (might be due to invalid IL or missing references)
			//IL_066c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0671: Unknown result type (might be due to invalid IL or missing references)
			//IL_068c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06de: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_071d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0731: Unknown result type (might be due to invalid IL or missing references)
			//IL_075c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_079b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07af: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0802: Unknown result type (might be due to invalid IL or missing references)
			//IL_0816: Unknown result type (might be due to invalid IL or missing references)
			//IL_082b: Unknown result type (might be due to invalid IL or missing references)
			//IL_084a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0864: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_08df: Unknown result type (might be due to invalid IL or missing references)
			//IL_08fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0904: Unknown result type (might be due to invalid IL or missing references)
			//IL_093e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0952: Unknown result type (might be due to invalid IL or missing references)
			owner = vehicle;
			casing = Make(new Color(0.045f, 0.055f, 0.039f), Color.black, 0.05f);
			metal = Make(new Color(0.23f, 0.25f, 0.21f), Color.black, 0.35f);
			darkGreen = Make(new Color(0.025f, 0.07f, 0.015f), new Color(0.008f, 0.025f, 0.004f));
			green = Make(new Color(0.12f, 0.48f, 0.02f), new Color(0.35f, 1.1f, 0.035f));
			amber = Make(new Color(0.28f, 0.12f, 0.02f), new Color(0.6f, 0.12f, 0.015f));
			white = Make(new Color(0.7f, 0.8f, 0.45f), new Color(0.9f, 1f, 0.45f));
			MeshRenderer grabMesh = vehicle.Vehicle.grabMesh;
			Transform val = (Object.op_Implicit((Object)(object)grabMesh) ? ((Component)grabMesh).transform : ((Component)this).transform);
			MeshFilter val2 = (Object.op_Implicit((Object)(object)grabMesh) ? ((Component)grabMesh).GetComponent<MeshFilter>() : null);
			Bounds val3 = (Bounds)((Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sharedMesh)) ? val2.sharedMesh.bounds : new Bounds(Vector3.zero, new Vector3(0.5f, 0.25f, 0.01f)));
			panel = new GameObject("Tow dashboard").transform;
			panel.SetParent(val, false);
			panel.localPosition = new Vector3(((Bounds)(ref val3)).center.x, ((Bounds)(ref val3)).center.y, ((Bounds)(ref val3)).min.z - 0.008f);
			Vector3 lossyScale = val.lossyScale;
			panel.localScale = new Vector3(1f / Mathf.Max(0.01f, Mathf.Abs(lossyScale.x)), 1f / Mathf.Max(0.01f, Mathf.Abs(lossyScale.y)), 1f / Mathf.Max(0.01f, Mathf.Abs(lossyScale.z)));
			float num = Mathf.Clamp(((Bounds)(ref val3)).extents.x * Mathf.Abs(lossyScale.x), 0.15f, 0.5f);
			halfHeight = Mathf.Clamp(((Bounds)(ref val3)).extents.y * Mathf.Abs(lossyScale.y) * 0.82f, 0.075f, 0.13f);
			float num2 = num * 0.7f;
			Cube("Speed gauge bezel", panel, new Vector3(num2, 0f, 0f), new Vector3(0.052f, halfHeight * 2f + 0.024f, 0.014f), casing);
			Cube("Gauge glass", panel, new Vector3(num2, 0f, -0.008f), new Vector3(0.038f, halfHeight * 2f, 0.006f), darkGreen);
			float num3 = halfHeight * 2f / 9f;
			for (int i = 0; i < 9; i++)
			{
				bars.Add(Cube("Speed segment " + (i + 1), panel, new Vector3(num2, 0f - halfHeight + num3 * ((float)i + 0.5f), -0.013f), new Vector3(0.03f, num3 * 0.63f, 0.005f), green));
			}
			marker = ((Component)Cube("Actual speed marker", panel, new Vector3(num2 + 0.032f, 0f - halfHeight, -0.014f), new Vector3(0.01f, 0.009f, 0.007f), white)).transform;
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(0f - num - 0.075f, 0f, -0.028f);
			Cube("Power button bezel", panel, val4 + new Vector3(0f, 0f, 0.005f), new Vector3(0.095f, 0.1f, 0.025f), casing);
			button = new GameObject("Boost power switch").transform;
			button.SetParent(panel, false);
			button.localPosition = val4;
			buttonHome = val4;
			((Component)Primitive("Power button", (PrimitiveType)2, button, Vector3.zero, new Vector3(0.074f, 0.01f, 0.074f), metal)).transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			lamp = Cube("Boost indicator", button, new Vector3(0f, -0.036f, -0.014f), new Vector3(0.04f, 0.008f, 0.004f), green);
			Transform transform = new GameObject("Power symbol").transform;
			transform.SetParent(button, false);
			transform.localPosition = new Vector3(0f, 0.003f, -0.013f);
			Vector3[] array = (Vector3[])(object)new Vector3[13];
			for (int j = 0; j < array.Length; j++)
			{
				float num4 = (40f + 280f * (float)j / 12f) * (MathF.PI / 180f);
				array[j] = new Vector3(Mathf.Sin(num4), Mathf.Cos(num4), 0f) * 0.023f;
			}
			Stroke("Power ring", transform, array, 0.004f, white);
			Stroke("Power stem", transform, (Vector3[])(object)new Vector3[2]
			{
				new Vector3(0f, 0.008f, 0f),
				new Vector3(0f, 0.03f, 0f)
			}, 0.004f, white);
			dock = new GameObject("Tow cable socket").transform;
			dock.SetParent(Object.op_Implicit((Object)(object)vehicle.Vehicle.meshTransform) ? vehicle.Vehicle.meshTransform : ((Component)this).transform, false);
			dock.position = ((Component)this).transform.TransformPoint(owner.RearAnchor);
			dock.rotation = ((Component)this).transform.rotation;
			Cube("Hitch socket", dock, new Vector3(0f, 0f, 0.022f), new Vector3(0.18f, 0.12f, 0.075f), casing);
			Cube("Hitch stripe", dock, new Vector3(0f, 0.037f, -0.005f), new Vector3(0.13f, 0.008f, 0.005f), green);
			Cube("Hook retaining clip", dock, new Vector3(0f, 0.065f, -0.055f), new Vector3(0.085f, 0.026f, 0.13f), casing);
			hook = new GameObject("Tow hook").transform;
			hook.SetParent(((Component)this).transform, false);
			((Component)Primitive("Hook grip", (PrimitiveType)2, hook, new Vector3(0f, 0.035f, 0f), new Vector3(0.044f, 0.065f, 0.044f), casing)).transform.localRotation = Quaternion.identity;
			List<Vector3> list = new List<Vector3>
			{
				new Vector3(0f, 0.02f, 0f),
				new Vector3(0f, -0.055f, 0f)
			};
			for (int k = 0; k <= 7; k++)
			{
				float num5 = MathF.PI - (float)k / 7f * MathF.PI;
				list.Add(new Vector3(0.035f + Mathf.Cos(num5) * 0.035f, -0.055f - Mathf.Sin(num5) * 0.035f, 0f));
			}
			list.Add(new Vector3(0.07f, -0.025f, 0f));
			for (int l = 1; l < list.Count; l++)
			{
				Rod(hook, list[l - 1], list[l], 0.025f);
			}
			Cube("Hook grip stripe", hook, new Vector3(0f, 0.042f, -0.024f), new Vector3(0.028f, 0.016f, 0.005f), green);
			lastBoost = owner.BoostEnabled;
			lastAttached = owner.HasCart;
			lastHolder = owner.HookActor;
			initialized = true;
			Present();
		}

		private Material Make(Color color, Color emission, float gloss = 0f)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0011: 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)
			Material val = new Material(Shader.Find("Standard"));
			val.color = color;
			val.SetFloat("_Glossiness", gloss);
			val.EnableKeyword("_EMISSION");
			val.SetColor("_EmissionColor", emission);
			materials.Add(val);
			return val;
		}

		internal static Renderer Primitive(string name, PrimitiveType type, Transform parent, Vector3 position, Vector3 size, Material material)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive(type);
			((Object)obj).name = name;
			obj.layer = LayerMask.NameToLayer("Ignore Raycast");
			Collider component = obj.GetComponent<Collider>();
			component.enabled = false;
			Object.Destroy((Object)(object)component);
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = position;
			obj.transform.localScale = size;
			Renderer component2 = obj.GetComponent<Renderer>();
			component2.sharedMaterial = material;
			component2.shadowCastingMode = (ShadowCastingMode)0;
			return component2;
		}

		private static Renderer Cube(string name, Transform parent, Vector3 position, Vector3 size, Material material)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return Primitive(name, (PrimitiveType)3, parent, position, size, material);
		}

		private void Rod(Transform parent, Vector3 a, Vector3 b, float width)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			((Component)Primitive("Steel hook", (PrimitiveType)2, parent, (a + b) * 0.5f, new Vector3(width, Vector3.Distance(a, b) * 0.5f, width), metal)).transform.localRotation = Quaternion.FromToRotation(Vector3.up, b - a);
		}

		internal static void Stroke(string name, Transform parent, Vector3[] points, float width, Material material)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			((Renderer)obj).sharedMaterial = material;
			obj.useWorldSpace = false;
			obj.positionCount = points.Length;
			obj.SetPositions(points);
			float startWidth = (obj.endWidth = width);
			obj.startWidth = startWidth;
			obj.numCornerVertices = 0;
			obj.numCapVertices = 0;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
		}

		private void LateUpdate()
		{
			if (initialized)
			{
				Present();
			}
		}

		public void Present()
		{
			//IL_00a8: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: 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_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: 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_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized)
			{
				return;
			}
			bool active = owner.Active;
			((Component)panel).gameObject.SetActive(active);
			((Component)hook).gameObject.SetActive(active);
			((Component)dock).gameObject.SetActive(active);
			DisplayedSegments = TowRules.LitSegments(owner.SpeedLimit);
			for (int i = 0; i < bars.Count; i++)
			{
				bars[i].sharedMaterial = ((i < DisplayedSegments) ? green : darkGreen);
			}
			Vector3 localPosition = marker.localPosition;
			float num = Mathf.Lerp(0f - halfHeight, halfHeight, Mathf.Clamp01(owner.ActualSpeedKmh / 45f));
			localPosition.y = Mathf.Lerp(localPosition.y, num, 1f - Mathf.Exp((0f - Time.unscaledDeltaTime) * 15f));
			marker.localPosition = localPosition;
			lamp.sharedMaterial = (owner.BoostEnabled ? green : amber);
			if (lastBoost != owner.BoostEnabled || lastAttached != owner.HasCart || lastHolder != owner.HookActor)
			{
				if (Object.op_Implicit((Object)(object)AssetManager.instance))
				{
					((owner.BoostEnabled == lastBoost) ? ((owner.HasCart || owner.HookActor != 0) ? AssetManager.instance.soundDeviceTurnOn : AssetManager.instance.soundDeviceTurnOff) : (owner.BoostEnabled ? AssetManager.instance.soundDeviceTurnOn : AssetManager.instance.soundDeviceTurnOff)).Play((owner.BoostEnabled != lastBoost) ? ButtonPosition : HookPosition, 1f, 1f, 1f, 1f);
				}
				if (lastBoost != owner.BoostEnabled)
				{
					pressAt = Time.time;
				}
				lastBoost = owner.BoostEnabled;
				lastAttached = owner.HasCart;
				lastHolder = owner.HookActor;
			}
			float num2 = Mathf.Sin(Mathf.Clamp01((Time.time - pressAt) / 0.25f) * MathF.PI) * 0.012f;
			button.localPosition = buttonHome + Vector3.forward * num2;
			hook.position = HookPosition;
			hook.rotation = (Object.op_Implicit((Object)(object)owner.AttachedCart) ? ((Component)owner.AttachedCart).transform.rotation : (Object.op_Implicit((Object)(object)owner.HookHolder) ? owner.HookHolder.localCamera.GetOverrideTransform().rotation : dock.rotation));
			if (Object.op_Implicit((Object)(object)owner.AttachedCart))
			{
				Transform obj = hook;
				obj.position += hook.rotation * new Vector3(-0.035f, 0.055f, -0.022f);
			}
			Highlighted = active && owner.IsHeldBy(SemiFunc.PlayerGetLocal()) && Object.op_Implicit((Object)(object)TowInteractions.Target);
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)panel))
			{
				Object.Destroy((Object)(object)((Component)panel).gameObject);
			}
			if (Object.op_Implicit((Object)(object)dock))
			{
				Object.Destroy((Object)(object)((Component)dock).gameObject);
			}
			foreach (Material material in materials)
			{
				if (Object.op_Implicit((Object)(object)material))
				{
					Object.Destroy((Object)(object)material);
				}
			}
		}
	}
	public static class TowRules
	{
		public const byte NetworkEventCode = 196;

		public const int MinSpeed = 5;

		public const int MaxSpeed = 45;

		public const int Step = 5;

		public const float HudSpeedFactor = 7.2f;

		public const float Reach = 3f;

		public const float CouplingReach = 2.8f;

		public const float AttachRadius = 0.36f;

		public const float AttachRetainRadius = 0.55f;

		public const float AttachHostRadius = 0.65f;

		public const float TargetGrace = 0.4f;

		public const float HookRadius = 0.14f;

		public static int ClampSpeed(int speed)
		{
			return Math.Max(5, Math.Min(45, speed));
		}

		public static int Scroll(int speed, float input)
		{
			if (!float.IsNaN(input) && !float.IsInfinity(input) && input != 0f)
			{
				return ClampSpeed(speed + ((input > 0f) ? 5 : (-5)));
			}
			return ClampSpeed(speed);
		}

		public static bool ValidLimit(int speed)
		{
			if (speed >= 5)
			{
				return speed <= 45;
			}
			return false;
		}

		public static bool ValidOperation(int operation)
		{
			if (operation >= 0)
			{
				return operation <= 6;
			}
			return false;
		}

		public static bool ValidScrollStep(int step)
		{
			if (step != -1)
			{
				return step == 1;
			}
			return true;
		}

		public static bool ValidActualSpeed(float speed)
		{
			return ValidDistance(speed, 1000f);
		}

		public static int LitSegments(int speed)
		{
			return (ClampSpeed(speed) + 5 - 1) / 5;
		}

		public static bool ValidDistance(float distance, float maximum)
		{
			if (!float.IsNaN(distance) && distance >= 0f)
			{
				return distance <= maximum;
			}
			return false;
		}

		public static float BrakeSpeed(float speed, int limit, float dt)
		{
			return Math.Max((float)ClampSpeed(limit) / 7.2f, speed - 6f * Math.Max(0f, dt));
		}

		public static (float x, float z) GovernorCorrection(float vx, float vz, float pendingX, float pendingZ, int limit, float dt)
		{
			float num = BrakeSpeed((float)Math.Sqrt(vx * vx + vz * vz), limit, dt);
			float num2 = vx + pendingX;
			float num3 = vz + pendingZ;
			float num4 = (float)Math.Sqrt(num2 * num2 + num3 * num3);
			if (float.IsNaN(num4) || float.IsInfinity(num4) || num4 <= num)
			{
				return (x: 0f, z: 0f);
			}
			float num5 = num / num4 - 1f;
			return (x: num2 * num5, z: num3 * num5);
		}

		public static bool MayUseParkedSwitch(bool occupied, bool seatedElsewhere, float speed, float distance)
		{
			if (!occupied && !seatedElsewhere && ValidDistance(speed, 1.5f))
			{
				return ValidDistance(distance, 3f);
			}
			return false;
		}

		public static bool MayChange(bool driver, bool nearby, int operation, bool parkedSwitch = false)
		{
			if (operation != 0 && operation != 3 && operation != 4 && operation != 5)
			{
				if (operation != 1)
				{
					return (operation == 2 || operation == 6) && driver;
				}
				return driver || parkedSwitch;
			}
			return nearby;
		}
	}
	public sealed class TowRuntime : MonoBehaviour, IOnEventCallback
	{
		private const byte EventCode = 196;

		private const string Protocol = "robin.towtuner/3";

		private const string VersionKey = "TowTuner.Version";

		internal static readonly List<TowVehicle> Vehicles = new List<TowVehicle>();

		private bool registered;

		private float nextSync;

		private float nextScroll;

		private static float nextSendWarning;

		private readonly Dictionary<int, float> requests = new Dictionary<int, float>();

		private LevelGenerator? generation;

		public static TowRuntime? Instance { get; private set; }

		public static bool Ready
		{
			get
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Invalid comparison between Unknown and I4
				if (Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated)
				{
					return !SemiFunc.RunIsArena();
				}
				return false;
			}
		}

		internal static bool Multiplayer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)GameManager.instance))
				{
					return GameManager.Multiplayer();
				}
				return false;
			}
		}

		internal static bool Host
		{
			get
			{
				if (Multiplayer)
				{
					if (PhotonNetwork.InRoom)
					{
						return PhotonNetwork.IsMasterClient;
					}
					return false;
				}
				return true;
			}
		}

		internal static bool Compatible { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			if (registered)
			{
				PhotonNetwork.RemoveCallbackTarget((object)this);
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			Compatible = false;
			TowCartGrip.ClearPending();
		}

		private void Update()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Invalid comparison between Unknown and I4
			if (!Object.op_Implicit((Object)(object)GameManager.instance) || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)LevelGenerator.Instance))
			{
				Compatible = false;
				return;
			}
			if (!registered)
			{
				PhotonNetwork.AddCallbackTarget((object)this);
				registered = true;
			}
			if ((Object)(object)generation != (Object)(object)LevelGenerator.Instance)
			{
				generation = LevelGenerator.Instance;
				requests.Clear();
				TowCartGrip.ClearPending();
				nextSync = 0f;
			}
			if (Multiplayer && PhotonNetwork.InRoom && (!(PhotonNetwork.LocalPlayer.CustomProperties[(object)"TowTuner.Version"] is string text) || !(text == "0.2.4")))
			{
				PhotonNetwork.LocalPlayer.SetCustomProperties(new Hashtable { [(object)"TowTuner.Version"] = "0.2.4" }, (Hashtable)null, (WebFlags)null);
			}
			Compatible = !Multiplayer || (PhotonNetwork.InRoom && PhotonNetwork.PlayerList.All((Player p) => p.CustomProperties[(object)"TowTuner.Version"] is string text2 && text2 == "0.2.4"));
			if (!Ready)
			{
				TowInteractions.CancelLocal();
				return;
			}
			if (Host && Time.unscaledTime >= nextSync)
			{
				nextSync = Time.unscaledTime + 0.2f;
				TowVehicle[] array = Vehicles.ToArray();
				foreach (TowVehicle towVehicle in array)
				{
					if (Object.op_Implicit((Object)(object)towVehicle))
					{
						Broadcast(towVehicle);
					}
				}
			}
			PlayerAvatar local = SemiFunc.PlayerGetLocal();
			if (!Object.op_Implicit((Object)(object)local))
			{
				return;
			}
			TowInteractions.Tick();
			TowVehicle towVehicle2 = Vehicles.FirstOrDefault((TowVehicle v) => Object.op_Implicit((Object)(object)v) && (Object)(object)v.Driver == (Object)(object)local);
			if (Object.op_Implicit((Object)(object)towVehicle2) && (int)Cursor.lockState == 1 && SemiFunc.NoTextInputsActive() && !(Time.timeScale <= 0f) && !((Object)(object)towVehicle2.Driver != (Object)(object)local) && TowPlugin.WheelEnabled.Value && Time.unscaledTime >= nextScroll)
			{
				float num2 = SemiFunc.InputScrollY();
				if (Mathf.Abs(num2) > 0.01f)
				{
					nextScroll = Time.unscaledTime + 0.12f;
					Request(towVehicle2, 6, (num2 > 0f) ? 1 : (-1));
				}
			}
		}

		public void Request(TowVehicle vehicle, int operation, int value, PhysGrabCart? cart = null)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			if (!Ready || !Compatible)
			{
				Show("Iedereen in de lobby heeft Tow Tuner 0.2.4 nodig.");
				return;
			}
			PlayerAvatar val = SemiFunc.PlayerGetLocal();
			if (Object.op_Implicit((Object)(object)val))
			{
				if (Host)
				{
					Apply(vehicle, val, operation, value, cart);
					return;
				}
				SendEvent(new object[5]
				{
					"robin.towtuner/3",
					0,
					vehicle.View.ViewID,
					operation,
					value
				}, new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)2
				});
			}
		}

		private void Apply(TowVehicle vehicle, PlayerAvatar player, int operation, int value, PhysGrabCart? cart = null)
		{
			string text = vehicle.HandleRequest(player, operation, value, cart);
			if ((Object)(object)player == (Object)(object)SemiFunc.PlayerGetLocal())
			{
				Show(text);
			}
			else if (Multiplayer && Object.op_Implicit((Object)(object)player.photonView) && player.photonView.Owner != null)
			{
				Send(new object[3] { "robin.towtuner/3", 2, text }, new int[1] { player.photonView.OwnerActorNr });
			}
			Broadcast(vehicle);
		}

		internal static void Broadcast(TowVehicle vehicle)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (Multiplayer && PhotonNetwork.InRoom && Host && Object.op_Implicit((Object)(object)vehicle.View) && vehicle.View.ViewID > 0)
			{
				Send(new object[11]
				{
					"robin.towtuner/3",
					1,
					vehicle.View.ViewID,
					vehicle.SpeedLimit,
					vehicle.BoostEnabled,
					vehicle.CartViewId,
					vehicle.CartAnchor,
					vehicle.RearAnchor,
					vehicle.RopeLength,
					vehicle.HookActor,
					vehicle.ActualSpeedKmh
				}, PeerActors());
			}
		}

		private static int[] PeerActors()
		{
			return (from p in PhotonNetwork.PlayerListOthers
				where p.CustomProperties[(object)"TowTuner.Version"] is string text && text == "0.2.4"
				select p.ActorNumber).ToArray();
		}

		private static void Send(object[] data, int[] actors)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			if (actors.Length != 0)
			{
				SendEvent(data, new RaiseEventOptions
				{
					TargetActors = actors
				});
			}
		}

		private static void SendEvent(object[] data, RaiseEventOptions options)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.RaiseEvent((byte)196, (object)data, options, SendOptions.SendReliable) && !(Time.unscaledTime < nextSendWarning))
			{
				nextSendWarning = Time.unscaledTime + 5f;
				TowPlugin.Log.LogWarning((object)"Tow Tuner could not send its multiplayer update. Check the room connection and that everyone has version 0.2.4.");
			}
		}

		public void OnEvent(EventData ev)
		{
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: 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_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			if (ev.Code != 196 || !Ready || !(ev.CustomData is object[] array) || array.Length < 3 || !(array[0] is string text) || text != "robin.towtuner/3" || !(array[1] is int num))
			{
				return;
			}
			object obj;
			if (num == 0 && Host && Compatible && array.Length == 5)
			{
				obj = array[2];
				if (obj is int)
				{
					int viewId = (int)obj;
					if (array[3] is int num2 && array[4] is int num3)
					{
						if (!TowRules.ValidOperation(num2))
						{
							return;
						}
						int key = ev.Sender * 8 + num2;
						if (!requests.TryGetValue(key, out var value) || !(Time.unscaledTime - value < 0.08f))
						{
							requests[key] = Time.unscaledTime;
							PlayerAvatar val = ((IEnumerable<PlayerAvatar>)SemiFunc.PlayerGetList()).FirstOrDefault((Func<PlayerAvatar, bool>)((PlayerAvatar p) => Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.photonView) && p.photonView.OwnerActorNr == ev.Sender));
							TowVehicle towVehicle = Vehicles.FirstOrDefault((TowVehicle v) => Object.op_Implicit((Object)(object)v) && Object.op_Implicit((Object)(object)v.View) && v.View.ViewID == viewId);
							object obj2;
							if (num2 != 4 || num3 <= 0)
							{
								obj2 = null;
							}
							else
							{
								PhotonView obj3 = PhotonView.Find(num3);
								obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<PhysGrabCart>() : null);
							}
							PhysGrabCart cart = (PhysGrabCart)obj2;
							if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)towVehicle))
							{
								Apply(towVehicle, val, num2, num3, cart);
							}
						}
						return;
					}
				}
			}
			if (!PhotonNetwork.InRoom || ev.Sender != PhotonNetwork.MasterClient.ActorNumber)
			{
				return;
			}
			if (num == 2 && array.Length == 3 && array[2] is string text2)
			{
				Show(text2);
			}
			if (num != 1 || array.Length != 11)
			{
				return;
			}
			obj = array[2];
			if (!(obj is int))
			{
				return;
			}
			int id = (int)obj;
			if (array[3] is int speed && array[4] is bool boost && array[5] is int num4 && array[6] is Vector3 val2 && array[7] is Vector3 val3 && array[8] is float num5 && array[9] is int num6 && num6 >= 0 && TowRules.ValidLimit(speed) && num4 >= 0 && Finite(val2) && Finite(val3) && TowRules.ValidDistance(num5, 2.8f) && array[10] is float num7 && TowRules.ValidActualSpeed(num7))
			{
				TowVehicle towVehicle2 = Vehicles.FirstOrDefault((TowVehicle v) => Object.op_Implicit((Object)(object)v) && Object.op_Implicit((Object)(object)v.View) && v.View.ViewID == id);
				if (Object.op_Implicit((Object)(object)towVehicle2))
				{
					towVehicle2.ReceiveState(speed, boost, num4, val2, val3, num5, num6, num7);
				}
			}
		}

		private static bool Finite(Vector3 value)
		{
			if (!float.IsNaN(((Vector3)(ref value)).sqrMagnitude) && !float.IsInfinity(((Vector3)(ref value)).sqrMagnitude))
			{
				return ((Vector3)(ref value)).sqrMagnitude < 10000f;
			}
			return false;
		}

		internal void Show(string text)
		{
			TowPlugin.Log.LogDebug((object)text);
		}
	}
	public sealed class TowVehicle : MonoBehaviour
	{
		private float hookDeadline;

		private PhysGrabCart? cart;

		private Rigidbody? cartBody;

		private PhysGrabObject? cartItem;

		private SpringJoint? joint;

		private LineRenderer? line;

		private Material? lineMaterial;

		private bool hadJoint;

		private float lastSwitchAt = -100f;

		private float cartContactUntil = -1f;

		private float receivedSpeed;

		public ItemVehicle Vehicle { get; private set; }

		public PhotonView View { get; private set; }

		public int SpeedLimit { get; private set; }

		public bool BoostEnabled { get; private set; }

		public float ActualSpeedKmh
		{
			get
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: 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_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				if (!TowRuntime.Host)
				{
					return receivedSpeed;
				}
				Vector3 velocity = Vehicle.rb.velocity;
				Vector2 val = new Vector2(velocity.x, velocity.z);
				float num = ((Vector2)(ref val)).magnitude * 7.2f;
				if (!float.IsNaN(num) && !float.IsInfinity(num))
				{
					return Mathf.Clamp(num, 0f, 1000f);
				}
				return 0f;
			}
		}

		public int CartViewId { get; private set; }

		public Vector3 CartAnchor { get; private set; }

		public Vector3 RearAnchor { get; private set; }

		public float RopeLength { get; private set; }

		public bool HasCart
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)cart))
				{
					return CartViewId > 0;
				}
				return true;
			}
		}

		public PlayerAvatar? Driver
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)Vehicle) || Vehicle.seats == null || Vehicle.seats.Length == 0)
				{
					return null;
				}
				return Vehicle.seats[0].seatedPlayer;
			}
		}

		public bool Active
		{
			get
			{
				if (((Behaviour)this).enabled && ((Component)this).gameObject.activeInHierarchy && TowRuntime.Ready)
				{
					return TowRuntime.Compatible;
				}
				return false;
			}
		}

		public PhysGrabCart? AttachedCart => cart;

		public bool HasJoint => Object.op_Implicit((Object)(object)joint);

		public TowPresentation Presentation { get; private set; }

		public int HookActor { get; private set; }

		public PlayerAvatar? HookHolder
		{
			get
			{
				if (HookActor != 0)
				{
					if (HookActor != -1)
					{
						return ((IEnumerable<PlayerAvatar>)SemiFunc.PlayerGetList()).FirstOrDefault((Func<PlayerAvatar, bool>)((PlayerAvatar p) => Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.photonView) && p.photonView.OwnerActorNr == HookActor));
					}
					return SemiFunc.PlayerGetLocal();
				}
				return null;
			}
		}

		public bool IsSeatedDriver(PlayerAvatar player)
		{
			if (Object.op_Implicit((Object)(object)player) && (Object)(object)Driver == (Object)(object)player)
			{
				if (!Vehicle.seats[0].reachedFirstMount)
				{
					return !Object.op_Implicit((Object)(object)Vehicle.seats[0].firstMountTransform);
				}
				return true;
			}
			return false;
		}

		private void Awake()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Vehicle = ((Component)this).GetComponent<ItemVehicle>();
			View = ((Component)this).GetComponent<PhotonView>();
			SpeedLimit = TowRules.ClampSpeed(TowPlugin.DefaultSpeed.Value);
			BoostEnabled = TowPlugin.DefaultBoost.Value;
			RearAnchor = FindRearAnchor(Vehicle);
			TowRuntime.Vehicles.Add(this);
			Presentation = ((Component)this).gameObject.AddComponent<TowPresentation>();
			Presentation.Initialize(this);
		}

		public static Vector3 FindRearAnchor(ItemVehicle vehicle)
		{
			//IL_00d4: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter val = ((IEnumerable<MeshFilter>)((Component)(Object.op_Implicit((Object)(object)vehicle.meshTransform) ? vehicle.meshTransform : ((Component)vehicle).transform)).GetComponentsInChildren<MeshFilter>(true)).FirstOrDefault((Func<MeshFilter, bool>)((MeshFilter m) => ((Object)m).name == "item vehicle bike back lights holder MAIN" && Object.op_Implicit((Object)(object)m.sharedMesh)));
			if (Object.op_Implicit((Object)(object)val))
			{
				Bounds bounds = val.sharedMesh.bounds;
				Vector3 val2 = ((Component)val).transform.TransformPoint(new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, ((Bounds)(ref bounds)).max.z));
				return ((Component)vehicle).transform.InverseTransformPoint(val2 - ((Component)vehicle).transform.forward * 0.025f);
			}
			TowPlugin.Log.LogWarning((object)"Unknown vehicle body: using compact fallback hitch mount.");
			return new Vector3(0f, 0.46f, -0.5f);
		}

		public bool CanUseSwitch(PlayerAvatar player)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)player))
			{
				if (!((Object)(object)Driver == (Object)(object)player))
				{
					bool occupied = Vehicle.seats.Any((VehicleSeat s) => Object.op_Implicit((Object)(object)s.seatedPlayer));
					bool seatedElsewhere = Object.op_Implicit((Object)(object)ItemVehicle.GetVehicleForPlayer(player));
					Vector3 velocity = Vehicle.rb.velocity;
					return TowRules.MayUseParkedSwitch(occupied, seatedElsewhere, ((Vector3)(ref velocity)).magnitude, Vector3.Distance(((Component)player).transform.position, Presentation.ButtonPosition));
				}
				return true;
			}
			return false;
		}

		public bool NearRear(PlayerAvatar player)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)player))
			{
				return Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.TransformPoint(RearAnchor)) <= 3f;
			}
			return false;
		}

		public string HandleRequest(PlayerAvatar player, int operation, int value, PhysGrabCart? requestedCart = null)
		{
			//IL_002c: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: 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_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			bool nearby = Object.op_Implicit((Object)(object)player) && (NearRear(player) || (HasCart && Object.op_Implicit((Object)(object)cart) && Vector3.Distance(((Component)player).transform.position, Hitch(cart)) <= 3f));
			if (!Active || !TowRuntime.Host || !Object.op_Implicit((Object)(object)player) || !TowRules.MayChange(IsSeatedDriver(player), nearby, operation, operation == 1 && CanUseSwitch(player)))
			{
				return "Niet bereikbaar of niet de bestuurder.";
			}
			Vector3 velocity;
			switch (operation)
			{
			case 3:
				if (!HasCart && HookActor == 0)
				{
					velocity = Vehicle.rb.velocity;
					if (!(((Vector3)(ref velocity)).magnitude > 1.5f) && NearRear(player) && !player.physGrabber.grabbed && !Object.op_Implicit((Object)(object)ItemVehicle.GetVehicleForPlayer(player)) && TowInteractions.Aimed(player, Presentation.HookPosition, 0.14f, this))
					{
						HookActor = Actor(player);
						hookDeadline = Time.unscaledTime + 25f;
						return "Haak opgepakt.";
					}
				}
				return "Haak niet beschikbaar.";
			case 5:
				if (IsHeldBy(player))
				{
					CancelHook();
				}
				return "Haak teruggezet.";
			case 1:
				if ((value != 0 && value != 1) || !CanUseSwitch(player) || !Presentation.ButtonAimed(player) || Time.unscaledTime - lastSwitchAt < 0.25f)
				{
					return "Richt op de boostknop.";
				}
				lastSwitchAt = Time.unscaledTime;
				BoostEnabled = value == 1;
				if (!BoostEnabled)
				{
					TowPatches.ClearBoost(Vehicle);
				}
				return "Boost " + (BoostEnabled ? "aan." : "uit.");
			case 2:
				if (!TowRules.ValidLimit(value))
				{
					return "Ongeldige snelheid.";
				}
				SpeedLimit = value;
				return $"Maximumsnelheid: {SpeedLimit} km/h.";
			case 6:
				if (!TowRules.ValidScrollStep(value))
				{
					return "Ongeldige snelheidsstap.";
				}
				SpeedLimit = TowRules.Scroll(SpeedLimit, value);
				return $"Maximumsnelheid: {SpeedLimit} km/h.";
			case 0:
				if (HasCart && !TowCartGrip.HandleAimed(player, cart) && TowInteractions.Aimed(player, Presentation.HookPosition, 0.14f, this, cart))
				{
					Detach();
					return "Kar losgemaakt.";
				}
				return "Richt op de aangesloten haak.";
			case 4:
				if (IsHeldBy(player))
				{
					CancelHook();
					velocity = Vehicle.rb.velocity;
					if (((Vector3)(ref velocity)).magnitude > 1.5f)
					{
						return "Stop even om de kar aan te koppelen.";
					}
					Vector3 val = ((Component)this).transform.TransformPoint(RearAnchor);
					if (!Object.op_Implicit((Object)(object)requestedCart) || !CanAttach(requestedCart, val) || !TowInteractions.Aimed(player, Hitch(requestedCart), 0.65f, this, requestedCart))
					{
						return "Breng de haak naar het bevestigingsoog op de kar.";
					}
					cart = requestedCart;
					cartBody = ((Component)cart).GetComponent<Rigidbody>();
					cartItem = ((Component)cart).GetComponent<PhysGrabObject>();
					CartAnchor = ((Component)cart).transform.InverseTransformPoint(Hitch(cart));
					RopeLength = Mathf.Clamp(Vector3.Distance(val, Hitch(cart)), 0.45f, 2.8f);
					CartViewId = (TowRuntime.Multiplayer ? ((Component)cart).GetComponent<PhotonView>().ViewID : 0);
					EnsureJoint();
					return "Kar aangekoppeld. Rij rustig; de kar kan nog steeds tegen dingen botsen.";
				}
				goto default;
			default:
				return "Pak eerst de haak.";
			}
		}

		public bool IsHeldBy(PlayerAvatar player)
		{
			if (HookActor != 0 && Object.op_Implicit((Object)(object)player))
			{
				return HookActor == Actor(player);
			}
			return false;
		}

		private static int Actor(PlayerAvatar p)
		{
			if (!TowRuntime.Multiplayer)
			{
				return -1;
			}
			return p.photonView.OwnerActorNr;
		}

		public void CancelHook()
		{
			HookActor = 0;
			hookDeadline = 0f;
		}

		public bool CanAttach(PhysGrabCart candidate, Vector3 rear)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)candidate) || !((Component)candidate).gameObject.activeInHierarchy)
			{
				return false;
			}
			Rigidbody body = ((Component)candidate).GetComponent<Rigidbody>();
			PhysGrabObject component = ((Component)candidate).GetComponent<PhysGrabObject>();
			if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)component) || (TowRuntime.Host && body.isKinematic) || TowCartGrip.HasPlayer(component))
			{
				return false;
			}
			if (TowRuntime.Multiplayer && (!Object.op_Implicit((Object)(object)((Component)candidate).GetComponent<PhotonView>()) || ((Component)candidate).GetComponent<PhotonView>().ViewID <= 0))
			{
				return false;
			}
			int candidateId = (TowRuntime.Multiplayer ? ((Component)candidate).GetComponent<PhotonView>().ViewID : 0);
			if (TowRuntime.Vehicles.Any((TowVehicle v) => Object.op_Implicit((Object)(object)v) && (Object)(object)v != (Object)(object)this && ((Object)(object)v.cart == (Object)(object)candidate || (candidateId > 0 && v.CartViewId == candidateId))))
			{
				return false;
			}
			Vector3 val = Hitch(candidate);
			if (!TowRules.ValidDistance(Vector3.Distance(rear, val), 2.8f) || Vector3.Dot(val - ((Component)this).transform.position, ((Component)this).transform.forward) > -0.2f)
			{