Decompiled source of FrogQTE v1.0.1

FrogQTE.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("FrogQTEMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FrogQTEMod")]
[assembly: AssemblyTitle("FrogQTEMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace FrogQTEMod;

[BepInPlugin("com.peaks.frogqte", "FrogQTE", "1.0.1")]
public class Plugin : BaseUnityPlugin
{
	public static Plugin Instance;

	internal ManualLogSource Logger;

	private Harmony _harmony;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> FlyTrapAmount;

	internal static ConfigEntry<int> PressesToEscape;

	internal static ConfigEntry<float> EscapeTime;

	internal static ConfigEntry<float> EscapeThreshold;

	internal static ConfigEntry<float> HoldTime;

	private void Awake()
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Expected O, but got Unknown
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Expected O, but got Unknown
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Expected O, but got Unknown
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Expected O, but got Unknown
		Instance = this;
		Logger = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the frog-capture QTE (mash Space to escape)");
		FlyTrapAmount = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FlyTrapAmount", 0.05f, new ConfigDescription("FlyTrap status (5% of HP) applied when the frog grabs you", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.025f, 1f), Array.Empty<object>()));
		PressesToEscape = ((BaseUnityPlugin)this).Config.Bind<int>("General", "PressesToEscape", 1, new ConfigDescription("How many Space presses it takes to escape", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
		EscapeTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EscapeTime", 5f, new ConfigDescription("Seconds you have to mash Space and escape", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>()));
		EscapeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EscapeThreshold", 0.025f, new ConfigDescription("FlyTrap status below which the frog lets go", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.1f), Array.Empty<object>()));
		HoldTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HoldTime", 1.5f, new ConfigDescription("Seconds the frog holds you (tongue stuck) before pulling", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), Array.Empty<object>()));
		_harmony = new Harmony("com.peaks.frogqte");
		_harmony.PatchAll(typeof(FrogQTE));
		MethodBase methodBase = FrogQTE.FindLickMoveNext();
		if (methodBase != null)
		{
			_harmony.Patch(methodBase, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FrogQTE), "TranspileLick", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			Logger.LogInfo((object)"[FrogQTE] Lock-hold patch applied to frog lick routine");
		}
		else
		{
			Logger.LogWarning((object)"[FrogQTE] Frog lick routine not found; hold time will not be extended");
		}
		Logger.LogInfo((object)"[FrogQTE] Loaded");
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch]
internal static class FrogQTE
{
	private static readonly FieldInfo TargetField = AccessTools.Field(typeof(FrogTongue), "_targetCharacter");

	private static readonly FieldInfo PullingField = AccessTools.Field(typeof(FrogTongue), "_isPulling");

	private static readonly MethodInfo LetGoMethod = AccessTools.Method(typeof(FrogTongue), "LetGo", (Type[])null, (Type[])null);

	private static readonly FieldInfo MovementCharField = AccessTools.Field(typeof(CharacterMovement), "character");

	internal static readonly Dictionary<int, float> CaptureStart = new Dictionary<int, float>();

	internal static readonly Dictionary<int, int> PressCount = new Dictionary<int, int>();

	private static bool IsSkeleton(Character character)
	{
		try
		{
			return (Object)(object)character?.data != (Object)null && character.data.isSkeleton;
		}
		catch
		{
			return false;
		}
	}

	internal static MethodBase FindLickMoveNext()
	{
		try
		{
			Type[] nestedTypes = typeof(FrogTongue).GetNestedTypes(BindingFlags.NonPublic);
			foreach (Type type in nestedTypes)
			{
				if (type.Name != null && type.Name.Contains("LickRoutine"))
				{
					MethodInfo method = type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null)
					{
						return method;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	internal static IEnumerable<CodeInstruction> TranspileLick(IEnumerable<CodeInstruction> instructions)
	{
		float num = 1f / Mathf.Max(0.05f, Plugin.HoldTime.Value);
		bool flag = false;
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		for (int i = 0; i < list.Count - 2; i++)
		{
			CodeInstruction val = list[i];
			CodeInstruction val2 = list[i + 1];
			CodeInstruction val3 = list[i + 2];
			if (val.opcode == OpCodes.Call && val.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Time) && methodInfo.Name == "get_deltaTime" && val2.opcode == OpCodes.Ldc_R4 && val2.operand is float num2 && Mathf.Abs(num2 - 2f) < 0.0001f && val3.opcode == OpCodes.Mul)
			{
				val2.operand = num;
				flag = true;
			}
		}
		if (!flag && (Object)(object)Plugin.Instance != (Object)null)
		{
			Plugin.Instance.Logger.LogWarning((object)"[FrogQTE] Transpiler did not find the lock loop");
		}
		return list;
	}

	[HarmonyPatch(typeof(FrogTongue), "Attack")]
	[HarmonyPostfix]
	private static void OnAttack(PhotonView characterView)
	{
		if (!Plugin.Enabled.Value || (Object)(object)characterView == (Object)null)
		{
			return;
		}
		Character component = ((Component)characterView).GetComponent<Character>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		try
		{
			if (IsSkeleton(component))
			{
				Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + component.characterName + " is a skeleton, immune to FlyTrap"));
			}
			else
			{
				component.refs.afflictions.AddStatus((STATUSTYPE)14, Plugin.FlyTrapAmount.Value, true, true, true);
			}
			CaptureStart[characterView.ViewID] = Time.time;
			PressCount[characterView.ViewID] = 0;
			Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + component.characterName + " grabbed by frog, mash Space to escape"));
		}
		catch (Exception ex)
		{
			Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] OnAttack: " + ex.Message));
		}
	}

	[HarmonyPatch(typeof(CharacterMovement), "TryToJump")]
	[HarmonyPostfix]
	private static void OnTryToJump(CharacterMovement __instance)
	{
		if (!Plugin.Enabled.Value)
		{
			return;
		}
		object? obj = MovementCharField?.GetValue(__instance);
		Character val = (Character)((obj is Character) ? obj : null);
		if ((Object)(object)val == (Object)null || !val.IsLocal || val.refs == null || (Object)(object)val.refs.afflictions == (Object)null)
		{
			return;
		}
		int viewID = ((MonoBehaviourPun)val).photonView.ViewID;
		if (!CaptureStart.ContainsKey(viewID))
		{
			return;
		}
		bool flag = IsSkeleton(val);
		if (!flag && val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) <= 0f)
		{
			return;
		}
		int value;
		int num = ((!PressCount.TryGetValue(viewID, out value)) ? 1 : (value + 1));
		PressCount[viewID] = num;
		if (num >= Plugin.PressesToEscape.Value)
		{
			if (!flag)
			{
				val.refs.afflictions.SubtractStatus((STATUSTYPE)14, 1f, false, false);
			}
			CancelFall(val);
			Plugin.Instance.Logger.LogInfo((object)$"[FrogQTE] {val.characterName} pressed Space {num} times, escaped!");
		}
	}

	private static void CancelFall(Character character)
	{
		try
		{
			if (!((Object)(object)character?.data == (Object)null) && !(character.data.fallSeconds <= 0f))
			{
				character.data.fallSeconds = 0f;
				if ((Object)(object)character.refs?.view != (Object)null)
				{
					character.refs.view.RPC("RPCA_UnFall", (RpcTarget)0, Array.Empty<object>());
				}
			}
		}
		catch (Exception ex)
		{
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				instance.Logger.LogWarning((object)("[FrogQTE] CancelFall: " + ex.Message));
			}
		}
	}

	[HarmonyPatch(typeof(FrogTongue), "FixedUpdate")]
	[HarmonyPostfix]
	private static void OnFixedUpdate(FrogTongue __instance)
	{
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.Enabled.Value)
		{
			return;
		}
		object? obj = TargetField?.GetValue(__instance);
		Character val = (Character)((obj is Character) ? obj : null);
		if ((Object)(object)val == (Object)null || (bool?)PullingField?.GetValue(__instance) != true)
		{
			return;
		}
		int value;
		bool flag = ((!IsSkeleton(val)) ? (val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) < Plugin.EscapeThreshold.Value) : (PressCount.TryGetValue(((MonoBehaviourPun)val).photonView.ViewID, out value) && value >= Plugin.PressesToEscape.Value));
		bool flag2 = false;
		if (!flag && CaptureStart.TryGetValue(((MonoBehaviourPun)val).photonView.ViewID, out var value2))
		{
			flag2 = Time.time - value2 > Plugin.EscapeTime.Value;
		}
		if (!flag && !flag2)
		{
			return;
		}
		if (PhotonNetwork.IsMasterClient)
		{
			try
			{
				if (flag)
				{
					CancelFall(val);
				}
				((MonoBehaviourPun)__instance).photonView.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
				{
					((MonoBehaviourPun)val).photonView,
					(object)(FrogActionType)3,
					Vector3.zero
				});
			}
			catch (Exception ex)
			{
				Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] LetGo RPC: " + ex.Message));
				LetGoMethod?.Invoke(__instance, null);
			}
		}
		if (flag)
		{
			Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + val.characterName + " escaped the frog!"));
		}
	}

	[HarmonyPatch(typeof(FrogTongue), "LetGo")]
	[HarmonyPrefix]
	private static void OnLetGo(FrogTongue __instance)
	{
		if (!Plugin.Enabled.Value)
		{
			return;
		}
		object? obj = TargetField?.GetValue(__instance);
		Character val = (Character)((obj is Character) ? obj : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		try
		{
			int viewID = ((MonoBehaviourPun)val).photonView.ViewID;
			CaptureStart.Remove(viewID);
			PressCount.Remove(viewID);
			if (val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) > 0f)
			{
				val.refs.afflictions.SubtractStatus((STATUSTYPE)14, 1f, true, false);
			}
		}
		catch (Exception ex)
		{
			Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] OnLetGo: " + ex.Message));
		}
	}
}