Decompiled source of FrogSkill v1.4.0

plugins/FrogSkill.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

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

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FrogSkill
{
	public sealed class CustomTongueMode : MonoBehaviour, ITongueMode
	{
		private const string FireRpc = "RPCA_FrogSkillFire";

		private const string MissRpc = "RPCA_FrogSkillMiss";

		private const string ReleaseRpc = "RPCA_FrogSkillRelease";

		private const float TongueTravelDuration = 0.25f;

		private const float FrogTargetTurnDuration = 0.5f;

		private const float NetworkMaxDistance = 65f;

		private Character _caster;

		private TongueContext _context;

		private Character? _target;

		private Rigidbody? _targetRig;

		private LineRenderer? _line;

		private Material? _lineMaterial;

		private float _firedAt;

		private float _pullStartedAt;

		private Vector3 _missEndpoint;

		private bool _missActive;

		private bool _pulling;

		private ModConfig Config => Plugin.Instance.Settings;

		bool ITongueMode.CanRelease => (Object)(object)_target != (Object)null;

		bool ITongueMode.IsBusy
		{
			get
			{
				if (!((Object)(object)_target != (Object)null))
				{
					return _missActive;
				}
				return true;
			}
		}

		private void Awake()
		{
			_caster = ((Component)this).GetComponent<Character>();
			_context = new TongueContext(_caster);
			CreateTongueVisual();
		}

		private void Update()
		{
			if ((Object)(object)_target != (Object)null && !IsValidActiveTarget())
			{
				ReleaseOrClear();
			}
			UpdateTongueVisual();
		}

		bool ITongueMode.TryFire()
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (!_caster.IsLocal || (Object)(object)Plugin.Instance == (Object)null || !Config.Enabled.Value || (Object)(object)_target != (Object)null || _missActive || !_context.CanCasterAttack() || !_context.TryGetAim(Config.MaxDistance.Value, Config.AimForgivenessDegrees.Value, out Character target, out Vector3 endpoint))
			{
				return false;
			}
			if ((Object)(object)target != (Object)null)
			{
				if (!FrogPullProfile.TryGet(Plugin.Instance.ModLogger, out FrogPullProfile _))
				{
					return false;
				}
				((MonoBehaviourPun)_caster).photonView.RPC("RPCA_FrogSkillFire", (RpcTarget)0, new object[1] { ((MonoBehaviourPun)target).photonView.ViewID });
			}
			else
			{
				((MonoBehaviourPun)_caster).photonView.RPC("RPCA_FrogSkillMiss", (RpcTarget)0, new object[1] { endpoint });
			}
			return true;
		}

		void ITongueMode.Release()
		{
			if (_caster.IsLocal && (Object)(object)_target != (Object)null)
			{
				SendRelease();
			}
		}

		private void FixedUpdate()
		{
			//IL_0059: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			if (!_pulling || (Object)(object)_target == (Object)null || (Object)(object)_targetRig == (Object)null)
			{
				return;
			}
			if ((Object)(object)Plugin.Instance == (Object)null || !Config.Enabled.Value || !IsValidActiveTarget())
			{
				ReleaseOrClear();
				return;
			}
			Vector3 mouthPosition = _context.GetMouthPosition();
			Vector3 val = mouthPosition - _target.Center;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (!FrogPullProfile.TryGet(Plugin.Instance.ModLogger, out FrogPullProfile profile))
			{
				ReleaseOrClear();
				return;
			}
			Vector3 val2 = ((magnitude > 0.001f) ? (val / magnitude) : Vector3.zero);
			float num = profile.PullStrengthCurve.Evaluate(magnitude);
			Vector3 val3 = val2 * Config.PullForce.Value * num;
			Vector3 val4 = Vector3.up * Mathf.Clamp(val.y, 0f, profile.MaxLiftDistance) * Config.LiftForce.Value;
			_target.refs.movement.ApplyExtraDrag(Config.ExtraDragOther.Value, true);
			_target.data.sinceGrounded = Mathf.Clamp(_target.data.sinceGrounded, 0f, 1f);
			if (((MonoBehaviourPun)_caster).photonView.IsMine)
			{
				_target.AddForceToBodyPart(_targetRig, (val3 + val4) * 0.2f, val3 + val4);
				float num2 = Mathf.Max(Time.fixedDeltaTime, Config.MaxHookDuration.Value - 0.5f);
				if (Vector3.Distance(mouthPosition, _targetRig.position) < Config.StopDistance.Value || Time.time - _pullStartedAt > num2)
				{
					SendRelease();
				}
			}
		}

		[PunRPC]
		public void RPCA_FrogSkillFire(int targetViewId, PhotonMessageInfo info)
		{
			//IL_0001: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			if (IsOwnerMessage(info.Sender) && !((Object)(object)_target != (Object)null))
			{
				PhotonView val = PhotonView.Find(targetViewId);
				Character val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<Character>());
				if (_context.IsPermittedTarget(val2) && !((Object)(object)Plugin.Instance == (Object)null) && FrogPullProfile.TryGet(Plugin.Instance.ModLogger, out FrogPullProfile _) && !(Vector3.Distance(_caster.Center, val2.Center) > 65f))
				{
					ClearMiss();
					_target = val2;
					_targetRig = val2.refs.ragdoll.partDict[(BodypartType)2].Rig;
					_firedAt = Time.time;
					_pulling = false;
					((Renderer)_line).enabled = true;
				}
			}
		}

		[PunRPC]
		public void RPCA_FrogSkillMiss(Vector3 endpoint, PhotonMessageInfo info)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (IsOwnerMessage(info.Sender) && !((Object)(object)_target != (Object)null) && !(Vector3.Distance(_caster.Center, endpoint) > 65f))
			{
				_missEndpoint = endpoint;
				_firedAt = Time.time;
				_missActive = true;
				((Renderer)_line).enabled = true;
			}
		}

		[PunRPC]
		public void RPCA_FrogSkillRelease(PhotonMessageInfo info)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (IsOwnerMessage(info.Sender))
			{
				ClearTarget();
			}
		}

		private bool IsValidActiveTarget()
		{
			if (_context.IsPermittedTarget(_target) && (Object)(object)_targetRig != (Object)null)
			{
				return !_caster.data.dead;
			}
			return false;
		}

		private bool IsOwnerMessage(Player sender)
		{
			if (sender != null && ((MonoBehaviourPun)_caster).photonView.Owner != null)
			{
				return sender.ActorNumber == ((MonoBehaviourPun)_caster).photonView.Owner.ActorNumber;
			}
			return false;
		}

		private void SendRelease()
		{
			if ((Object)(object)((MonoBehaviourPun)_caster).photonView != (Object)null)
			{
				((MonoBehaviourPun)_caster).photonView.RPC("RPCA_FrogSkillRelease", (RpcTarget)0, Array.Empty<object>());
			}
		}

		private void ReleaseOrClear()
		{
			if (((MonoBehaviourPun)_caster).photonView.IsMine)
			{
				SendRelease();
			}
			else
			{
				ClearTarget();
			}
		}

		private void ClearTarget()
		{
			if (_pulling && (Object)(object)_target != (Object)null && (Object)(object)_target.refs?.movement != (Object)null)
			{
				float num = (((Object)(object)Plugin.Instance == (Object)null) ? 0.1f : Config.ExtraDragLetGo.Value);
				_target.refs.movement.ApplyExtraDrag(num, true);
				_target.data.sinceGrounded = 0f;
			}
			_pulling = false;
			_targetRig = null;
			_target = null;
			if ((Object)(object)_line != (Object)null && !_missActive)
			{
				((Renderer)_line).enabled = false;
			}
		}

		private void ClearMiss()
		{
			_missActive = false;
			if ((Object)(object)_line != (Object)null && (Object)(object)_target == (Object)null)
			{
				((Renderer)_line).enabled = false;
			}
		}

		private void CreateTongueVisual()
		{
			_line = TongueVisual.CreateLine(((Component)this).transform, "FrogSkill Custom Tongue", out _lineMaterial);
		}

		private void UpdateTongueVisual()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			if ((Object)(object)_line == (Object)null || !((Renderer)_line).enabled)
			{
				return;
			}
			Vector3 mouthPosition = _context.GetMouthPosition();
			if (_missActive)
			{
				if (TongueVisual.UpdateMiss(_line, _firedAt, mouthPosition, _missEndpoint))
				{
					ClearMiss();
				}
			}
			else if (!((Object)(object)_target == (Object)null))
			{
				float num = Mathf.Clamp01((Time.time - _firedAt) / 0.25f);
				_line.SetPosition(0, mouthPosition);
				_line.SetPosition(1, Vector3.Lerp(mouthPosition, _target.Center, num));
				if (num >= 1f && !_pulling)
				{
					BeginPull();
				}
			}
		}

		private void BeginPull()
		{
			//IL_0027: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0069: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_target == (Object)null)
			{
				return;
			}
			_pulling = true;
			_pullStartedAt = Time.time;
			Vector3 val = _context.GetMouthPosition() - _target.Center;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				_target.data.lookValues = Vector2.op_Implicit(DirectionToLook(((Vector3)(ref val)).normalized));
			}
			if (((MonoBehaviourPun)_target).photonView.IsMine)
			{
				_target.refs.climbing.StopAnyClimbing();
				GamefeelHandler instance = GamefeelHandler.instance;
				if (instance != null)
				{
					instance.AddPerlinShake(5f, 0.2f, 15f);
				}
			}
			_target.RPCA_Fall(1f, 0f);
		}

		private static Vector3 DirectionToLook(Vector3 direction)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			Quaternion val = Quaternion.LookRotation(direction, Vector3.up);
			Vector3 eulerAngles = ((Quaternion)(ref val)).eulerAngles;
			while (eulerAngles.x > 180f)
			{
				eulerAngles.x -= 360f;
			}
			return new Vector3(eulerAngles.y, 0f - eulerAngles.x, 0f);
		}

		private void OnDestroy()
		{
			ClearTarget();
			ClearMiss();
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_lineMaterial);
			}
		}
	}
	internal sealed class FrogPullProfile
	{
		private const float RetryInterval = 5f;

		private static FrogPullProfile? _cached;

		private static float _nextSearchTime;

		private static bool _missingLogged;

		public AnimationCurve PullStrengthCurve { get; }

		public float MaxLiftDistance { get; }

		private FrogPullProfile(FrogTongue source)
		{
			PullStrengthCurve = CloneCurve(source.pullStrengthCurve);
			MaxLiftDistance = source.maxLiftDistance;
		}

		public static bool TryGet(ManualLogSource logger, out FrogPullProfile profile)
		{
			if (_cached != null)
			{
				profile = _cached;
				return true;
			}
			if (Time.unscaledTime < _nextSearchTime)
			{
				profile = null;
				return false;
			}
			_nextSearchTime = Time.unscaledTime + 5f;
			FrogTongue[] array = Resources.FindObjectsOfTypeAll<FrogTongue>();
			foreach (FrogTongue val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.pullStrengthCurve != null && val.pullStrengthCurve.length != 0)
				{
					_cached = new FrogPullProfile(val);
					_missingLogged = false;
					logger.LogInfo((object)("Captured vanilla FrogTongue drag profile from " + ((Object)((Component)val).gameObject).name + ": " + $"curve keys={_cached.PullStrengthCurve.length}, max lift distance={_cached.MaxLiftDistance}."));
					profile = _cached;
					return true;
				}
			}
			if (!_missingLogged)
			{
				_missingLogged = true;
				logger.LogWarning((object)"A loaded FrogTongue prefab was not found yet; tongue firing is unavailable until the vanilla pull curve can be captured.");
			}
			profile = null;
			return false;
		}

		private static AnimationCurve CloneCurve(AnimationCurve source)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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: Expected O, but got Unknown
			return new AnimationCurve(source.keys)
			{
				preWrapMode = source.preWrapMode,
				postWrapMode = source.postWrapMode
			};
		}
	}
	internal interface ITongueMode
	{
		bool IsBusy { get; }

		bool CanRelease { get; }

		bool TryFire();

		void Release();
	}
	internal sealed class ModConfig
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<string> ActivationPath { get; }

		public ConfigEntry<string> ModeSwitchPath { get; }

		public ConfigEntry<float> MaxDistance { get; }

		public ConfigEntry<float> AimForgivenessDegrees { get; }

		public ConfigEntry<float> PullForce { get; }

		public ConfigEntry<float> LiftForce { get; }

		public ConfigEntry<float> MaxHookDuration { get; }

		public ConfigEntry<float> StopDistance { get; }

		public ConfigEntry<float> ExtraDragOther { get; }

		public ConfigEntry<float> ExtraDragLetGo { get; }

		public ConfigEntry<float> Cooldown { get; }

		public ModConfig(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Scout tongue skill.");
			ActivationPath = config.Bind<string>("Controls", "Activation Path", "<Keyboard>/g", "Unity Input System control path for firing the tongue.");
			ModeSwitchPath = config.Bind<string>("Controls", "Mode Switch Path", "<Keyboard>/c", "Unity Input System control path for switching tongue modes.");
			MaxDistance = BindRange(config, "Tongue", "Max Distance", 40f, 5f, 60f, "Maximum target distance in meters. Vanilla FrogTongue default: 40.");
			AimForgivenessDegrees = BindRange(config, "Tongue", "Aim Forgiveness Degrees", 3f, 0f, 10f, "Aim-assist cone half-angle in degrees. Direct crosshair hits always take priority; set to 0 for strict targeting.");
			PullForce = BindRange(config, "Tongue", "Pull Force", 450f, 0f, 2000f, "Directional pull acceleration before the vanilla distance curve. Current Frog prefab default: 450.");
			LiftForce = BindRange(config, "Tongue", "Lift Force", 30f, 0f, 500f, "Additional upward acceleration per vertical meter. FrogSkill default: 30; set to 0 for no supplemental lift.");
			MaxHookDuration = BindRange(config, "Tongue", "Max Hook Duration", 1f, 0.5f, 10f, "Vanilla-style maximum hook time in seconds, including the 0.5 second target-turn phase. Current Frog prefab default: 1.");
			StopDistance = BindRange(config, "Tongue", "Stop Distance", 5f, 1f, 10f, "Release when the target reaches this distance. Vanilla FrogTongue default: 5.");
			ExtraDragOther = BindRange(config, "Tongue", "Extra Drag Other", 0.95f, 0f, 1f, "Velocity retention applied each physics frame while pulling. Vanilla FrogTongue default: 0.95.");
			ExtraDragLetGo = BindRange(config, "Tongue", "Extra Drag Let Go", 0.1f, 0f, 1f, "Velocity retention applied once when releasing. Vanilla FrogTongue default: 0.1.");
			Cooldown = BindRange(config, "Tongue", "Cooldown", 0.5f, 0f, 60f, "Cooldown after successfully grabbing a target. Misses do not trigger it.");
		}

		private static ConfigEntry<float> BindRange(ConfigFile config, string section, string key, float value, float min, float max, string description)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return config.Bind<float>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()));
		}
	}
	[BepInPlugin("com.github.lllei.FrogSkill", "FrogSkill", "1.4.0")]
	[BepInIncompatibility("com.github.lllei.FrogSkillVanilla")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.github.lllei.FrogSkill";

		public const string PluginName = "FrogSkill";

		private const string VanillaPluginGuid = "com.github.lllei.FrogSkillVanilla";

		private Harmony? _harmony;

		internal static Plugin? Instance { get; private set; }

		internal ModConfig Settings { get; private set; }

		internal ManualLogSource ModLogger => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Instance = this;
			Settings = new ModConfig(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.github.lllei.FrogSkill");
			_harmony.PatchAll(typeof(CharacterStartPatch));
			_harmony.PatchAll(typeof(FrogProxyAiPatch));
			_harmony.PatchAll(typeof(FrogProxyCollisionPatch));
			_harmony.PatchAll(typeof(FrogProxyReleasePatch));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"FrogSkill 1.4.0 loaded with Custom and Vanilla tongue modes.");
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
	[HarmonyPatch(typeof(FrogTongue), "RPCA_FrogAction")]
	internal static class FrogProxyReleasePatch
	{
		private static void Postfix(FrogTongue __instance, FrogActionType frogActionType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)frogActionType == 3)
			{
				VanillaFrogProxy.DestroyAfterRelease(((MonoBehaviourPun)__instance).photonView);
			}
		}
	}
	[HarmonyPatch(typeof(FrogTongue), "OnCollisionEnter")]
	internal static class FrogProxyCollisionPatch
	{
		private static bool Prefix(FrogTongue __instance)
		{
			return !VanillaFrogProxy.IsProxy(((MonoBehaviourPun)__instance).photonView);
		}
	}
	[HarmonyPatch(typeof(FrogTongue), "CheckAllCharacters")]
	internal static class FrogProxyAiPatch
	{
		private static bool Prefix(FrogTongue __instance)
		{
			return !VanillaFrogProxy.IsProxy(((MonoBehaviourPun)__instance).photonView);
		}
	}
	[HarmonyPatch(typeof(Character), "Start")]
	internal static class CharacterStartPatch
	{
		private static void Postfix(Character __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<CustomTongueMode>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<CustomTongueMode>();
			}
			((MonoBehaviourPun)__instance).photonView.RefreshRpcMonoBehaviourCache();
			if (__instance.IsLocal)
			{
				if ((Object)(object)((Component)__instance).GetComponent<VanillaTongueMode>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<VanillaTongueMode>();
				}
				if ((Object)(object)((Component)__instance).GetComponent<TongueModeController>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<TongueModeController>();
				}
			}
		}
	}
	internal sealed class TongueContext
	{
		private const float MissDistanceRatio = 0.35f;

		private const float VisibilityRayExtraDistance = 0.05f;

		private static readonly Vector3 FallbackMouthLocalOffset = new Vector3(0f, 0.82f, 0.16f);

		private readonly Character _caster;

		private readonly Renderer? _mouthRenderer;

		internal TongueContext(Character caster)
		{
			_caster = caster;
			AnimatedMouth component = ((Component)caster).GetComponent<AnimatedMouth>();
			_mouthRenderer = (((Object)(object)component != (Object)null) ? component.mouthRenderer : null);
			if ((Object)(object)_mouthRenderer == (Object)null && (Object)(object)caster.refs?.customization?.refs != (Object)null)
			{
				_mouthRenderer = caster.refs.customization.refs.mouthRenderer;
			}
		}

		internal bool TryGetAim(float maxDistance, float aimForgivenessDegrees, out Character? target, out Vector3 endpoint)
		{
			//IL_0005: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			target = null;
			endpoint = default(Vector3);
			Camera val = (((Object)(object)MainCamera.instance != (Object)null) ? ((Component)MainCamera.instance).GetComponent<Camera>() : Camera.main);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Ray val2 = val.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f));
			float num = maxDistance * 0.35f;
			endpoint = ((Ray)(ref val2)).GetPoint(num);
			int physicalMask = LayerMask.op_Implicit(HelperFunctions.GetMask((LayerType)7));
			TryGetNearestPhysicalHit(val2, maxDistance, physicalMask, out var nearestHit);
			if ((Object)(object)((RaycastHit)(ref nearestHit)).collider != (Object)null && ((RaycastHit)(ref nearestHit)).distance < num)
			{
				endpoint = ((RaycastHit)(ref nearestHit)).point;
			}
			Character val3 = default(Character);
			if ((Object)(object)((RaycastHit)(ref nearestHit)).collider != (Object)null && CharacterRagdoll.TryGetCharacterFromCollider(((RaycastHit)(ref nearestHit)).collider, ref val3) && IsPermittedTarget(val3))
			{
				target = val3;
				return true;
			}
			if (aimForgivenessDegrees > 0f)
			{
				target = FindAssistedTarget(val2, maxDistance, aimForgivenessDegrees, physicalMask);
			}
			return true;
		}

		private Character? FindAssistedTarget(Ray aimRay, float maxDistance, float aimForgivenessDegrees, int physicalMask)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_0081: 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_00a1: 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_00a7: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Tan(aimForgivenessDegrees * (MathF.PI / 180f));
			float num2 = float.MaxValue;
			float num3 = float.MaxValue;
			Character result = null;
			Collider[] array = Physics.OverlapSphere(((Ray)(ref aimRay)).origin, maxDistance, physicalMask);
			Character val2 = default(Character);
			Ray ray = default(Ray);
			Character val5 = default(Character);
			foreach (Collider val in array)
			{
				if ((Object)(object)val == (Object)null || !CharacterRagdoll.TryGetCharacterFromCollider(val, ref val2) || !IsPermittedTarget(val2))
				{
					continue;
				}
				Bounds bounds = val.bounds;
				float num4 = Vector3.Dot(((Bounds)(ref bounds)).center - ((Ray)(ref aimRay)).origin, ((Ray)(ref aimRay)).direction);
				Vector3 point = ((Ray)(ref aimRay)).GetPoint(Mathf.Clamp(num4, 0f, maxDistance));
				Vector3 val3 = val.ClosestPoint(point) - ((Ray)(ref aimRay)).origin;
				float num5 = Vector3.Dot(val3, ((Ray)(ref aimRay)).direction);
				float magnitude = ((Vector3)(ref val3)).magnitude;
				if (num5 <= 0f || magnitude <= 0f || magnitude > maxDistance)
				{
					continue;
				}
				Vector3 val4 = Vector3.Cross(((Ray)(ref aimRay)).direction, val3);
				float magnitude2 = ((Vector3)(ref val4)).magnitude;
				float num6 = num5 * num;
				if (magnitude2 > num6)
				{
					continue;
				}
				float num7 = magnitude2 / num5;
				if (!(num7 > num2) && (!Mathf.Approximately(num7, num2) || !(magnitude >= num3)))
				{
					((Ray)(ref ray))..ctor(((Ray)(ref aimRay)).origin, val3 / magnitude);
					if (TryGetNearestPhysicalHit(ray, magnitude + 0.05f, physicalMask, out var nearestHit) && CharacterRagdoll.TryGetCharacterFromCollider(((RaycastHit)(ref nearestHit)).collider, ref val5) && !((Object)(object)val5 != (Object)(object)val2))
					{
						num2 = num7;
						num3 = magnitude;
						result = val2;
					}
				}
			}
			return result;
		}

		private bool TryGetNearestPhysicalHit(Ray ray, float maxDistance, int physicalMask, out RaycastHit nearestHit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0022: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			nearestHit = default(RaycastHit);
			float num = float.MaxValue;
			RaycastHit[] array = Physics.RaycastAll(ray, maxDistance, physicalMask);
			Character val2 = default(Character);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).distance >= num))
				{
					CharacterRagdoll.TryGetCharacterFromCollider(((RaycastHit)(ref val)).collider, ref val2);
					if (!((Object)(object)val2 == (Object)(object)_caster))
					{
						num = ((RaycastHit)(ref val)).distance;
						nearestHit = val;
					}
				}
			}
			return (Object)(object)((RaycastHit)(ref nearestHit)).collider != (Object)null;
		}

		internal bool IsPermittedTarget(Character? target)
		{
			if ((Object)(object)target == (Object)null || (Object)(object)target == (Object)(object)_caster)
			{
				return false;
			}
			if ((target.isZombie || (!target.isBot && !target.isScoutmaster)) && (Object)(object)target.data != (Object)null && !target.data.dead && !target.data.fullyPassedOut && (Object)(object)target.refs?.ragdoll != (Object)null)
			{
				return target.refs.ragdoll.partDict.ContainsKey((BodypartType)2);
			}
			return false;
		}

		internal bool CanCasterAttack()
		{
			if ((Object)(object)_caster.data != (Object)null && !_caster.data.dead && !_caster.data.fullyPassedOut)
			{
				return !_caster.warping;
			}
			return false;
		}

		internal Vector3 GetMouthPosition()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_mouthRenderer != (Object)null)
			{
				Bounds bounds = _mouthRenderer.bounds;
				return ((Bounds)(ref bounds)).center;
			}
			return _caster.refs.head.transform.TransformPoint(FallbackMouthLocalOffset);
		}
	}
	internal sealed class TongueModeController : MonoBehaviour
	{
		private enum TongueMode
		{
			Custom,
			Vanilla
		}

		private ITongueMode _customTongue;

		private ITongueMode _vanillaTongue;

		private Character _caster;

		private ModConfig _config;

		private TongueMode _mode;

		private float _nextFireTime;

		private bool _refirePending;

		private TextMeshProUGUI? _modeLabel;

		private Material? _modeLabelMaterial;

		private CanvasGroup? _modeLabelGroup;

		private Coroutine? _modeLabelRoutine;

		private InputAction? _activationAction;

		private InputAction? _modeSwitchAction;

		private ModConfig Config => _config;

		private void Awake()
		{
			_caster = ((Component)this).GetComponent<Character>();
			_customTongue = ((Component)this).GetComponent<CustomTongueMode>();
			_vanillaTongue = ((Component)this).GetComponent<VanillaTongueMode>();
			_config = Plugin.Instance.Settings;
			_mode = TongueMode.Custom;
			BindInputActions();
			Config.ActivationPath.SettingChanged += OnInputPathChanged;
			Config.ModeSwitchPath.SettingChanged += OnInputPathChanged;
		}

		private void Update()
		{
			if ((Object)(object)Plugin.Instance == (Object)null || !CanReadInput())
			{
				return;
			}
			int num;
			if (!string.Equals(Config.ActivationPath.Value?.Trim(), Config.ModeSwitchPath.Value?.Trim(), StringComparison.OrdinalIgnoreCase))
			{
				InputAction? modeSwitchAction = _modeSwitchAction;
				num = ((modeSwitchAction != null && modeSwitchAction.WasPressedThisFrame()) ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			InputAction? activationAction = _activationAction;
			bool flag = activationAction != null && activationAction.WasPressedThisFrame();
			if (num != 0)
			{
				SwitchMode();
			}
			if (!flag || !(Time.time < _nextFireTime))
			{
				if (flag && _customTongue.CanRelease)
				{
					_customTongue.Release();
					_refirePending = true;
				}
				else if (flag && _vanillaTongue.CanRelease)
				{
					_vanillaTongue.Release();
					_refirePending = true;
				}
				else if (flag && !_customTongue.IsBusy && !_vanillaTongue.IsBusy)
				{
					TryFire();
				}
				if (_refirePending && !_customTongue.IsBusy && !_vanillaTongue.IsBusy)
				{
					_refirePending = false;
					TryFire();
				}
			}
		}

		private void TryFire()
		{
			if (Config.Enabled.Value)
			{
				ITongueMode tongueMode = ((_mode == TongueMode.Custom) ? _customTongue : _vanillaTongue);
				if (tongueMode.TryFire() && tongueMode.CanRelease)
				{
					_nextFireTime = Time.time + Config.Cooldown.Value;
				}
			}
		}

		private void SwitchMode()
		{
			_mode = ((_mode == TongueMode.Custom) ? TongueMode.Vanilla : TongueMode.Custom);
			string text = ((_mode == TongueMode.Vanilla) ? "Vanilla" : "Custom");
			ShowModeNotification(text);
			Plugin? instance = Plugin.Instance;
			if (instance != null)
			{
				instance.ModLogger.LogInfo((object)("Tongue mode switched to " + text + "."));
			}
		}

		private void ShowModeNotification(string modeName)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (EnsureModeLabel() && !((Object)(object)_modeLabel == (Object)null) && !((Object)(object)_modeLabelGroup == (Object)null))
			{
				Color playerColor = _caster.refs.customization.PlayerColor;
				playerColor.a = 1f;
				((Graphic)_modeLabel).color = playerColor;
				((TMP_Text)_modeLabel).text = "Tongue mode: " + modeName;
				((TMP_Text)_modeLabel).transform.SetAsLastSibling();
				if (_modeLabelRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_modeLabelRoutine);
				}
				_modeLabelRoutine = ((MonoBehaviour)this).StartCoroutine(ShowModeLabelRoutine());
			}
		}

		private bool EnsureModeLabel()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			if ((Object)(object)_modeLabel != (Object)null && (Object)(object)_modeLabelGroup != (Object)null)
			{
				return true;
			}
			if ((Object)(object)GUIManager.instance == (Object)null || (Object)(object)GUIManager.instance.hudCanvas == (Object)null)
			{
				return false;
			}
			GameObject val = new GameObject("FrogSkill Mode Notification", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(((Component)GUIManager.instance.hudCanvas).transform, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -96f);
			component.sizeDelta = new Vector2(520f, 52f);
			_modeLabelGroup = val.GetComponent<CanvasGroup>();
			_modeLabelGroup.alpha = 0f;
			_modeLabelGroup.blocksRaycasts = false;
			_modeLabelGroup.interactable = false;
			_modeLabel = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)_modeLabel).alignment = (TextAlignmentOptions)514;
			((TMP_Text)_modeLabel).fontSize = 30f;
			TextMeshProUGUI val2 = GUIManager.instance.interactNameText ?? GUIManager.instance.itemPromptMain;
			if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Text)val2).font != (Object)null)
			{
				((TMP_Text)_modeLabel).font = ((TMP_Text)val2).font;
				((TMP_Text)_modeLabel).fontStyle = ((TMP_Text)val2).fontStyle;
				if ((Object)(object)((TMP_Text)val2).fontSharedMaterial != (Object)null)
				{
					_modeLabelMaterial = new Material(((TMP_Text)val2).fontSharedMaterial);
					((TMP_Text)_modeLabel).fontSharedMaterial = _modeLabelMaterial;
				}
			}
			((TMP_Text)_modeLabel).faceColor = Color32.op_Implicit(Color.white);
			((TMP_Text)_modeLabel).outlineColor = Color32.op_Implicit(Color.black);
			((TMP_Text)_modeLabel).outlineWidth = 0.08f;
			((Graphic)_modeLabel).raycastTarget = false;
			return true;
		}

		private IEnumerator ShowModeLabelRoutine()
		{
			if (!((Object)(object)_modeLabelGroup == (Object)null))
			{
				_modeLabelGroup.alpha = 1f;
				yield return (object)new WaitForSecondsRealtime(1.25f);
				float elapsed = 0f;
				while (elapsed < 0.25f && (Object)(object)_modeLabelGroup != (Object)null)
				{
					elapsed += Time.unscaledDeltaTime;
					_modeLabelGroup.alpha = 1f - Mathf.Clamp01(elapsed / 0.25f);
					yield return null;
				}
				if ((Object)(object)_modeLabelGroup != (Object)null)
				{
					_modeLabelGroup.alpha = 0f;
				}
				_modeLabelRoutine = null;
			}
		}

		private static bool CanReadInput()
		{
			if (Time.timeScale > 0f && (Object)(object)GUIManager.instance != (Object)null && !GUIManager.instance.windowBlockingInput)
			{
				return !GUIManager.instance.wheelActive;
			}
			return false;
		}

		private void OnInputPathChanged(object sender, EventArgs eventArgs)
		{
			BindInputActions();
		}

		private void BindInputActions()
		{
			InputAction? activationAction = _activationAction;
			if (activationAction != null)
			{
				activationAction.Dispose();
			}
			_activationAction = CreateButtonAction("FrogSkillActivation", Config.ActivationPath.Value, "activation");
			InputAction? modeSwitchAction = _modeSwitchAction;
			if (modeSwitchAction != null)
			{
				modeSwitchAction.Dispose();
			}
			_modeSwitchAction = CreateButtonAction("FrogSkillModeSwitch", Config.ModeSwitchPath.Value, "mode-switch");
		}

		private static InputAction? CreateButtonAction(string actionName, string? controlPath, string logName)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			controlPath = controlPath?.Trim() ?? string.Empty;
			if (controlPath.Length == 0)
			{
				Plugin? instance = Plugin.Instance;
				if (instance != null)
				{
					instance.ModLogger.LogWarning((object)("The " + logName + " path is empty; the action is disabled."));
				}
				return null;
			}
			InputAction val = null;
			try
			{
				val = new InputAction(actionName, (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
				InputActionSetupExtensions.AddBinding(val, controlPath, (string)null, (string)null, (string)null);
				val.Enable();
				return val;
			}
			catch (Exception ex)
			{
				if (val != null)
				{
					val.Dispose();
				}
				Plugin? instance2 = Plugin.Instance;
				if (instance2 != null)
				{
					instance2.ModLogger.LogWarning((object)("Could not bind the configured " + logName + " path; the action is disabled: " + ex.Message));
				}
				return null;
			}
		}

		private void OnDestroy()
		{
			Config.ActivationPath.SettingChanged -= OnInputPathChanged;
			Config.ModeSwitchPath.SettingChanged -= OnInputPathChanged;
			InputAction? activationAction = _activationAction;
			if (activationAction != null)
			{
				activationAction.Dispose();
			}
			_activationAction = null;
			InputAction? modeSwitchAction = _modeSwitchAction;
			if (modeSwitchAction != null)
			{
				modeSwitchAction.Dispose();
			}
			_modeSwitchAction = null;
			if ((Object)(object)_modeLabel != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_modeLabel).gameObject);
			}
			if ((Object)(object)_modeLabelMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_modeLabelMaterial);
			}
		}
	}
	internal static class TongueVisual
	{
		private const float MissExtendDuration = 0.12f;

		private const float MissRetractDuration = 0.12f;

		private static readonly Color Color = new Color(0.85f, 0.18f, 0.28f, 1f);

		internal static LineRenderer CreateLine(Transform parent, string objectName, out 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)
			//IL_005a: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(objectName);
			val.transform.SetParent(parent, false);
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			val2.useWorldSpace = true;
			val2.positionCount = 2;
			val2.startWidth = 0.075f;
			val2.endWidth = 0.035f;
			val2.numCapVertices = 4;
			Shader val3 = Shader.Find("Sprites/Default");
			material = (((Object)(object)val3 == (Object)null) ? ((Material)null) : new Material(val3));
			if ((Object)(object)material != (Object)null)
			{
				((Renderer)val2).material = material;
			}
			val2.startColor = Color;
			val2.endColor = Color;
			((Renderer)val2).enabled = false;
			return val2;
		}

		internal static bool UpdateMiss(LineRenderer line, float startedAt, Vector3 origin, Vector3 endpoint)
		{
			//IL_0028: 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)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time - startedAt;
			float num2 = Mathf.Clamp01(num / 0.12f);
			float num3 = Mathf.Clamp01((num - 0.12f) / 0.12f);
			line.SetPosition(0, origin);
			line.SetPosition(1, Vector3.Lerp(origin, endpoint, num2 * (1f - num3)));
			return num3 >= 1f;
		}
	}
	internal static class VanillaFrogProxy
	{
		private const int Marker = 1179799367;

		private static readonly HashSet<int> PendingDestroy = new HashSet<int>();

		internal static object[] InstantiationData { get; } = new object[1] { 1179799367 };

		internal static bool IsProxy(PhotonView? view)
		{
			object[] array = ((view != null) ? view.InstantiationData : null);
			if (array != null && array.Length == 1 && array[0] is int num)
			{
				return num == 1179799367;
			}
			return false;
		}

		internal static void DestroyAfterRelease(PhotonView? view)
		{
			if (!((Object)(object)view == (Object)null) && view.IsMine && IsProxy(view) && PendingDestroy.Add(view.ViewID) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(DestroyNextFrame(view, view.ViewID));
			}
		}

		private static IEnumerator DestroyNextFrame(PhotonView view, int viewId)
		{
			yield return null;
			PendingDestroy.Remove(viewId);
			if (!((Object)(object)view == (Object)null) && view.IsMine && IsProxy(view))
			{
				if (PhotonNetwork.InRoom)
				{
					PhotonNetwork.Destroy(((Component)view).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)view).gameObject);
				}
			}
		}
	}
	internal sealed class VanillaTongueMode : MonoBehaviour, ITongueMode
	{
		private const string FrogPrefabName = "0_Items/Frog";

		private const string FrogActionRpc = "RPCA_FrogAction";

		private const string SetKinematicRpc = "SetKinematicRPC";

		private const float ProxySyncInterval = 0.08f;

		private const float ProxyCleanupDelay = 0.2f;

		private Character _caster;

		private TongueContext _context;

		private GameObject? _proxy;

		private FrogTongue? _proxyTongue;

		private PhotonView? _proxyView;

		private LineRenderer? _missLine;

		private Material? _missLineMaterial;

		private float _nextProxySyncTime;

		private float _cleanupAt = float.PositiveInfinity;

		private float _missStartedAt;

		private Vector3 _missEndpoint;

		private bool _missActive;

		private bool _releaseSent;

		private ModConfig Config => Plugin.Instance.Settings;

		bool ITongueMode.CanRelease
		{
			get
			{
				if ((Object)(object)_proxy != (Object)null)
				{
					return !_releaseSent;
				}
				return false;
			}
		}

		bool ITongueMode.IsBusy
		{
			get
			{
				if (!((Object)(object)_proxy != (Object)null))
				{
					return _missActive;
				}
				return true;
			}
		}

		private void Awake()
		{
			_caster = ((Component)this).GetComponent<Character>();
			_context = new TongueContext(_caster);
			CreateMissVisual();
		}

		private void Update()
		{
			UpdateMissVisual();
			if (_caster.IsLocal && !((Object)(object)Plugin.Instance == (Object)null) && (Object)(object)_proxy != (Object)null)
			{
				FollowProxy();
				if (Time.time >= _cleanupAt)
				{
					DestroyProxy();
				}
			}
		}

		bool ITongueMode.TryFire()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (!_caster.IsLocal || (Object)(object)Plugin.Instance == (Object)null || !Config.Enabled.Value || (Object)(object)_proxy != (Object)null || _missActive || !_context.CanCasterAttack() || !_context.TryGetAim(Config.MaxDistance.Value, Config.AimForgivenessDegrees.Value, out Character target, out Vector3 endpoint))
			{
				return false;
			}
			if ((Object)(object)target != (Object)null)
			{
				return FireProxy(target);
			}
			StartMiss(endpoint);
			return true;
		}

		void ITongueMode.Release()
		{
			if (_caster.IsLocal)
			{
				ReleaseProxy();
			}
		}

		private bool FireProxy(Character target)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.InRoom)
			{
				Plugin.Instance.ModLogger.LogWarning((object)"A Photon room is required to create the vanilla frog proxy.");
				return false;
			}
			Vector3 mouthPosition = _context.GetMouthPosition();
			Quaternion proxyRotation = GetProxyRotation(target.Center - mouthPosition);
			GameObject val;
			try
			{
				val = PhotonNetwork.Instantiate("0_Items/Frog", mouthPosition, proxyRotation, (byte)0, VanillaFrogProxy.InstantiationData);
			}
			catch (Exception arg)
			{
				Plugin.Instance.ModLogger.LogError((object)$"Failed to instantiate the vanilla frog proxy: {arg}");
				return false;
			}
			_proxy = val;
			_proxyTongue = val.GetComponent<FrogTongue>();
			_proxyView = val.GetComponent<PhotonView>();
			Item component = val.GetComponent<Item>();
			if ((Object)(object)_proxyTongue == (Object)null || (Object)(object)_proxyView == (Object)null || (Object)(object)component == (Object)null)
			{
				Plugin.Instance.ModLogger.LogError((object)"The vanilla Frog prefab is missing FrogTongue, Item, or PhotonView.");
				DestroyProxy();
				return false;
			}
			ConfigureOwnedProxy(component, _proxyTongue);
			MoveProxy(mouthPosition, proxyRotation);
			_proxyView.RPC("SetKinematicRPC", (RpcTarget)0, new object[3]
			{
				true,
				val.transform.position,
				val.transform.rotation
			});
			_proxyView.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
			{
				((MonoBehaviourPun)target).photonView,
				(object)(FrogActionType)1,
				Vector3.zero
			});
			_nextProxySyncTime = Time.time + 0.08f;
			_cleanupAt = Time.time + _proxyTongue.maxScoutHookTime + 1.25f;
			_releaseSent = false;
			return true;
		}

		private void ConfigureOwnedProxy(Item proxyItem, FrogTongue tongue)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			proxyItem.blockInteraction = true;
			proxyItem.rig.useGravity = false;
			proxyItem.rig.detectCollisions = false;
			proxyItem.rig.linearVelocity = Vector3.zero;
			proxyItem.rig.angularVelocity = Vector3.zero;
			((Mob)tongue).sleeping = true;
			tongue.dragForce = Config.PullForce.Value;
			tongue.liftDragForce = Config.LiftForce.Value;
			tongue.maxScoutHookTime = Config.MaxHookDuration.Value;
			tongue.stopPullFriendDistance = Config.StopDistance.Value;
		}

		private void FollowProxy()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0048: 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_0052: 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_0055: 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)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_proxy == (Object)null) && !((Object)(object)_proxyView == (Object)null) && !((Object)(object)_proxyTongue == (Object)null))
			{
				Vector3 mouthPosition = _context.GetMouthPosition();
				Quaternion proxyRotation = GetProxyRotation(_proxyTongue.tongueEnd.position - mouthPosition);
				MoveProxy(mouthPosition, proxyRotation);
				if (!(Time.time < _nextProxySyncTime))
				{
					_nextProxySyncTime = Time.time + 0.08f;
					_proxyView.RPC("SetKinematicRPC", (RpcTarget)1, new object[3]
					{
						true,
						_proxy.transform.position,
						_proxy.transform.rotation
					});
				}
			}
		}

		private void MoveProxy(Vector3 mouth, Quaternion rotation)
		{
			//IL_002a: 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_003c: 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_004c: 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_0054: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			if (!((Object)(object)_proxy == (Object)null) && !((Object)(object)_proxyTongue == (Object)null))
			{
				Transform transform = _proxy.transform;
				transform.SetPositionAndRotation(mouth, rotation);
				Vector3 val = _proxyTongue.dragPoint.position - transform.position;
				transform.position -= val;
				Rigidbody component = _proxy.GetComponent<Rigidbody>();
				if (!((Object)(object)component == (Object)null))
				{
					component.position = transform.position;
					component.rotation = transform.rotation;
					component.linearVelocity = Vector3.zero;
					component.angularVelocity = Vector3.zero;
				}
			}
		}

		private void ReleaseProxy()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_proxyView == (Object)null) && !_releaseSent)
			{
				_releaseSent = true;
				_proxyView.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
				{
					_proxyView,
					(object)(FrogActionType)3,
					Vector3.zero
				});
				_cleanupAt = Time.time + 0.2f;
			}
		}

		private void DestroyProxy()
		{
			GameObject proxy = _proxy;
			_proxy = null;
			_proxyTongue = null;
			_proxyView = null;
			_cleanupAt = float.PositiveInfinity;
			_releaseSent = false;
			if (!((Object)(object)proxy == (Object)null))
			{
				PhotonView component = proxy.GetComponent<PhotonView>();
				if (PhotonNetwork.InRoom && (Object)(object)component != (Object)null && component.IsMine)
				{
					PhotonNetwork.Destroy(proxy);
				}
				else
				{
					Object.Destroy((Object)(object)proxy);
				}
			}
		}

		private static Quaternion GetProxyRotation(Vector3 direction)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			direction.y = 0f;
			if (!(((Vector3)(ref direction)).sqrMagnitude > 0.0001f))
			{
				return Quaternion.identity;
			}
			return Quaternion.LookRotation(((Vector3)(ref direction)).normalized, Vector3.up);
		}

		private void CreateMissVisual()
		{
			_missLine = TongueVisual.CreateLine(((Component)this).transform, "FrogSkill Vanilla Miss Tongue", out _missLineMaterial);
		}

		private void StartMiss(Vector3 endpoint)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_missLine == (Object)null))
			{
				_missEndpoint = endpoint;
				_missStartedAt = Time.time;
				_missActive = true;
				((Renderer)_missLine).enabled = true;
			}
		}

		private void UpdateMissVisual()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (_missActive && !((Object)(object)_missLine == (Object)null))
			{
				Vector3 mouthPosition = _context.GetMouthPosition();
				if (TongueVisual.UpdateMiss(_missLine, _missStartedAt, mouthPosition, _missEndpoint))
				{
					_missActive = false;
					((Renderer)_missLine).enabled = false;
				}
			}
		}

		private void OnDestroy()
		{
			DestroyProxy();
			if ((Object)(object)_missLineMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_missLineMaterial);
			}
		}
	}
	internal static class BuildInfo
	{
		internal const string Version = "1.4.0";
	}
}