using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Landfall.TABC;
using Landfall.TABS;
using Landfall.TABS.AI.Systems;
using RootMotion;
using Unity.Entities;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Tabs Poof Mod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tabs Poof Mod")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8aad4f38-2ad4-4206-bf0b-7d28fb6d5c2e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace mypanicfpsmodd;
[BepInPlugin("bayturtleking.panicfps", "Panic FPS", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource logzzz;
private void Awake()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
logzzz = ((BaseUnityPlugin)this).Logger;
panicconfiggg.bindddd(((BaseUnityPlugin)this).Config);
Harmony val = new Harmony("bayturtleking.panicfps");
val.PatchAll();
morefpscompatt(val);
SceneManager.sceneLoaded += newstuffhappe;
}
private void Update()
{
//IL_0005: 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)
if (Input.GetKeyDown(panicconfiggg.panickeyyy.Value))
{
panicstateee.flipitt();
}
if (Input.GetKeyDown(panicconfiggg.cleankeyyy.Value))
{
cleanupstuff.dothecleann();
}
panicstateee.tickkk();
}
private void OnGUI()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
if (panicconfiggg.toastsss.Value)
{
if (panicstateee.onnn)
{
GUI.Label(new Rect(10f, 10f, 300f, 25f), "PANIC MODE ON");
}
if (Time.unscaledTime < toastyyy.untilll)
{
GUI.Label(new Rect(10f, 35f, 500f, 25f), toastyyy.texttt);
}
}
}
private static void newstuffhappe(Scene scenee, LoadSceneMode modeee)
{
panicstateee.turnofffff();
deadregistryy.forgetall();
deadscriptss.idsss.Clear();
cleanupstuff.forgetall();
unitlistttt.forgetitt();
}
private static void morefpscompatt(Harmony harmonyyy)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected O, but got Unknown
try
{
Type type = AccessTools.TypeByName("myfpsmodd.battleweightstuff");
if (type == null)
{
logzzz.LogInfo((object)"more fps not installed :(");
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "getmultiplierrr", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(multiplmorefps), "Postfix", (Type[])null, (Type[])null);
if (methodInfo == null || methodInfo2 == null)
{
logzzz.LogWarning((object)"could not find getmultiplierrr");
return;
}
harmonyyy.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
logzzz.LogInfo((object)"more fps connected :)");
}
catch (Exception ex)
{
logzzz.LogWarning((object)("mult h fail :( : " + ex.Message));
}
}
}
internal static class panicconfiggg
{
public static ConfigEntry<KeyCode> panickeyyy;
public static ConfigEntry<KeyCode> cleankeyyy;
public static ConfigEntry<float> autorevertsecsss;
public static ConfigEntry<bool> toastsss;
public static ConfigEntry<bool> boostmultiplierrr;
public static ConfigEntry<float> multiplieramounttt;
public static ConfigEntry<bool> physics30hzzz;
public static ConfigEntry<bool> renderlowwww;
public static ConfigEntry<bool> slowbarsss;
public static ConfigEntry<int> barrskipfrakmea;
public static ConfigEntry<bool> cullikkk;
public static ConfigEntry<float> culldistancee;
public static ConfigEntry<bool> freezecorpsesss;
public static ConfigEntry<bool> cleangcccc;
public static void bindddd(ConfigFile config)
{
panickeyyy = config.Bind<KeyCode>("Keys", "Panic mode key", (KeyCode)289, "toggles 'panic mode': makes a bunch of highly visible tweaks when your FPS is VERY low.");
cleankeyyy = config.Bind<KeyCode>("Keys", "Clean up key", (KeyCode)290, "one shot cleanup that can slightly improve FPS that does not make visual changes. don't spam!");
autorevertsecsss = config.Bind<float>("Panic", "AutoTurnoff Panic", 15f, "how long until panic mode automatically turns off in seconds. 0 means it stays on until you toggle it.");
toastsss = config.Bind<bool>("Panic", "show messages", true, "tell you when a mode is activated or settings change");
boostmultiplierrr = config.Bind<bool>("Panic", "boost fps throttles", true, "while panic is on, raises More FPS's throttle multiplier thingy. requires MORE FPS");
multiplieramounttt = config.Bind<float>("Panic", "Throttle multiplier", 4f, "multiplier used while panic is on. More FPS's normal max is 3.");
physics30hzzz = config.Bind<bool>("Panic", "Physics 30Hz", true, "drops the physics step to 30Hz while panic is on. the game already supports 30Hz so forces get adjusted.");
renderlowwww = config.Bind<bool>("Panic", "Lower graphics", true, "turns off shadows, halves LOD bias and limits pixel lights while panic is on");
slowbarsss = config.Bind<bool>("Panic", "Slower healthbars", true, "healthbars update less often while panic is on");
barrskipfrakmea = config.Bind<int>("Panic", "healthbar skip frames", 4, "how many frames a healthbar can skip between updating when panic is on. 4 means it updates once every 5 frames.");
cullikkk = config.Bind<bool>("Panic", "Disable far IK", true, "turns off final ik solvers on far away units and dead bodies while panic is on");
culldistancee = config.Bind<float>("Panic", "Far ik distance", 60f, "units that are too far (this distance) lose their ik in panic mode enabled.");
freezecorpsesss = config.Bind<bool>("Panic", "Freeze corpses", true, "dead bodies that stopped moving stop getting collisions or as many updates when panic is on.");
cleangcccc = config.Bind<bool>("Cleanup", "Free memory", true, "cleanup gets rid of unneeded stuff taking up assets. might cause a short hitch");
}
}
internal static class toastyyy
{
public static string texttt = "";
public static float untilll;
public static void sayyy(string whatttt)
{
texttt = whatttt;
untilll = Time.unscaledTime + 3f;
ManualLogSource logzzz = Plugin.logzzz;
if (logzzz != null)
{
logzzz.LogInfo((object)whatttt);
}
}
}
internal static class cameraaaaaa
{
private static Camera itiscached;
private static int cachedcamframezzz = -1;
public static Camera getmaincammm()
{
if (Time.frameCount != cachedcamframezzz)
{
itiscached = Camera.main;
cachedcamframezzz = Time.frameCount;
}
return itiscached;
}
}
internal static class unitlistttt
{
private static TeamSystem cachedteamsystemzzz;
public static void forgetitt()
{
cachedteamsystemzzz = null;
}
public static List<Unit> gimmeallunitsss()
{
if (cachedteamsystemzzz == null)
{
World active = World.Active;
if (active == null)
{
return null;
}
cachedteamsystemzzz = active.GetOrCreateManager<TeamSystem>();
}
return cachedteamsystemzzz.GetAllUnits();
}
}
internal static class deadregistryy
{
private const float reviveguardsecsss = 6f;
public static readonly List<Unit> listtt = new List<Unit>();
private static readonly Dictionary<int, float> deathtimesss = new Dictionary<int, float>();
public static void adddd(Unit deadguyyy)
{
if (!((Object)(object)deadguyyy == (Object)null))
{
int instanceID = ((Object)deadguyyy).GetInstanceID();
if (!deathtimesss.ContainsKey(instanceID))
{
deathtimesss[instanceID] = Time.time;
listtt.Add(deadguyyy);
}
}
}
public static bool stayeddeadddd(Unit uuu)
{
if (!deathtimesss.TryGetValue(((Object)uuu).GetInstanceID(), out var value))
{
return false;
}
return Time.time - value > 6f;
}
public static void backfromthedeadd(Unit uuu)
{
deathtimesss.Remove(((Object)uuu).GetInstanceID());
listtt.Remove(uuu);
}
public static void prunenullsss()
{
listtt.RemoveAll((Unit x) => (Object)(object)x == (Object)null);
}
public static void forgetall()
{
listtt.Clear();
deathtimesss.Clear();
}
}
internal static class deadscriptss
{
public static readonly HashSet<int> idsss = new HashSet<int>();
}
internal static class multiplmorefps
{
public static void Postfix(ref float __result)
{
if (panicstateee.onnn && panicconfiggg.boostmultiplierrr.Value)
{
__result = Mathf.Max(__result, panicconfiggg.multiplieramounttt.Value);
}
}
}
internal static class panicstateee
{
public static bool onnn;
private static float whenstartedd;
private static float nexttickkk;
private static bool changedphysicsss;
private static float oldfixeddeltaaa;
private static bool changedrenderrr;
private static ShadowQuality oldshadowsss;
private static float oldlodbiasss;
private static int oldpixellightsss;
private static float oldshadowdistancee;
private static ShadowResolution oldshadowresss;
private static int oldshadowcascadesss;
private static readonly Dictionary<Unit, SolverManager[]> solvercacheee = new Dictionary<Unit, SolverManager[]>();
private static readonly HashSet<SolverManager> turnedoffbyusss = new HashSet<SolverManager>();
private static readonly Dictionary<int, List<Rigidbody>> frozenbyunitttt = new Dictionary<int, List<Rigidbody>>();
public static void flipitt()
{
if (onnn)
{
turnofffff();
toastyyy.sayyy("panic fps mode turned off :)");
}
else
{
turnonnnn();
}
}
private static void turnonnnn()
{
//IL_0058: 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_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)
onnn = true;
whenstartedd = Time.unscaledTime;
nexttickkk = 0f;
if (panicconfiggg.physics30hzzz.Value && Time.fixedDeltaTime < 0.025f)
{
oldfixeddeltaaa = Time.fixedDeltaTime;
Time.fixedDeltaTime = 1f / 30f;
changedphysicsss = true;
}
if (panicconfiggg.renderlowwww.Value)
{
oldshadowsss = QualitySettings.shadows;
oldlodbiasss = QualitySettings.lodBias;
oldpixellightsss = QualitySettings.pixelLightCount;
oldshadowdistancee = QualitySettings.shadowDistance;
oldshadowresss = QualitySettings.shadowResolution;
oldshadowcascadesss = QualitySettings.shadowCascades;
QualitySettings.shadows = (ShadowQuality)0;
QualitySettings.lodBias = oldlodbiasss * 0.5f;
QualitySettings.pixelLightCount = Mathf.Min(oldpixellightsss, 1);
changedrenderrr = true;
}
Plugin.logzzz.LogInfo((object)"panic fps mode turned on :O");
}
public static void turnofffff()
{
//IL_002c: 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)
if (!onnn)
{
return;
}
onnn = false;
if (changedphysicsss)
{
Time.fixedDeltaTime = oldfixeddeltaaa;
changedphysicsss = false;
}
if (changedrenderrr)
{
QualitySettings.shadows = oldshadowsss;
QualitySettings.lodBias = oldlodbiasss;
QualitySettings.pixelLightCount = oldpixellightsss;
QualitySettings.shadowDistance = oldshadowdistancee;
QualitySettings.shadowResolution = oldshadowresss;
QualitySettings.shadowCascades = oldshadowcascadesss;
changedrenderrr = false;
}
foreach (SolverManager item in turnedoffbyusss)
{
if ((Object)(object)item != (Object)null)
{
((Behaviour)item).enabled = true;
}
}
turnedoffbyusss.Clear();
solvercacheee.Clear();
foreach (KeyValuePair<int, List<Rigidbody>> item2 in frozenbyunitttt)
{
thawrigsss(item2.Value);
}
frozenbyunitttt.Clear();
}
private static void thawrigsss(List<Rigidbody> rigzzz)
{
for (int i = 0; i < rigzzz.Count; i++)
{
Rigidbody val = rigzzz[i];
if (!((Object)(object)val == (Object)null))
{
val.isKinematic = false;
val.detectCollisions = true;
}
}
}
public static void thawunittt(Unit uuu)
{
if (frozenbyunitttt.TryGetValue(((Object)uuu).GetInstanceID(), out var value))
{
thawrigsss(value);
frozenbyunitttt.Remove(((Object)uuu).GetInstanceID());
}
}
public static void tickkk()
{
if (onnn)
{
if (panicconfiggg.autorevertsecsss.Value > 0f && Time.unscaledTime - whenstartedd > panicconfiggg.autorevertsecsss.Value)
{
turnofffff();
toastyyy.sayyy("panic mode auto-turned off. you can disable in config!");
}
else if (!(Time.unscaledTime < nexttickkk))
{
nexttickkk = Time.unscaledTime + 0.5f;
doculllling();
dofreezzzze();
}
}
}
private static void doculllling()
{
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
if (!panicconfiggg.cullikkk.Value)
{
return;
}
Camera val = cameraaaaaa.getmaincammm();
if ((Object)(object)val == (Object)null)
{
return;
}
List<Unit> list = unitlistttt.gimmeallunitsss();
if (list == null)
{
return;
}
float value = panicconfiggg.culldistancee.Value;
float num = value * 0.8f;
for (int i = 0; i < list.Count; i++)
{
Unit val2 = list[i];
if ((Object)(object)val2 == (Object)null || (Object)(object)val2.data == (Object)null || (Object)(object)val2.data.mainRig == (Object)null)
{
continue;
}
if (!solvercacheee.TryGetValue(val2, out var value2))
{
value2 = ((Component)val2).GetComponentsInChildren<SolverManager>(true);
solvercacheee[val2] = value2;
}
float num2 = Vector3.Distance(((Component)val).transform.position, val2.data.mainRig.position);
bool dead = val2.data.Dead;
bool flag = dead || num2 > value;
bool flag2 = !dead && num2 < num;
foreach (SolverManager val3 in value2)
{
if (!((Object)(object)val3 == (Object)null))
{
if (flag && ((Behaviour)val3).enabled)
{
((Behaviour)val3).enabled = false;
turnedoffbyusss.Add(val3);
}
else if (flag2 && turnedoffbyusss.Contains(val3))
{
((Behaviour)val3).enabled = true;
turnedoffbyusss.Remove(val3);
}
}
}
}
}
private static void dofreezzzze()
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
if (!panicconfiggg.freezecorpsesss.Value)
{
return;
}
deadregistryy.prunenullsss();
List<Unit> listtt = deadregistryy.listtt;
for (int i = 0; i < listtt.Count; i++)
{
Unit val = listtt[i];
if ((Object)(object)val.data == (Object)null || !val.data.Dead || (Object)(object)val.data.mainRig == (Object)null)
{
continue;
}
int instanceID = ((Object)val).GetInstanceID();
if (frozenbyunitttt.ContainsKey(instanceID) || !deadregistryy.stayeddeadddd(val))
{
continue;
}
Vector3 velocity = val.data.mainRig.velocity;
if (((Vector3)(ref velocity)).sqrMagnitude > 0.25f || (Object)(object)val.data.allRigs == (Object)null)
{
continue;
}
Rigidbody[] allRigs = val.data.allRigs.AllRigs;
if (allRigs == null)
{
continue;
}
List<Rigidbody> list = new List<Rigidbody>();
foreach (Rigidbody val2 in allRigs)
{
if (!((Object)(object)val2 == (Object)null) && !val2.isKinematic)
{
val2.isKinematic = true;
val2.detectCollisions = false;
list.Add(val2);
}
}
frozenbyunitttt[instanceID] = list;
}
}
}
internal static class cleanupstuff
{
private static float nextokkkk;
private static readonly Dictionary<int, List<Behaviour>> turnedoffbyuss = new Dictionary<int, List<Behaviour>>();
public static void forgetall()
{
turnedoffbyuss.Clear();
}
public static void undounittt(Unit uuu)
{
if (!turnedoffbyuss.TryGetValue(((Object)uuu).GetInstanceID(), out var value))
{
return;
}
for (int i = 0; i < value.Count; i++)
{
Behaviour val = value[i];
if (!((Object)(object)val == (Object)null))
{
deadscriptss.idsss.Remove(((Object)val).GetInstanceID());
val.enabled = true;
}
}
turnedoffbyuss.Remove(((Object)uuu).GetInstanceID());
}
public static void dothecleann()
{
//IL_009b: 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 (Time.unscaledTime < nextokkkk)
{
return;
}
nextokkkk = Time.unscaledTime + 2f;
deadregistryy.prunenullsss();
List<Unit> listtt = deadregistryy.listtt;
for (int i = 0; i < listtt.Count; i++)
{
Unit val = listtt[i];
if ((Object)(object)val.data == (Object)null || !val.data.Dead || (Object)(object)val.data.mainRig == (Object)null)
{
continue;
}
int instanceID = ((Object)val).GetInstanceID();
if (turnedoffbyuss.ContainsKey(instanceID) || !deadregistryy.stayeddeadddd(val))
{
continue;
}
Vector3 velocity = val.data.mainRig.velocity;
if (((Vector3)(ref velocity)).sqrMagnitude > 0.25f)
{
continue;
}
if ((Object)(object)val.data.allRigs != (Object)null && val.data.allRigs.AllRigs != null)
{
Rigidbody[] allRigs = val.data.allRigs.AllRigs;
foreach (Rigidbody val2 in allRigs)
{
if (!((Object)(object)val2 == (Object)null) && !val2.isKinematic)
{
val2.sleepThreshold = Mathf.Max(val2.sleepThreshold, 0.5f);
val2.Sleep();
}
}
}
List<Behaviour> list = new List<Behaviour>();
AnimationForce[] componentsInChildren = ((Component)val).GetComponentsInChildren<AnimationForce>(true);
for (int k = 0; k < componentsInChildren.Length; k++)
{
if (!((Object)(object)componentsInChildren[k] == (Object)null))
{
deadscriptss.idsss.Add(((Object)componentsInChildren[k]).GetInstanceID());
((Behaviour)componentsInChildren[k]).enabled = false;
list.Add((Behaviour)(object)componentsInChildren[k]);
}
}
AnimationTorque[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<AnimationTorque>(true);
for (int l = 0; l < componentsInChildren2.Length; l++)
{
if (!((Object)(object)componentsInChildren2[l] == (Object)null))
{
deadscriptss.idsss.Add(((Object)componentsInChildren2[l]).GetInstanceID());
((Behaviour)componentsInChildren2[l]).enabled = false;
list.Add((Behaviour)(object)componentsInChildren2[l]);
}
}
IkLeg[] componentsInChildren3 = ((Component)val).GetComponentsInChildren<IkLeg>(true);
for (int m = 0; m < componentsInChildren3.Length; m++)
{
if (!((Object)(object)componentsInChildren3[m] == (Object)null))
{
((Behaviour)componentsInChildren3[m]).enabled = false;
list.Add((Behaviour)(object)componentsInChildren3[m]);
}
}
turnedoffbyuss[instanceID] = list;
}
if (panicconfiggg.cleangcccc.Value)
{
GC.Collect();
Resources.UnloadUnusedAssets();
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class deadsetterrr
{
private static void Postfix(DataHandler __instance, bool value)
{
Unit componentInParent = ((Component)__instance).GetComponentInParent<Unit>();
if (!((Object)(object)componentInParent == (Object)null))
{
if (value)
{
deadregistryy.adddd(componentInParent);
return;
}
deadregistryy.backfromthedeadd(componentInParent);
cleanupstuff.undounittt(componentInParent);
panicstateee.thawunittt(componentInParent);
}
}
}
[HarmonyPatch(typeof(AnimationForce), "FixedUpdate")]
internal static class deadforceskipppp
{
private static bool Prefix(AnimationForce __instance)
{
if (deadscriptss.idsss.Count == 0)
{
return true;
}
return !deadscriptss.idsss.Contains(((Object)__instance).GetInstanceID());
}
}
[HarmonyPatch(typeof(AnimationTorque), "FixedUpdate")]
internal static class deadtorqueskipppp
{
private static bool Prefix(AnimationTorque __instance)
{
if (deadscriptss.idsss.Count == 0)
{
return true;
}
return !deadscriptss.idsss.Contains(((Object)__instance).GetInstanceID());
}
}
[HarmonyPatch(typeof(TABCUnitUI), "LateUpdate")]
public static class barsslowwwww
{
private sealed class excusecounter
{
public int lazyframe;
}
private static readonly ConditionalWeakTable<TABCUnitUI, excusecounter> whosloggingthisss = new ConditionalWeakTable<TABCUnitUI, excusecounter>();
private static bool Prefix(TABCUnitUI __instance)
{
if (!panicstateee.onnn)
{
return true;
}
if (!panicconfiggg.slowbarsss.Value)
{
return true;
}
excusecounter orCreateValue = whosloggingthisss.GetOrCreateValue(__instance);
orCreateValue.lazyframe++;
if (orCreateValue.lazyframe <= panicconfiggg.barrskipfrakmea.Value)
{
return false;
}
orCreateValue.lazyframe = 0;
return true;
}
}