Decompiled source of LethalEscapeThrottle v1.1.0

LethalEscapeThrottle.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.AI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Erskine.LethalEscapeThrottle;

[BepInPlugin("Erskine.LethalEscapeThrottle", "LethalEscapeThrottle", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> cEnabled;

	internal static ConfigEntry<float> cCooldown;

	internal static ConfigEntry<float> cMaxBackoff;

	internal static ConfigEntry<bool> cDiag;

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

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

	internal static int DiagBlocked = 0;

	internal static int DiagSearched = 0;

	internal static int DiagFailed = 0;

	private const float DiagInterval = 30f;

	private float _diagTimer = 0f;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Expected O, but got Unknown
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Expected O, but got Unknown
		//IL_0167: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		cEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle for the throttle patch.");
		cCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CooldownSeconds", 2f, new ConfigDescription("Base seconds to skip the escape-exit search for an enemy that just failed to find any reachable exit. The search (a full scene scan plus a NavMesh path to every entrance) is what causes the lag, so this is the main dial.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), new object[0]));
		cMaxBackoff = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxBackoffSeconds", 15f, new ConfigDescription("Adaptive back-off cap. An enemy that keeps failing waits longer and longer between searches, up to this many seconds. Higher = less lag but slower to notice a newly-opened path.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), new object[0]));
		cDiag = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DiagnosticLogging", true, "Log a short summary every 30 seconds (only when active) showing how many exit searches were skipped vs actually run. Handy to confirm the throttle is doing something; turn off once you're satisfied.");
		try
		{
			Harmony val = new Harmony("Erskine.LethalEscapeThrottle");
			Type type = AccessTools.TypeByName("UpdatedEscape.Plugin");
			if (type == null)
			{
				Log.LogWarning((object)"Couldn't find UpdatedEscape.Plugin. Is LethalEscapeUpdated installed and enabled? Throttle not applied.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "FindClosestReachableEntrance", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogWarning((object)"Couldn't find FindClosestReachableEntrance (mod version changed?). Throttle not applied.");
				return;
			}
			val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches).GetMethod("Prefix")), new HarmonyMethod(typeof(Patches).GetMethod("Postfix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.LogInfo((object)("LethalEscapeThrottle v1.1.0: throttling FindClosestReachableEntrance (cooldown " + cCooldown.Value + "s, cap " + cMaxBackoff.Value + "s)."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed, throttle not applied: " + ex));
		}
	}

	private void Update()
	{
		if (cDiag == null || !cDiag.Value)
		{
			return;
		}
		_diagTimer += Time.deltaTime;
		if (!(_diagTimer < 30f))
		{
			_diagTimer = 0f;
			if (DiagBlocked > 0 || DiagSearched > 0)
			{
				Log.LogInfo((object)("[throttle] last " + 30 + "s: skipped " + DiagBlocked + " exit searches, ran " + DiagSearched + " (" + DiagFailed + " found no exit). Currently backing off " + BlockedUntil.Count + " enemy agent(s)."));
			}
			DiagBlocked = 0;
			DiagSearched = 0;
			DiagFailed = 0;
		}
	}
}
public static class Patches
{
	public static bool Prefix(NavMeshAgent agent, ref EntranceTeleport __result, out bool __state)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		__state = false;
		if (Plugin.cEnabled == null || !Plugin.cEnabled.Value)
		{
			__state = true;
			return true;
		}
		if ((Object)agent == (Object)null)
		{
			__state = true;
			return true;
		}
		int instanceID = ((Object)agent).GetInstanceID();
		if (Plugin.BlockedUntil.TryGetValue(instanceID, out var value) && Time.time < value)
		{
			__result = null;
			Plugin.DiagBlocked++;
			return false;
		}
		__state = true;
		return true;
	}

	public static void Postfix(NavMeshAgent agent, EntranceTeleport __result, bool __state)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Expected O, but got Unknown
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected O, but got Unknown
		if (!__state || (Object)agent == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)agent).GetInstanceID();
		Plugin.DiagSearched++;
		if ((Object)__result == (Object)null)
		{
			Plugin.DiagFailed++;
			int value;
			int num = ((!Plugin.Fails.TryGetValue(instanceID, out value)) ? 1 : (value + 1));
			Plugin.Fails[instanceID] = num;
			float num2 = Mathf.Min(Plugin.cCooldown.Value * Mathf.Pow(2f, (float)(num - 1)), Plugin.cMaxBackoff.Value);
			Plugin.BlockedUntil[instanceID] = Time.time + num2;
			if (Plugin.BlockedUntil.Count > 512)
			{
				Plugin.BlockedUntil.Clear();
				Plugin.Fails.Clear();
			}
		}
		else
		{
			Plugin.BlockedUntil.Remove(instanceID);
			Plugin.Fails.Remove(instanceID);
		}
	}
}