Decompiled source of GK2 Performance v0.1.4

GK2Perf.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cinemachine;
using HarmonyLib;
using HorizonBasedAmbientOcclusion;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using PI.NGSS;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GK2Perf")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GK2Perf")]
[assembly: AssemblyTitle("GK2Perf")]
[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 GK2Perf
{
	internal static class FpsCounter
	{
		private const float Window = 0.5f;

		private static int frames;

		private static float elapsed;

		private static float worst;

		private static string text = "";

		private static GUIStyle style;

		private static GUIStyle shadow;

		private static int styledFor;

		public static void Tick()
		{
			if (!PerfSettings.FpsCounter.Value)
			{
				frames = 0;
				elapsed = 0f;
				worst = 0f;
				return;
			}
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			frames++;
			elapsed += unscaledDeltaTime;
			worst = Mathf.Max(worst, unscaledDeltaTime);
			if (elapsed >= 0.5f)
			{
				text = $"{(float)frames / elapsed:0} fps   {elapsed * 1000f / (float)frames:0.0} ms   worst {worst * 1000f:0.0} ms";
				frames = 0;
				elapsed = 0f;
				worst = 0f;
			}
		}

		public static void Draw()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0060: 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_006c: 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)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0090: 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: Expected O, but got Unknown
			//IL_00c7: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			if (PerfSettings.FpsCounter.Value && text.Length != 0 && (int)Event.current.type == 7)
			{
				if (style == null || styledFor != Screen.height)
				{
					styledFor = Screen.height;
					int fontSize = Mathf.Max(12, Screen.height / 50);
					style = new GUIStyle(GUI.skin.label)
					{
						fontSize = fontSize,
						fontStyle = (FontStyle)1,
						wordWrap = false,
						alignment = (TextAnchor)2
					};
					style.normal.textColor = Color.white;
					shadow = new GUIStyle(style);
					shadow.normal.textColor = new Color(0f, 0f, 0f, 0.8f);
				}
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(10f, 6f, (float)Screen.width - 20f, (float)style.fontSize * 2f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 2f, ((Rect)(ref val)).y + 2f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), text, shadow);
				GUI.Label(val, text, style);
			}
		}
	}
	internal static class MotionCheck
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static CameraCallback <0>__OnPreCull;
		}

		private const float SampleSeconds = 4f;

		private const float PauseSeconds = 60f;

		private const int MaxLogs = 10;

		private const float WalkingSpeed = 0.5f;

		private static int physicsSteps;

		private static int lastFrame = -1;

		private static bool hasLast;

		private static Vector3 lastBody;

		private static Vector3 lastCamera;

		private static float nextSample;

		private static int logs;

		private static Camera worldCamera;

		private static float nextLookup;

		private static int measuredPacing = int.MinValue;

		private static float walked;

		private static int frames;

		private static int bodyStill;

		private static int cameraStill;

		private static int noStep;

		private static int manySteps;

		private static double cameraSum;

		private static double cameraSquares;

		private static float cameraMax;

		public static void Start()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0015: 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)
			//IL_0020: Expected O, but got Unknown
			CameraCallback onPreCull = Camera.onPreCull;
			object obj = <>O.<0>__OnPreCull;
			if (obj == null)
			{
				CameraCallback val = OnPreCull;
				<>O.<0>__OnPreCull = val;
				obj = (object)val;
			}
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)onPreCull, (Delegate?)obj);
		}

		public static void CountStep()
		{
			physicsSteps++;
		}

		public static string Describe()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			string text = "no player";
			PlayerPhysicalBody val = PlayerBody();
			if ((Object)(object)val != (Object)null && (Object)(object)val.Rb != (Object)null)
			{
				text = string.Format("player body {0}{1}", val.Rb.interpolation, val.Rb.isKinematic ? " (kinematic)" : "");
			}
			string text2 = "no camera brain";
			CameraSystem instance = CameraSystem.Instance;
			MainCamera val2 = (((Object)(object)instance != (Object)null) ? instance.MainCamera : null);
			CinemachineBrain val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<CinemachineBrain>() : null);
			if ((Object)(object)val3 != (Object)null)
			{
				text2 = $"camera brain {val3.m_UpdateMethod} (blends {val3.m_BlendUpdateMethod})";
			}
			CameraController val4 = (((Object)(object)instance != (Object)null) ? instance.ActiveCameraController : null);
			CinemachineVirtualCamera val5 = (((Object)(object)val4 != (Object)null) ? val4.VirtualCamera : null);
			string text3 = (((Object)(object)val5 != (Object)null && (Object)(object)((CinemachineVirtualCameraBase)val5).Follow != (Object)null) ? (", camera follows '" + ((Object)((CinemachineVirtualCameraBase)val5).Follow).name + "'") : "");
			return $"physics {1f / Time.fixedDeltaTime:0} Hz, {text}, {text2}{text3}";
		}

		private static PlayerPhysicalBody PlayerBody()
		{
			if ((Object)(object)MainGame.Instance == (Object)null)
			{
				return null;
			}
			PlayerController playerController = MainGame.PlayerController;
			if (!((Object)(object)playerController != (Object)null))
			{
				return null;
			}
			return playerController.PhysicalBody;
		}

		private static void OnPreCull(Camera camera)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00d2: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: 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_0113: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			int num = Application.targetFrameRate * 10 + QualitySettings.vSyncCount;
			if (num != measuredPacing)
			{
				measuredPacing = num;
				Restart();
				nextSample = 0f;
			}
			if (Time.frameCount == lastFrame || logs >= 10 || Time.unscaledTime < nextSample || Time.timeScale <= 0f)
			{
				return;
			}
			try
			{
				if ((Object)(object)camera != (Object)(object)WorldCamera())
				{
					return;
				}
				lastFrame = Time.frameCount;
				int num2 = physicsSteps;
				physicsSteps = 0;
				PlayerPhysicalBody val = PlayerBody();
				if ((Object)(object)val == (Object)null || (Object)(object)val.Rb == (Object)null || val.Rb.isKinematic)
				{
					hasLast = false;
					return;
				}
				Transform transform = ((Component)camera).transform;
				Vector3 position = ((Component)val).transform.position;
				Vector3 position2 = transform.position;
				Vector3 linearVelocity = val.Rb.linearVelocity;
				bool flag = ((Vector3)(ref linearVelocity)).magnitude > 0.5f;
				if (hasLast && flag)
				{
					float num3 = (float)Screen.height / (2f * camera.orthographicSize);
					float num4 = OnScreen(position - lastBody, transform) * num3;
					float num5 = OnScreen(position2 - lastCamera, transform) * num3;
					frames++;
					walked += Time.unscaledDeltaTime;
					bodyStill += ((num4 < 0.01f) ? 1 : 0);
					cameraStill += ((num5 < 0.01f) ? 1 : 0);
					noStep += ((num2 == 0) ? 1 : 0);
					manySteps += ((num2 > 1) ? 1 : 0);
					cameraSum += num5;
					cameraSquares += num5 * num5;
					cameraMax = Mathf.Max(cameraMax, num5);
					if (walked >= 4f)
					{
						Log();
					}
				}
				lastBody = position;
				lastCamera = position2;
				hasLast = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Measuring movement failed: " + ex.Message));
				logs = 10;
			}
		}

		private static Camera WorldCamera()
		{
			if ((Object)(object)worldCamera == (Object)null && Time.unscaledTime >= nextLookup)
			{
				nextLookup = Time.unscaledTime + 2f;
				CameraSystem val = (((Object)(object)MainGame.Instance != (Object)null) ? CameraSystem.Instance : null);
				MainCamera val2 = (((Object)(object)val != (Object)null) ? val.MainCamera : null);
				worldCamera = (((Object)(object)val2 != (Object)null) ? val2.Camera : null);
			}
			return worldCamera;
		}

		private static float OnScreen(Vector3 delta, Transform view)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			float num = Vector3.Dot(delta, view.right);
			float num2 = Vector3.Dot(delta, view.up);
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private static void Log()
		{
			double num = cameraSum / (double)frames;
			double num2 = Math.Sqrt(Math.Max(0.0, cameraSquares / (double)frames - num * num));
			logs++;
			Plugin.Log.LogInfo((object)($"Movement while walking ({frames} frames, {(float)frames / walked:0} fps): the character didn't move on {Percent(bodyStill)} of frames, " + "the camera on " + Percent(cameraStill) + "; frames with no physics step " + Percent(noStep) + ", with two or more " + Percent(manySteps) + "; " + $"camera step {num:0.0} px on average (spread {num2:0.0}, largest {cameraMax:0.0}); " + $"FPS limit {Application.targetFrameRate}, vsync {QualitySettings.vSyncCount}. {Describe()}."));
			Restart();
			nextSample = Time.unscaledTime + 60f;
		}

		private static void Restart()
		{
			walked = 0f;
			frames = (bodyStill = (cameraStill = (noStep = (manySteps = 0))));
			cameraSum = (cameraSquares = 0.0);
			cameraMax = 0f;
			hasLast = false;
		}

		private static string Percent(int count)
		{
			return $"{100f * (float)count / (float)frames:0}%";
		}
	}
	internal sealed class PerfRunner : MonoBehaviour
	{
		private bool applyPending;

		private bool appliedOnLoad;

		private float lastLoadReport = -1000f;

		public static PerfRunner Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			PerfSettings.Changed += delegate
			{
				applyPending = true;
			};
			SceneManager.sceneLoaded += OnSceneLoaded;
			MotionCheck.Start();
		}

		private void FixedUpdate()
		{
			MotionCheck.CountStep();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (!appliedOnLoad && PerfSettings.AnyOverride)
			{
				appliedOnLoad = true;
				applyPending = true;
			}
			else if (Time.unscaledTime - lastLoadReport > 30f)
			{
				lastLoadReport = Time.unscaledTime;
				Report.Soon();
			}
		}

		private void Update()
		{
			if (applyPending)
			{
				applyPending = false;
				Tuning.Reapply();
			}
			ShadowFit.Tick();
			FpsCounter.Tick();
			Report.Tick();
		}

		private void OnGUI()
		{
			FpsCounter.Draw();
		}
	}
	internal enum ShadowChoice
	{
		Game,
		Fitted,
		Console,
		Hard,
		Off
	}
	internal enum RenderChoice
	{
		Game,
		Full,
		PixelArt
	}
	internal enum SnapChoice
	{
		Game,
		Off
	}
	internal enum ShadingChoice
	{
		Game,
		HalfResolution,
		Low,
		Off
	}
	internal enum LampChoice
	{
		Game,
		Real,
		RealNoShadows,
		Faked
	}
	internal sealed class MenuOption
	{
		public string Key;

		public string Header;

		public string[] Labels;

		public Func<int> Get;

		public Action<int> Set;
	}
	internal static class PerfSettings
	{
		public static ConfigEntry<ShadowChoice> Shadows;

		public static ConfigEntry<RenderChoice> WorldResolution;

		public static ConfigEntry<SnapChoice> PixelSnapping;

		public static ConfigEntry<ShadingChoice> AmbientShading;

		public static ConfigEntry<LampChoice> Lamps;

		public static ConfigEntry<bool> FpsCounter;

		public static ConfigEntry<bool> InSettingsMenu;

		public static ConfigEntry<float> ShadowMargin;

		public static MenuOption[] Menu;

		public static bool AnyOverride
		{
			get
			{
				if (Shadows.Value == ShadowChoice.Game && WorldResolution.Value == RenderChoice.Game && AmbientShading.Value == ShadingChoice.Game)
				{
					return Lamps.Value != LampChoice.Game;
				}
				return true;
			}
		}

		public static event Action Changed;

		public static void Bind(ConfigFile config)
		{
			Shadows = config.Bind<ShadowChoice>("Graphics", "Shadows", ShadowChoice.Game, "Game: the Graphics preset's shadows (on PC: soft shadows reaching 3000 units in 4 layers, though the camera shows about 20). Fitted: the same soft shadows, reaching only as far as the camera shows, in one layer. Console: the shadows PS5 and Xbox Series use (simpler soft shadows, no lamp shadows). Hard: hard-edged shadows. Off: no shadows.");
			WorldResolution = config.Bind<RenderChoice>("Graphics", "WorldResolution", RenderChoice.Game, "Game: what the Graphics preset uses (Full on High to Low, Pixel art on Lowest). Full: the world at full screen resolution. Pixel art: the world at the game's pixel size (half resolution at 1080p, a quarter at 4K), scaled up. In Pixel art the camera follows the player rigidly and the water is the simpler kind, as on Lowest.");
			PixelSnapping = config.Bind<SnapChoice>("Graphics", "PixelSnapping", SnapChoice.Game, "Game: the camera and your character snap to whole screen pixels, so while walking the world moves in uneven pixel steps. Off: they move smoothly between pixels, so the world scrolls evenly; pixel-art edges may shimmer a little while moving. Only with the world at full resolution (Pixel art draws on the pixel grid anyway).");
			AmbientShading = config.Bind<ShadingChoice>("Graphics", "AmbientShading", ShadingChoice.Game, "Ambient shading (HBAO, the soft darkening in corners and under objects). Game: the preset's. HalfResolution: the preset's quality, worked out at half resolution. Low: the lowest quality at half resolution. Off: none.");
			Lamps = config.Bind<LampChoice>("Graphics", "Lamps", LampChoice.Game, "Lamps, torches and other point lights. Game: the preset's (real on High and Medium, faked on Low and Lowest). Real: real lights. RealNoShadows: real lights that cast no shadows. Faked: lights painted into a texture (cheaper).");
			FpsCounter = config.Bind<bool>("Display", "FpsCounter", false, "Show the frame rate and frame time in the top-right corner (to compare the options).");
			InSettingsMenu = config.Bind<bool>("Display", "InSettingsMenu", true, "Add these options to the game's Settings menu, under Graphics. Off: change them here only.");
			ShadowMargin = config.Bind<float>("Advanced", "FittedShadowMargin", 15f, "With Fitted, Console or Hard shadows: how far past the farthest ground the camera shows the shadows still reach (in game units). Raise it if shadows vanish at the top of the screen.");
			ConfigEntryBase[] graphics = (ConfigEntryBase[])(object)new ConfigEntryBase[4]
			{
				(ConfigEntryBase)Shadows,
				(ConfigEntryBase)WorldResolution,
				(ConfigEntryBase)AmbientShading,
				(ConfigEntryBase)Lamps
			};
			PixelSnapping.SettingChanged += delegate
			{
				Plugin.Log.LogInfo((object)$"Pixel snapping: {PixelSnapping.Value}.");
			};
			config.SettingChanged += delegate(object sender, SettingChangedEventArgs args)
			{
				if (Array.IndexOf(graphics, args.ChangedSetting) >= 0)
				{
					PerfSettings.Changed?.Invoke();
				}
			};
			Menu = new MenuOption[6]
			{
				Choice<ShadowChoice>("Shadows", "Shadows", Shadows, new string[5] { "Game", "Fitted", "Console", "Hard", "Off" }),
				Choice<RenderChoice>("WorldResolution", "World resolution", WorldResolution, new string[3] { "Game", "Full", "Pixel art" }),
				Choice<SnapChoice>("PixelSnapping", "Pixel snapping", PixelSnapping, new string[2] { "Game", "Off" }),
				Choice<ShadingChoice>("AmbientShading", "Ambient shading", AmbientShading, new string[4] { "Game", "Half res", "Low", "Off" }),
				Choice<LampChoice>("Lamps", "Lamps", Lamps, new string[4] { "Game", "Real", "No shadows", "Faked" }),
				new MenuOption
				{
					Key = "FpsCounter",
					Header = "FPS counter",
					Labels = new string[2] { "Off", "On" },
					Get = () => FpsCounter.Value ? 1 : 0,
					Set = delegate(int i)
					{
						FpsCounter.Value = i == 1;
					}
				}
			};
		}

		public static string Describe()
		{
			return $"Shadows {Shadows.Value}, world resolution {WorldResolution.Value}, pixel snapping {PixelSnapping.Value}, ambient shading {AmbientShading.Value}, lamps {Lamps.Value}.";
		}

		private static MenuOption Choice<T>(string key, string header, ConfigEntry<T> entry, params string[] labels) where T : struct, Enum
		{
			return new MenuOption
			{
				Key = key,
				Header = header,
				Labels = labels,
				Get = () => Convert.ToInt32(entry.Value),
				Set = delegate(int i)
				{
					entry.Value = (T)Enum.ToObject(typeof(T), i);
				}
			};
		}
	}
	[BepInPlugin("com.gk2perf.performance", "GK2 Performance", "0.1.4")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.gk2perf.performance";

		public const string Name = "GK2 Performance";

		public const string Version = "0.1.4";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_001b: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			PerfSettings.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("com.gk2perf.performance").PatchAll(typeof(Plugin).Assembly);
			GameObject val = new GameObject("GK2Perf")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<PerfRunner>();
			Log.LogInfo((object)("GK2 Performance 0.1.4 loaded. " + PerfSettings.Describe()));
		}
	}
	internal static class Report
	{
		private static float dueAt = -1f;

		public static void Soon()
		{
			dueAt = Time.unscaledTime + 1f;
		}

		public static void Tick()
		{
			if (dueAt < 0f || Time.unscaledTime < dueAt)
			{
				return;
			}
			dueAt = -1f;
			try
			{
				Plugin.Log.LogInfo((object)Describe());
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Describing the graphics failed: " + ex.Message));
			}
		}

		private static string Describe()
		{
			//IL_0028: 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_004a: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Invalid comparison between Unknown and I4
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			PlatformFeatureEntry current = PlatformFeatures.Current;
			GameSettings instance = GameSettings.Instance;
			string text = ((instance != null) ? ((object)Unsafe.As<GraphicsTier, GraphicsTier>(ref instance.graphicsTier)/*cast due to .constrained prefix*/).ToString() : "?");
			string text2;
			if ((int)QualitySettings.shadows == 0)
			{
				text2 = "off";
			}
			else
			{
				text2 = $"{current.shadowMode} ({PlatformFeatures.GetActiveUnityShadowPreset()}): distance {QualitySettings.shadowDistance:0}, " + $"cascades {QualitySettings.shadowCascades}, {QualitySettings.shadows}, resolution {QualitySettings.shadowResolution}, pixel lights {QualitySettings.pixelLightCount}";
				LightsSystem instance2 = LightsSystem.Instance;
				Light val = (((Object)(object)instance2 != (Object)null) ? instance2.SunLight : null);
				NGSS_Directional val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<NGSS_Directional>() : null);
				if ((Object)(object)val != (Object)null)
				{
					text2 += $"; sun {val.shadows}, custom map {val.shadowCustomResolution}";
				}
				if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled)
				{
					text2 += $"; NGSS samples {val2.NGSS_SAMPLING_TEST}/{val2.NGSS_SAMPLING_FILTER}, PCSS {val2.NGSS_PCSS_ENABLED}, map {val2.NGSS_SHADOWS_RESOLUTION}";
				}
			}
			string text3 = "?";
			string text4 = "?";
			CameraSystem instance3 = CameraSystem.Instance;
			MainCamera val3 = (((Object)(object)instance3 != (Object)null) ? instance3.MainCamera : null);
			if ((Object)(object)val3 != (Object)null)
			{
				Camera camera = val3.Camera;
				text3 = $"{val3.GetRenderType()}";
				if ((Object)(object)val3.RenderTexture != (Object)null)
				{
					text3 += $" {((Texture)val3.RenderTexture).width}x{((Texture)val3.RenderTexture).height}";
				}
				text3 += $" on {Screen.width}x{Screen.height} (pixel size {ResolutionConfig.PixelSize}";
				if ((Object)(object)camera != (Object)null)
				{
					text3 += $", view {camera.orthographicSize * 2f * camera.aspect:0.0}x{camera.orthographicSize * 2f:0.0}, clip {camera.nearClipPlane:0.##}-{camera.farClipPlane:0}";
				}
				text3 += ")";
				HBAO component = ((Component)val3).GetComponent<HBAO>();
				text4 = (((Object)(object)component == (Object)null) ? "none" : (((Behaviour)component).enabled ? $"{component.GetQuality()} at {component.GetResolution()} resolution" : "off"));
			}
			int num = 0;
			int num2 = 0;
			Light[] array = Object.FindObjectsByType<Light>((FindObjectsSortMode)0);
			foreach (Light val4 in array)
			{
				if ((int)val4.type != 1 && ((Behaviour)val4).isActiveAndEnabled)
				{
					num++;
					if ((int)val4.shadows != 0)
					{
						num2++;
					}
				}
			}
			return "In effect (Graphics preset " + text + "; ours: " + PerfSettings.Describe() + ")\n  Shadows: " + text2 + "\n  World: " + text3 + "\n  Ambient shading: " + text4 + "\n" + $"  Lamps: {current.pointLightMode}, {num} lit, {num2} with shadows\n" + "  Motion: " + MotionCheck.Describe() + "\n" + $"  Water {current.waterTier}, post-processing {current.postProcessing}, frame cap {Application.targetFrameRate}, vsync {QualitySettings.vSyncCount}, " + $"graphics {SystemInfo.graphicsDeviceType} on {SystemInfo.graphicsDeviceName}";
		}
	}
	internal static class SettingsMenu
	{
		private const string RowPrefix = "GK2Perf ";

		private const float ScreenShare = 0.94f;

		private static readonly FieldRef<UIGameSettingsWindow, UISwitchButton> GraphicsButton = AccessTools.FieldRefAccess<UIGameSettingsWindow, UISwitchButton>("graphicsTierButton");

		private static readonly FieldRef<UIGameSettingsWindow, UISwitchButton> FpsButton = AccessTools.FieldRefAccess<UIGameSettingsWindow, UISwitchButton>("fpsLockButton");

		private static readonly FieldRef<UISwitchButton, TextMeshProUGUI> HeaderLabel = AccessTools.FieldRefAccess<UISwitchButton, TextMeshProUGUI>("headerLabel");

		private static readonly FieldRef<UISwitchButton, TextMeshProUGUI> AmountLabel = AccessTools.FieldRefAccess<UISwitchButton, TextMeshProUGUI>("amountLabel");

		private static readonly FieldRef<UISwitchButton, GamepadNavigationItem> NavigationItem = AccessTools.FieldRefAccess<UISwitchButton, GamepadNavigationItem>("gamepadNavigationItem");

		private static readonly Dictionary<int, Vector3> ownScales = new Dictionary<int, Vector3>();

		public static void Build(UIGameSettingsWindow window)
		{
			if (!PerfSettings.InSettingsMenu.Value)
			{
				return;
			}
			UISwitchButton val = GraphicsButton.Invoke(window) ?? FpsButton.Invoke(window);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"The Settings window has no Graphics switch to copy: the options are in the config file only.");
				return;
			}
			Transform val2 = RowOf(val, ((Component)window).transform);
			Transform parent = val2.parent;
			int num = val2.GetSiblingIndex();
			(GameKey[], GameKey[]) tuple = (Traverse.Create(typeof(UIGameSettingsWindow)).Field("decreaseKeys").GetValue<GameKey[]>(), Traverse.Create(typeof(UIGameSettingsWindow)).Field("increaseKeys").GetValue<GameKey[]>());
			MenuOption[] menu = PerfSettings.Menu;
			foreach (MenuOption menuOption in menu)
			{
				Transform val3 = parent.Find("GK2Perf " + menuOption.Key);
				GameObject val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : Object.Instantiate<GameObject>(((Component)val2).gameObject, parent, false));
				((Object)val4).name = "GK2Perf " + menuOption.Key;
				val4.transform.SetSiblingIndex(++num);
				val4.SetActive(true);
				LocalizedLabel[] componentsInChildren = val4.GetComponentsInChildren<LocalizedLabel>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					componentsInChildren[j].IgnoreLocalize = true;
				}
				UISwitchButton button = val4.GetComponentInChildren<UISwitchButton>(true);
				GamepadNavigationItem val5 = NavigationItem.Invoke(button);
				if ((Object)(object)val5 != (Object)null)
				{
					val5.ResetCustomDirections();
				}
				MenuOption chosen = menuOption;
				button.Initialize((Action<int>)delegate(int obj)
				{
					chosen.Set(obj);
				}, chosen.Labels, chosen.Get(), chosen.Header, tuple.Item1, tuple.Item2, false);
				TextMeshProUGUI val6 = HeaderLabel.Invoke(button) ?? ((IEnumerable<TextMeshProUGUI>)val4.GetComponentsInChildren<TextMeshProUGUI>(true)).FirstOrDefault((Func<TextMeshProUGUI, bool>)((TextMeshProUGUI t) => (Object)(object)t != (Object)(object)AmountLabel.Invoke(button)));
				if ((Object)(object)val6 != (Object)null)
				{
					((TMP_Text)val6).text = chosen.Header;
				}
			}
			Plugin.Log.LogInfo((object)$"Added {PerfSettings.Menu.Length} options to the Settings window (copies of '{Path(val2, ((Component)window).transform)}', {((Component)val2).GetComponentsInChildren<Selectable>(true).Length} controls each).");
		}

		public static void Opened(UIGameSettingsWindow window)
		{
			if (!PerfSettings.InSettingsMenu.Value)
			{
				return;
			}
			UISwitchButton val = GraphicsButton.Invoke(window) ?? FpsButton.Invoke(window);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform parent = RowOf(val, ((Component)window).transform).parent;
			MenuOption[] menu = PerfSettings.Menu;
			foreach (MenuOption menuOption in menu)
			{
				Transform val2 = parent.Find("GK2Perf " + menuOption.Key);
				UISwitchButton val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponentInChildren<UISwitchButton>(true) : null);
				if ((Object)(object)val3 != (Object)null && val3.CurrentFieldIndex != menuOption.Get())
				{
					val3.UpdateField(menuOption.Get(), false);
				}
			}
			PerfRunner instance = PerfRunner.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(FitOnScreen(window, parent));
			}
		}

		private static IEnumerator FitOnScreen(UIGameSettingsWindow window, Transform rows)
		{
			yield return null;
			if ((Object)(object)window == (Object)null || !((Behaviour)window).isActiveAndEnabled || (Object)(object)rows == (Object)null)
			{
				yield break;
			}
			Canvas componentInParent = ((Component)window).GetComponentInParent<Canvas>();
			RectTransform val = (RectTransform)(((Object)(object)componentInParent != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				yield break;
			}
			Rect rect = val.rect;
			float height = ((Rect)(ref rect)).height;
			LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)((Component)window).transform);
			RectTransform val2 = null;
			Transform val3 = rows;
			while ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)((Component)window).transform)
			{
				RectTransform val4 = (RectTransform)(object)((val3 is RectTransform) ? val3 : null);
				if (val4 != null && HeightOnScreen(val4, val) < height * 0.99f)
				{
					val2 = val4;
				}
				val3 = val3.parent;
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				int instanceID = ((Object)val2).GetInstanceID();
				if (!ownScales.TryGetValue(instanceID, out var value))
				{
					value = ((Transform)val2).localScale;
					ownScales[instanceID] = value;
				}
				((Transform)val2).localScale = value;
				float num = HeightOnScreen(val2, val);
				float num2 = height * 0.94f;
				if (num > num2)
				{
					float num3 = num2 / num;
					((Transform)val2).localScale = value * num3;
					Plugin.Log.LogInfo((object)$"The Settings panel ({num:0} of {height:0} high) shrunk to {num3:0.00} to fit the screen.");
				}
			}
		}

		private static float HeightOnScreen(RectTransform rect, RectTransform canvasRect)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//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)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rect.GetWorldCorners(array);
			return ((Transform)canvasRect).InverseTransformPoint(array[1]).y - ((Transform)canvasRect).InverseTransformPoint(array[0]).y;
		}

		private static Transform RowOf(UISwitchButton button, Transform window)
		{
			TextMeshProUGUI val = HeaderLabel.Invoke(button);
			Transform val2 = ((Component)button).transform;
			if ((Object)(object)val == (Object)null || ((TMP_Text)val).transform.IsChildOf(val2))
			{
				return val2;
			}
			while ((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)window && !((TMP_Text)val).transform.IsChildOf(val2))
			{
				val2 = val2.parent;
			}
			if (!((TMP_Text)val).transform.IsChildOf(val2) || ((Component)val2).GetComponentsInChildren<UISwitchButton>(true).Length != 1)
			{
				Plugin.Log.LogWarning((object)"The Graphics switch's header isn't in its row: copying the switch alone.");
				return ((Component)button).transform;
			}
			return val2;
		}

		private static string Path(Transform t, Transform root)
		{
			string text = ((Object)t).name;
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)root)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	[HarmonyPatch(typeof(UIGameSettingsWindow), "Init")]
	internal static class AddSettingsRows
	{
		private static void Postfix(UIGameSettingsWindow __instance)
		{
			try
			{
				SettingsMenu.Build(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Adding the options to the Settings window failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(UIGameSettingsWindow), "Open", new Type[] { typeof(LazyWidgetDataBase) })]
	internal static class ShowSettingsRows
	{
		private static void Postfix(UIGameSettingsWindow __instance)
		{
			try
			{
				SettingsMenu.Opened(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Showing the options in the Settings window failed: {arg}");
			}
		}
	}
	internal static class ShadowFit
	{
		private const float CheckSeconds = 0.25f;

		private const float MinDistance = 30f;

		private const float MaxDistance = 600f;

		private const float LowerGround = 6f;

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(0f, 0f, 0f),
			new Vector3(1f, 0f, 0f),
			new Vector3(0f, 1f, 0f),
			new Vector3(1f, 1f, 0f)
		};

		private static float nextCheck;

		private static float nextLookup;

		private static CameraSystem cameras;

		private static int logged;

		public static float Distance { get; private set; } = 150f;

		public static void Tick()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			if (!Tuning.FitsShadows || Time.unscaledTime < nextCheck)
			{
				return;
			}
			nextCheck = Time.unscaledTime + 0.25f;
			float? num;
			try
			{
				num = Measure();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Measuring the camera's view failed: " + ex.Message));
				cameras = null;
				return;
			}
			if (num.HasValue)
			{
				float num2 = Mathf.Clamp(Mathf.Ceil((num.Value + PerfSettings.ShadowMargin.Value) / 10f) * 10f, 30f, 600f);
				if (num2 > Distance || num2 < Distance - 30f)
				{
					if (logged < 20)
					{
						logged++;
						Plugin.Log.LogInfo((object)$"Shadow range fitted to the camera: {Distance:0} -> {num2:0} (farthest ground {num.Value:0.0}).");
					}
					Distance = num2;
				}
			}
			if ((int)QualitySettings.shadows != 0 && (Mathf.Abs(QualitySettings.shadowDistance - Distance) > 0.5f || QualitySettings.shadowCascades > 1))
			{
				Tuning.AfterShadowsApplied();
			}
		}

		private static float? Measure()
		{
			//IL_002e: 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_0051: 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)
			//IL_0077: 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_007c: 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_0085: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			Camera val = WorldCamera();
			if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
			{
				return null;
			}
			Transform transform = ((Component)val).transform;
			float num = cameras.CameraGroundPos.y - 6f;
			Plane val2 = default(Plane);
			((Plane)(ref val2))..ctor(Vector3.up, new Vector3(0f, num, 0f));
			float num2 = 0f;
			Vector3[] corners = Corners;
			float num3 = default(float);
			foreach (Vector3 val3 in corners)
			{
				Ray val4 = val.ViewportPointToRay(val3);
				if (!((Plane)(ref val2)).Raycast(val4, ref num3))
				{
					return 600f;
				}
				num2 = Mathf.Max(num2, Vector3.Dot(((Ray)(ref val4)).GetPoint(num3) - transform.position, transform.forward));
			}
			return num2;
		}

		private static Camera WorldCamera()
		{
			if ((Object)(object)cameras == (Object)null)
			{
				if (Time.unscaledTime < nextLookup)
				{
					return null;
				}
				nextLookup = Time.unscaledTime + 2f;
				cameras = CameraSystem.Instance;
				if ((Object)(object)cameras == (Object)null)
				{
					return null;
				}
			}
			MainCamera mainCamera = cameras.MainCamera;
			if (!((Object)(object)mainCamera != (Object)null))
			{
				return null;
			}
			return mainCamera.Camera;
		}
	}
	internal static class Snapping
	{
		public static bool Off => PerfSettings.PixelSnapping.Value == SnapChoice.Off;
	}
	[HarmonyPatch(typeof(CameraController), "GetRoundedCameraPosition")]
	internal static class SmoothCamera
	{
		private static readonly FieldRef<bool> CanMoveBySubpixel = AccessTools.StaticFieldRefAccess<bool>(AccessTools.Field(typeof(CameraController), "canMoveBySubpixel"));

		private static readonly FieldRef<bool> SubpixelPosition = AccessTools.StaticFieldRefAccess<bool>(AccessTools.Field(typeof(CameraController), "subpixelPosition"));

		private static readonly int SubOffset = Shader.PropertyToID("_CameraSubOffset");

		private static readonly int Offset = Shader.PropertyToID("_CameraOffset");

		private static bool Prefix(Vector3 position, bool writeOffsetToShader, ref Vector3 __result)
		{
			//IL_0016: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0021: 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_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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_005c: 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_007b: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!Snapping.Off || !CanMoveBySubpixel.Invoke())
			{
				return true;
			}
			Vector3 roundedPosXYZ = VisualConsts.GetRoundedPosXYZ(position, 2, 1);
			Vector3 val = Vector3.Scale(position - roundedPosXYZ, VisualConsts.XYZ_STEP_INV) * ((float)ResolutionConfig.PixelSize / 2f);
			Shader.SetGlobalVector(SubOffset, Vector4.op_Implicit(SubpixelPosition.Invoke() ? val : Vector3.zero));
			if (writeOffsetToShader)
			{
				Shader.SetGlobalVector(Offset, Vector4.op_Implicit(val));
			}
			__result = position;
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerView), "LateUpdate")]
	internal static class SmoothPlayer
	{
		private static readonly FieldRef<PlayerView, int> RoundingSize = AccessTools.FieldRefAccess<PlayerView, int>("pixelSizeForPosRounding");

		private static bool Prefix(PlayerView __instance)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!Snapping.Off || RoundingSize.Invoke(__instance) != 1)
			{
				return true;
			}
			Transform parent = ((Component)__instance).transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return true;
			}
			((Component)__instance).transform.position = parent.position;
			return false;
		}
	}
	internal static class Tuning
	{
		private static readonly Dictionary<int, Resolution> hbaoResolutions = new Dictionary<int, Resolution>();

		public static bool FitsShadows
		{
			get
			{
				ShadowChoice value = PerfSettings.Shadows.Value;
				if (value != ShadowChoice.Fitted && value != ShadowChoice.Console)
				{
					return value == ShadowChoice.Hard;
				}
				return true;
			}
		}

		public static PlatformFeatureEntry Override(PlatformFeatureEntry entry, PlatformFeatureEntry baseEntry)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0072: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (entry == null || (int)entry.platform != 0 || !PerfSettings.AnyOverride)
			{
				return entry;
			}
			PlatformFeatureEntry val = ((entry == baseEntry) ? entry.Clone() : entry);
			switch (PerfSettings.Shadows.Value)
			{
			case ShadowChoice.Fitted:
				val.shadowMode = (PlatformShadowMode)1;
				break;
			case ShadowChoice.Console:
				val.shadowMode = (PlatformShadowMode)2;
				val.unityShadowPreset = (PlatformUnityShadowPreset)6;
				break;
			case ShadowChoice.Hard:
				val.shadowMode = (PlatformShadowMode)2;
				val.unityShadowPreset = (PlatformUnityShadowPreset)1;
				break;
			case ShadowChoice.Off:
				val.shadowMode = (PlatformShadowMode)0;
				break;
			}
			switch (PerfSettings.WorldResolution.Value)
			{
			case RenderChoice.Full:
				val.renderMode = (PlatformRenderMode)0;
				break;
			case RenderChoice.PixelArt:
				val.renderMode = (PlatformRenderMode)1;
				val.waterTier = (PlatformWaterTier)2;
				break;
			}
			switch (PerfSettings.AmbientShading.Value)
			{
			case ShadingChoice.Low:
				val.hbaoQuality = (PlatformHBAOQuality)1;
				break;
			case ShadingChoice.Off:
				val.hbaoQuality = (PlatformHBAOQuality)0;
				break;
			}
			switch (PerfSettings.Lamps.Value)
			{
			case LampChoice.Real:
			case LampChoice.RealNoShadows:
				val.pointLightMode = (PlatformPointLightMode)0;
				break;
			case LampChoice.Faked:
				val.pointLightMode = (PlatformPointLightMode)1;
				break;
			}
			return val;
		}

		public static void AfterShadowsApplied()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (FitsShadows && (int)QualitySettings.shadows != 0)
			{
				QualitySettings.shadowCascades = 0;
				QualitySettings.shadowDistance = ShadowFit.Distance;
				RefreshNgss();
			}
		}

		public static void RefreshNgss()
		{
			LightsSystem instance = LightsSystem.Instance;
			Light val = (((Object)(object)instance != (Object)null) ? instance.SunLight : null);
			NGSS_Directional val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<NGSS_Directional>() : null);
			if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).isActiveAndEnabled || !val2.NGSS_NO_UPDATE_ON_PLAY)
			{
				return;
			}
			try
			{
				val2.UpdateParameters();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Refreshing NGSS failed: " + ex.Message));
			}
		}

		public static void AfterHbaoApplied()
		{
			//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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0084: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			CameraSystem instance = CameraSystem.Instance;
			MainCamera val = (((Object)(object)instance != (Object)null) ? instance.MainCamera : null);
			HBAO val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<HBAO>() : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				int instanceID = ((Object)val2).GetInstanceID();
				if (!hbaoResolutions.TryGetValue(instanceID, out var value))
				{
					value = val2.GetResolution();
					hbaoResolutions[instanceID] = value;
				}
				ShadingChoice value2 = PerfSettings.AmbientShading.Value;
				Resolution val3 = (Resolution)((value2 == ShadingChoice.HalfResolution || value2 == ShadingChoice.Low) ? 1 : ((int)value));
				if (val2.GetResolution() != val3)
				{
					val2.SetResolution(val3);
				}
			}
		}

		public static void Reapply()
		{
			if (GameSettings.Instance == null)
			{
				return;
			}
			try
			{
				PlatformFeatures.ReapplyAll();
				Plugin.Log.LogInfo((object)("Applied: " + PerfSettings.Describe()));
				Report.Soon();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Applying the graphics options failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(GraphicsTierConfig), "ApplyTier")]
	internal static class TierOverrides
	{
		private static void Postfix(PlatformFeatureEntry baseEntry, ref PlatformFeatureEntry __result)
		{
			try
			{
				__result = Tuning.Override(__result, baseEntry);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Overriding the graphics preset failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(PlatformFeatures), "ApplyShadowSettings")]
	internal static class FittedShadows
	{
		private static void Postfix()
		{
			try
			{
				Tuning.AfterShadowsApplied();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Fitting the shadows failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(PlatformFeatures), "ApplyHBAO")]
	internal static class HbaoResolution
	{
		private static void Postfix()
		{
			try
			{
				Tuning.AfterHbaoApplied();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Setting the ambient shading resolution failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SwitchLightPolicy), "ApplyLocalLightShadowPolicy")]
	internal static class LampShadows
	{
		private static bool Prefix(Light light)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (PerfSettings.Lamps.Value != LampChoice.RealNoShadows || (Object)(object)light == (Object)null || (int)light.type == 1)
			{
				return true;
			}
			if ((int)light.shadows != 0)
			{
				light.shadows = (LightShadows)0;
			}
			return false;
		}
	}
}