Decompiled source of LowEndBoost v1.1.0

LowEndBoost.dll

Decompiled 4 hours 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 Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("LowEndBoost")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LowEndBoost")]
[assembly: AssemblyTitle("LowEndBoost")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 LowEndBoost
{
	internal class Item
	{
		public string Name;

		public Func<string> Val;

		public Action<int> Change;

		public string Result;
	}
	[BepInPlugin("tractionctr.lowendboost", "LowEndBoost", "1.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static Plugin I;

		private ConfigEntry<int> renderScale;

		private ConfigEntry<int> fpsCap;

		private ConfigEntry<int> farClip;

		private ConfigEntry<int> shadowDist;

		private ConfigEntry<int> textureLevel;

		private ConfigEntry<int> renderWidth;

		private ConfigEntry<int> treeDist;

		private ConfigEntry<int> maxLod;

		private ConfigEntry<float> lodBias;

		private ConfigEntry<bool> noShadows;

		private ConfigEntry<bool> noRendererShadows;

		private ConfigEntry<bool> showOverlay;

		private ConfigEntry<bool> noLocalVolumes;

		private ConfigEntry<bool> removeFoliage;

		private ConfigEntry<bool> noParticles;

		private ConfigEntry<bool> noDecals;

		private ConfigEntry<bool> noProbes;

		private ConfigEntry<bool> animCull;

		private ConfigEntry<bool> noCheapFx;

		private ConfigEntry<bool> noSsFx;

		private ConfigEntry<bool> noFog;

		private ConfigEntry<bool> smoothLoad;

		private ConfigEntry<bool> highPrio;

		private float timer;

		private float fps;

		private float fpsTimer;

		private float avgFrames;

		private float avgTime;

		private float lastAvg;

		private int frames;

		private int lightsFixed;

		private bool resApplied;

		private bool menuOpen;

		private bool origRealtimeProbes;

		private int sel;

		private int lastVolKey;

		private GUIStyle style;

		private GUIStyle itemStyle;

		private GUIStyle selStyle;

		private readonly List<Item> items = new List<Item>();

		private readonly List<Action> undoLights = new List<Action>();

		private readonly List<Action> undoRend = new List<Action>();

		private readonly List<Action> undoFoliage = new List<Action>();

		private readonly List<Action> undoParticles = new List<Action>();

		private readonly List<Action> undoProbes = new List<Action>();

		private readonly List<Action> undoAnim = new List<Action>();

		private readonly List<Action> undoDecals = new List<Action>();

		private readonly List<Action> undoVol = new List<Action>();

		private readonly HashSet<Terrain> terrainDone = new HashSet<Terrain>();

		private readonly Dictionary<Camera, float> origFar = new Dictionary<Camera, float>();

		private readonly Dictionary<RenderTexture, int[]> rtOrig = new Dictionary<RenderTexture, int[]>();

		private string lastRtMsg = "";

		private readonly List<Action> undoPost = new List<Action>();

		private int lastPostKey;

		private string lastPostMsg = "";

		private bool smoothOn;

		private bool lastPrio;

		private float origUpload;

		private int origBuf;

		private ThreadPriority origBg;

		private static readonly HashSet<string> cheapFx = new HashSet<string> { "Bloom", "DepthOfField", "MotionBlur", "FilmGrain", "ChromaticAberration", "LensDistortion", "PaniniProjection", "Vignette" };

		private static readonly HashSet<string> ssFx = new HashSet<string> { "ScreenSpaceReflection", "ScreenSpaceRefraction", "ScreenSpaceAmbientOcclusion", "AmbientOcclusion", "GlobalIllumination", "ContactShadows", "MicroShadowing", "ScreenSpaceLensFlare", "VolumetricClouds" };

		private bool benching;

		private int phase;

		private int dirB;

		private float phaseStart;

		private Item bItem;

		private readonly List<float> samples = new List<float>();

		private readonly float[] med = new float[4];

		private void Awake()
		{
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Expected O, but got Unknown
			I = this;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			origRealtimeProbes = QualitySettings.realtimeReflectionProbes;
			fpsCap = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FpsCap", 144, "Target FPS (0 = uncapped)");
			farClip = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FarClip", 80, "Max camera view distance");
			shadowDist = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ShadowDistance", 0, "Shadow distance (0 = off)");
			lodBias = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LodBias", 0.1f, "Lower = simpler models sooner");
			textureLevel = ((BaseUnityPlugin)this).Config.Bind<int>("General", "TextureLevel", 0, "0 = full, 1 = half, 2 = quarter, 3 = eighth");
			renderWidth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "RenderWidth", 0, "OLD method: shrinks the whole screen incl. HUD. 0 = off");
			renderScale = ((BaseUnityPlugin)this).Config.Bind<int>("General", "RenderScale", 50, "3D world resolution in percent (HUD stays sharp). 100 = native");
			noShadows = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableLightShadows", true, "Turn off shadows on all lights");
			noRendererShadows = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableRendererShadowCasting", true, "Objects stop casting shadows");
			removeFoliage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveFoliage", true, "Stop rendering foliage");
			treeDist = ((BaseUnityPlugin)this).Config.Bind<int>("General", "TreeDistance", 0, "Terrain tree draw distance");
			noParticles = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableParticles", true, "Turn off particle effects");
			noDecals = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableDecals", true, "Turn off decal projectors");
			noProbes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableReflectionProbes", true, "Turn off reflection probes");
			animCull = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CullOffscreenAnimation", false, "Stop animating off-screen objects");
			maxLod = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaximumLodLevel", 0, "Skip the most detailed model versions");
			noLocalVolumes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableLocalVolumes", false, "Turn off local fog/effect volumes");
			noCheapFx = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableCheapPostEffects", false, "Turn off bloom, depth of field, motion blur, grain, chromatic aberration, vignette");
			noSsFx = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableScreenSpaceEffects", false, "Turn off ambient occlusion, screen-space reflections/GI, contact shadows");
			noFog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableFog", false, "Turn off the fog effect (changes the look)");
			smoothLoad = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SmoothLoading", true, "Gentler texture upload and loading priority to reduce load spikes");
			highPrio = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HighProcessPriority", true, "Run the game at high CPU priority");
			showOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowOverlay", true, "Show on-screen status text");
			BuildMenu();
			GameObject val = new GameObject("LowEndBoostRunner")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<Runner>();
			ApplyGlobal();
			SceneManager.sceneLoaded += delegate
			{
				ApplyGlobal();
				timer = 3f;
			};
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LowEndBoost loaded");
		}

		private void AddToggle(string n, ConfigEntry<bool> e)
		{
			items.Add(new Item
			{
				Name = n,
				Val = () => (!e.Value) ? "off" : "ON",
				Change = delegate
				{
					e.Value = !e.Value;
				}
			});
		}

		private void AddInt(string n, ConfigEntry<int> e, int step, int min, int max)
		{
			items.Add(new Item
			{
				Name = n,
				Val = () => e.Value.ToString(),
				Change = delegate(int d)
				{
					e.Value = Mathf.Clamp(e.Value + d * step, min, max);
				}
			});
		}

		private void BuildMenu()
		{
			items.Add(new Item
			{
				Name = "3D render scale %",
				Val = () => renderScale.Value.ToString(),
				Change = delegate(int d)
				{
					renderScale.Value = Mathf.Clamp(renderScale.Value + d * 5, 25, 100);
					ApplyRtScale();
				}
			});
			AddInt("Texture level (0=full)", textureLevel, 1, 0, 3);
			AddInt("Far clip", farClip, 10, 20, 300);
			items.Add(new Item
			{
				Name = "LOD bias",
				Val = () => lodBias.Value.ToString("0.0"),
				Change = delegate(int d)
				{
					lodBias.Value = Mathf.Clamp(Mathf.Round((lodBias.Value + (float)d * 0.1f) * 10f) / 10f, 0.1f, 2f);
				}
			});
			AddInt("Max LOD level", maxLod, 1, 0, 3);
			AddInt("FPS cap", fpsCap, 10, 10, 144);
			AddToggle("No light shadows", noShadows);
			AddToggle("No object shadows", noRendererShadows);
			AddToggle("Remove foliage", removeFoliage);
			AddInt("Tree distance", treeDist, 10, 0, 200);
			AddToggle("No particles", noParticles);
			AddToggle("No decals", noDecals);
			AddToggle("No reflection probes", noProbes);
			AddToggle("Cull offscreen animation", animCull);
			AddToggle("No local volumes", noLocalVolumes);
			AddToggle("No cheap post effects (bloom/DoF/blur)", noCheapFx);
			AddToggle("No screen-space effects (AO/SSR)", noSsFx);
			AddToggle("No fog", noFog);
			AddToggle("Smooth loading", smoothLoad);
			AddToggle("High process priority", highPrio);
		}

		private void ApplyGlobal()
		{
			QualitySettings.vSyncCount = 0;
			Application.targetFrameRate = fpsCap.Value;
			QualitySettings.lodBias = lodBias.Value;
			QualitySettings.shadowDistance = shadowDist.Value;
			QualitySettings.pixelLightCount = 1;
			QualitySettings.skinWeights = (SkinWeights)2;
			QualitySettings.anisotropicFiltering = (AnisotropicFiltering)0;
			QualitySettings.billboardsFaceCameraPosition = false;
			QualitySettings.masterTextureLimit = textureLevel.Value;
			QualitySettings.maximumLODLevel = maxLod.Value;
			QualitySettings.realtimeReflectionProbes = !noProbes.Value && origRealtimeProbes;
		}

		private void ApplyRtScale()
		{
			//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)
			try
			{
				string text = "";
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				int num = ((name == "MainMenu" || name.StartsWith("InitScene")) ? 100 : renderScale.Value);
				Camera[] allCameras = Camera.allCameras;
				foreach (Camera val in allCameras)
				{
					RenderTexture targetTexture = val.targetTexture;
					if ((Object)(object)targetTexture == (Object)null)
					{
						continue;
					}
					if (!rtOrig.ContainsKey(targetTexture))
					{
						rtOrig[targetTexture] = new int[2]
						{
							((Texture)targetTexture).width,
							((Texture)targetTexture).height
						};
					}
					int num2 = rtOrig[targetTexture][0];
					int num3 = rtOrig[targetTexture][1];
					if (num2 >= 500)
					{
						int num4 = Mathf.Max(64, (num2 * num / 100) & -2);
						int num5 = Mathf.Max(64, (num3 * num / 100) & -2);
						if (((Texture)targetTexture).width != num4 || ((Texture)targetTexture).height != num5)
						{
							targetTexture.Release();
							((Texture)targetTexture).width = num4;
							((Texture)targetTexture).height = num5;
							targetTexture.Create();
						}
						text = text + ((Object)val).name + " " + num2 + "x" + num3 + " -> " + num4 + "x" + num5 + "; ";
					}
				}
				if (text != lastRtMsg)
				{
					lastRtMsg = text;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("rt scale: " + ((text == "") ? "no big render texture found" : text)));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("rt scale EXCEPTION " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void Undo(List<Action> l)
		{
			foreach (Action item in l)
			{
				try
				{
					item();
				}
				catch
				{
				}
			}
			l.Clear();
		}

		private static Type FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type type = null;
				try
				{
					type = assembly.GetType(fullName, throwOnError: false);
				}
				catch
				{
				}
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		private void ApplyPostFx()
		{
			int num = (int)((noCheapFx.Value ? 1u : 0u) | (uint)(noSsFx.Value ? 2 : 0)) | (noFog.Value ? 4 : 0);
			if (num != lastPostKey)
			{
				Undo(undoPost);
				lastPostKey = num;
			}
			if (num == 0)
			{
				return;
			}
			try
			{
				Type type = FindType("UnityEngine.Rendering.Volume");
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"postfx: Volume type not found");
					return;
				}
				PropertyInfo property = type.GetProperty("sharedProfile");
				string text = "";
				Object[] array = Object.FindObjectsOfType(type);
				foreach (Object obj in array)
				{
					object value = property.GetValue(obj, null);
					if (value == null)
					{
						continue;
					}
					FieldInfo field = value.GetType().GetField("components");
					IList list = ((field != null) ? (field.GetValue(value) as IList) : null);
					if (list == null)
					{
						continue;
					}
					foreach (object item in list)
					{
						if (item == null)
						{
							continue;
						}
						Type type2 = item.GetType();
						string name = type2.Name;
						if (((num & 1) == 0 || !cheapFx.Contains(name)) && ((num & 2) == 0 || !ssFx.Contains(name)) && ((num & 4) == 0 || !(name == "Fog")))
						{
							continue;
						}
						FieldInfo field2 = type2.GetField("active");
						if (!(field2 == null) && (bool)field2.GetValue(item))
						{
							object c2 = item;
							FieldInfo af2 = field2;
							undoPost.Add(delegate
							{
								af2.SetValue(c2, true);
							});
							field2.SetValue(item, false);
							text = text + name + " ";
						}
					}
				}
				if (text != "" && text != lastPostMsg)
				{
					lastPostMsg = text;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("postfx disabled: " + text));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("postfx EXCEPTION " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void ApplyMisc()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (smoothLoad.Value && !smoothOn)
			{
				origUpload = QualitySettings.asyncUploadTimeSlice;
				origBuf = QualitySettings.asyncUploadBufferSize;
				origBg = Application.backgroundLoadingPriority;
				QualitySettings.asyncUploadTimeSlice = 1;
				QualitySettings.asyncUploadBufferSize = 16;
				Application.backgroundLoadingPriority = (ThreadPriority)0;
				smoothOn = true;
			}
			else if (!smoothLoad.Value && smoothOn)
			{
				QualitySettings.asyncUploadTimeSlice = (int)origUpload;
				QualitySettings.asyncUploadBufferSize = origBuf;
				Application.backgroundLoadingPriority = origBg;
				smoothOn = false;
			}
			if (highPrio.Value != lastPrio)
			{
				lastPrio = highPrio.Value;
				try
				{
					Process.GetCurrentProcess().PriorityClass = (highPrio.Value ? ProcessPriorityClass.High : ProcessPriorityClass.Normal);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("priority: " + ex.Message));
				}
			}
		}

		private void Scan()
		{
			//IL_000c: 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)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Invalid comparison between Unknown and I4
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Invalid comparison between Unknown and I4
			//IL_05ca: Unknown result type (might be due to invalid IL or missing references)
			ApplyRtScale();
			ApplyGlobal();
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			bool flag = name == "MainMenu" || name.StartsWith("InitScene");
			if (!flag)
			{
				Camera[] allCameras = Camera.allCameras;
				foreach (Camera val in allCameras)
				{
					if (!origFar.ContainsKey(val))
					{
						origFar[val] = val.farClipPlane;
					}
					float num = Mathf.Min(origFar[val], (float)farClip.Value);
					if (Mathf.Abs(val.farClipPlane - num) > 0.01f)
					{
						val.farClipPlane = num;
					}
				}
			}
			if (!flag && removeFoliage.Value)
			{
				int num2 = LayerMask.NameToLayer("Foliage");
				int bit = ((num2 >= 0) ? (1 << num2) : 0);
				Camera[] allCameras = Camera.allCameras;
				foreach (Camera val2 in allCameras)
				{
					if (bit == 0 || (val2.cullingMask & bit) == 0)
					{
						continue;
					}
					Camera c = val2;
					undoFoliage.Add(delegate
					{
						if ((Object)(object)c != (Object)null)
						{
							Camera obj2 = c;
							obj2.cullingMask |= bit;
						}
					});
					val2.cullingMask &= ~bit;
				}
				Terrain[] activeTerrains = Terrain.activeTerrains;
				foreach (Terrain val3 in activeTerrains)
				{
					if (terrainDone.Add(val3))
					{
						Terrain tt = val3;
						float d0 = val3.detailObjectDistance;
						float t0 = val3.treeDistance;
						float b0 = val3.treeBillboardDistance;
						int l0 = val3.treeMaximumFullLODCount;
						undoFoliage.Add(delegate
						{
							if ((Object)(object)tt != (Object)null)
							{
								tt.detailObjectDistance = d0;
								tt.treeDistance = t0;
								tt.treeBillboardDistance = b0;
								tt.treeMaximumFullLODCount = l0;
							}
						});
					}
					val3.detailObjectDistance = 0f;
					val3.treeDistance = treeDist.Value;
					val3.treeBillboardDistance = (float)treeDist.Value * 0.5f;
					val3.treeMaximumFullLODCount = 0;
				}
			}
			else if (undoFoliage.Count > 0)
			{
				Undo(undoFoliage);
				terrainDone.Clear();
			}
			lightsFixed = 0;
			if (noShadows.Value)
			{
				Light[] array = Object.FindObjectsOfType<Light>();
				foreach (Light val4 in array)
				{
					if ((int)val4.shadows == 0)
					{
						continue;
					}
					Light o = val4;
					LightShadows orig = val4.shadows;
					undoLights.Add(delegate
					{
						//IL_0015: Unknown result type (might be due to invalid IL or missing references)
						if ((Object)(object)o != (Object)null)
						{
							o.shadows = orig;
						}
					});
					val4.shadows = (LightShadows)0;
					lightsFixed++;
				}
			}
			else if (undoLights.Count > 0)
			{
				Undo(undoLights);
			}
			if (noRendererShadows.Value)
			{
				Renderer[] array2 = Object.FindObjectsOfType<Renderer>();
				foreach (Renderer val5 in array2)
				{
					if ((int)val5.shadowCastingMode != 1 && (int)val5.shadowCastingMode != 2)
					{
						continue;
					}
					Renderer o2 = val5;
					ShadowCastingMode orig2 = val5.shadowCastingMode;
					undoRend.Add(delegate
					{
						//IL_0015: Unknown result type (might be due to invalid IL or missing references)
						if ((Object)(object)o2 != (Object)null)
						{
							o2.shadowCastingMode = orig2;
						}
					});
					val5.shadowCastingMode = (ShadowCastingMode)0;
				}
			}
			else if (undoRend.Count > 0)
			{
				Undo(undoRend);
			}
			int num3 = (noLocalVolumes.Value ? 1 : 0);
			if (num3 != lastVolKey)
			{
				Undo(undoVol);
				lastVolKey = num3;
			}
			if (num3 != 0)
			{
				Type type = Type.GetType("UnityEngine.Rendering.Volume, Unity.RenderPipelines.Core.Runtime");
				if (type != null)
				{
					PropertyInfo property = type.GetProperty("isGlobal");
					Object[] array3 = Object.FindObjectsOfType(type);
					foreach (Object val6 in array3)
					{
						Behaviour val7 = (Behaviour)(object)((val6 is Behaviour) ? val6 : null);
						if ((Object)(object)val7 == (Object)null || !val7.enabled || (bool)property.GetValue(val6, null))
						{
							continue;
						}
						Behaviour bb = val7;
						undoVol.Add(delegate
						{
							if ((Object)(object)bb != (Object)null)
							{
								bb.enabled = true;
							}
						});
						val7.enabled = false;
					}
				}
			}
			ApplyPostFx();
			ApplyMisc();
			if (noParticles.Value)
			{
				ParticleSystemRenderer[] array4 = Object.FindObjectsOfType<ParticleSystemRenderer>();
				foreach (ParticleSystemRenderer val8 in array4)
				{
					if (!((Renderer)val8).enabled)
					{
						continue;
					}
					ParticleSystemRenderer o3 = val8;
					undoParticles.Add(delegate
					{
						if ((Object)(object)o3 != (Object)null)
						{
							((Renderer)o3).enabled = true;
						}
					});
					((Renderer)val8).enabled = false;
				}
			}
			else if (undoParticles.Count > 0)
			{
				Undo(undoParticles);
			}
			if (noProbes.Value)
			{
				ReflectionProbe[] array5 = Object.FindObjectsOfType<ReflectionProbe>();
				foreach (ReflectionProbe val9 in array5)
				{
					if (!((Behaviour)val9).enabled)
					{
						continue;
					}
					ReflectionProbe o4 = val9;
					undoProbes.Add(delegate
					{
						if ((Object)(object)o4 != (Object)null)
						{
							((Behaviour)o4).enabled = true;
						}
					});
					((Behaviour)val9).enabled = false;
				}
			}
			else if (undoProbes.Count > 0)
			{
				Undo(undoProbes);
			}
			if (animCull.Value)
			{
				Animator[] array6 = Object.FindObjectsOfType<Animator>();
				foreach (Animator val10 in array6)
				{
					if ((int)val10.cullingMode != 0)
					{
						continue;
					}
					Animator o5 = val10;
					undoAnim.Add(delegate
					{
						if ((Object)(object)o5 != (Object)null)
						{
							o5.cullingMode = (AnimatorCullingMode)0;
						}
					});
					val10.cullingMode = (AnimatorCullingMode)1;
				}
			}
			else if (undoAnim.Count > 0)
			{
				Undo(undoAnim);
			}
			if (noDecals.Value)
			{
				Type type2 = Type.GetType("UnityEngine.Rendering.HighDefinition.DecalProjector, Unity.RenderPipelines.HighDefinition.Runtime");
				if (!(type2 != null))
				{
					return;
				}
				Object[] array3 = Object.FindObjectsOfType(type2);
				foreach (Object obj in array3)
				{
					Behaviour val11 = (Behaviour)(object)((obj is Behaviour) ? obj : null);
					if (!((Object)(object)val11 != (Object)null) || !val11.enabled)
					{
						continue;
					}
					Behaviour bb2 = val11;
					undoDecals.Add(delegate
					{
						if ((Object)(object)bb2 != (Object)null)
						{
							bb2.enabled = true;
						}
					});
					val11.enabled = false;
				}
			}
			else if (undoDecals.Count > 0)
			{
				Undo(undoDecals);
			}
		}

		private float MedianFps()
		{
			if (samples.Count == 0)
			{
				return 0f;
			}
			samples.Sort();
			float num = samples[samples.Count / 2];
			if (!(num > 0f))
			{
				return 0f;
			}
			return 1f / num;
		}

		private void ApplyNow()
		{
			ApplyGlobal();
			timer = 0f;
		}

		private void StartBench()
		{
			bItem = items[sel];
			string text = bItem.Val();
			bItem.Change(1);
			if (bItem.Val() == text)
			{
				dirB = -1;
			}
			else
			{
				dirB = 1;
				bItem.Change(-1);
			}
			phase = 0;
			samples.Clear();
			phaseStart = Time.unscaledTime;
			benching = true;
			bItem.Result = "benchmarking...";
			ApplyNow();
		}

		private void CancelBench()
		{
			if (benching)
			{
				if (phase == 1 || phase == 3)
				{
					bItem.Change(-dirB);
				}
				benching = false;
				bItem.Result = "cancelled";
				ApplyNow();
			}
		}

		private void BenchStep()
		{
			float num = Time.unscaledTime - phaseStart;
			if (num >= 3f)
			{
				samples.Add(Time.unscaledDeltaTime);
			}
			if (num < 8f)
			{
				return;
			}
			med[phase] = MedianFps();
			samples.Clear();
			phase++;
			if (phase < 4)
			{
				if (phase == 1 || phase == 3)
				{
					bItem.Change(dirB);
				}
				else
				{
					bItem.Change(-dirB);
				}
				ApplyNow();
				phaseStart = Time.unscaledTime;
				return;
			}
			bItem.Change(-dirB);
			ApplyNow();
			benching = false;
			float num2 = (med[0] + med[2]) / 2f;
			float num3 = (med[1] + med[3]) / 2f;
			float num4 = num3 - num2;
			bItem.Result = ((num4 >= 0f) ? "+" : "") + num4.ToString("0.0") + " fps (off " + num2.ToString("0.0") + " > on " + num3.ToString("0.0") + ")";
			((BaseUnityPlugin)this).Logger.LogInfo((object)("bench: " + bItem.Name + " " + bItem.Result));
		}

		internal void Tick()
		{
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			frames++;
			fpsTimer += Time.unscaledDeltaTime;
			if (fpsTimer >= 0.5f)
			{
				fps = (float)frames / fpsTimer;
				frames = 0;
				fpsTimer = 0f;
			}
			avgFrames += 1f;
			avgTime += Time.unscaledDeltaTime;
			if (avgTime >= 4f)
			{
				lastAvg = avgFrames / avgTime;
				avgFrames = 0f;
				avgTime = 0f;
			}
			if (benching)
			{
				BenchStep();
			}
			timer -= Time.unscaledDeltaTime;
			if (timer > 0f)
			{
				return;
			}
			timer = 30f;
			if (!resApplied)
			{
				resApplied = true;
				if (renderWidth.Value > 0)
				{
					int value = renderWidth.Value;
					Screen.SetResolution(value, value * 9 / 16, Screen.fullScreenMode);
				}
				else if (Screen.width != Display.main.systemWidth)
				{
					Screen.SetResolution(Display.main.systemWidth, Display.main.systemHeight, Screen.fullScreenMode);
				}
			}
			Scan();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("tick: tex=" + QualitySettings.masterTextureLimit + " fps=" + fps.ToString("0")));
		}

		internal void Draw()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_01fa: 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_0023: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Invalid comparison between Unknown and I4
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Invalid comparison between Unknown and I4
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Invalid comparison between Unknown and I4
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Invalid comparison between Unknown and I4
			Event current = Event.current;
			if (current != null && (int)current.type == 4)
			{
				if ((int)current.keyCode == 289)
				{
					menuOpen = !menuOpen;
					if (!menuOpen)
					{
						((BaseUnityPlugin)this).Config.Save();
					}
					current.Use();
				}
				else if (menuOpen)
				{
					int num = 0;
					if ((int)current.keyCode == 273)
					{
						sel = (sel + items.Count - 1) % items.Count;
						current.Use();
					}
					else if ((int)current.keyCode == 274)
					{
						sel = (sel + 1) % items.Count;
						current.Use();
					}
					else if ((int)current.keyCode == 98)
					{
						if (benching)
						{
							CancelBench();
						}
						else
						{
							StartBench();
						}
						current.Use();
					}
					else if ((int)current.keyCode == 276)
					{
						num = -1;
					}
					else if ((int)current.keyCode == 275 || (int)current.keyCode == 13)
					{
						num = 1;
					}
					if (num != 0 && !benching)
					{
						items[sel].Change(num);
						items[sel].Result = null;
						ApplyNow();
						current.Use();
					}
				}
			}
			if (style == null)
			{
				style = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				style.normal.textColor = Color.green;
				itemStyle = new GUIStyle(GUI.skin.label);
				itemStyle.normal.textColor = Color.white;
				selStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				selStyle.normal.textColor = Color.yellow;
			}
			int fontSize = Mathf.Max(8, Screen.width / 140);
			if (showOverlay.Value || benching)
			{
				style.fontSize = fontSize;
				string text = (benching ? ("BENCHMARK " + (phase + 1) + "/4 (" + ((phase % 2 == 0) ? "off" : "on") + ") - " + bItem.Name + " - stand still") : ("LowEndBoost | FPS " + fps.ToString("0") + " (avg " + lastAvg.ToString("0.0") + ") | F8 = settings"));
				GUI.Label(new Rect(6f, 4f, (float)(Screen.width - 12), (float)(Screen.height / 12)), text, style);
			}
			if (menuOpen)
			{
				int num2 = Mathf.Max(10, Screen.width / 90);
				itemStyle.fontSize = num2;
				selStyle.fontSize = num2;
				float num3 = (float)num2 * 1.7f;
				float num4 = (float)Screen.height / 12f;
				GUI.Box(new Rect(6f, num4, (float)Screen.width * 0.6f, num3 * (float)(items.Count + 2)), "");
				GUI.Label(new Rect(14f, num4 + 2f, (float)Screen.width * 0.6f, num3), "Up/Down pick | Left/Right change | B = auto-test selected setting (32s, stand still) | F8 close", itemStyle);
				for (int i = 0; i < items.Count; i++)
				{
					GUIStyle val = ((i == sel) ? selStyle : itemStyle);
					GUI.Label(new Rect(14f, num4 + num3 * (float)(i + 1), (float)Screen.width * 0.6f, num3), ((i == sel) ? "> " : "  ") + items[i].Name + ": " + items[i].Val() + ((items[i].Result != null) ? ("   => " + items[i].Result) : ""), val);
				}
			}
		}
	}
	public class Runner : MonoBehaviour
	{
		private void Update()
		{
			Plugin.I.Tick();
		}

		private void OnGUI()
		{
			Plugin.I.Draw();
		}
	}
}