Decompiled source of REPOFidelity v1.6.3

REPOFidelity.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using REPOFidelity.Patches;
using REPOFidelity.Shaders;
using REPOFidelity.Upscalers;
using TMPro;
using Unity.Profiling;
using Unity.Profiling.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("Vippy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.6.3.0")]
[assembly: AssemblyInformationalVersion("1.6.3+5b124e5e41855e590e49024ae9fec305860b5997")]
[assembly: AssemblyProduct("REPOFidelity")]
[assembly: AssemblyTitle("REPOFidelity")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 REPOFidelity
{
	internal static class BuildInfo
	{
		public const string Version = "1.6.3";
	}
	internal class CostProbe : MonoBehaviour
	{
		private class CamTiming
		{
			public readonly Stopwatch Sw = new Stopwatch();

			public double TotalMs;

			public int Frames;
		}

		internal static class ScriptTiming
		{
			internal class Acc
			{
				public long Ticks;

				public int Calls;
			}

			private static readonly Dictionary<MethodBase, Acc> _accs = new Dictionary<MethodBase, Acc>();

			internal static void Clear()
			{
				_accs.Clear();
			}

			internal static void Reset()
			{
				foreach (Acc value in _accs.Values)
				{
					value.Ticks = 0L;
					value.Calls = 0;
				}
			}

			internal static void Register(MethodInfo m)
			{
				if (!_accs.ContainsKey(m))
				{
					_accs[m] = new Acc();
				}
			}

			internal static (long ticks, int calls) Read(MethodInfo m)
			{
				if (_accs.TryGetValue(m, out Acc value))
				{
					return (value.Ticks, value.Calls);
				}
				return (0L, 0);
			}

			public static void Prefix(out long __state)
			{
				__state = Stopwatch.GetTimestamp();
			}

			public static void Postfix(MethodBase __originalMethod, long __state)
			{
				if (_accs.TryGetValue(__originalMethod, out Acc value))
				{
					value.Ticks += Stopwatch.GetTimestamp() - __state;
					value.Calls++;
				}
			}
		}

		private struct Sample
		{
			public float AvgFps;

			public float AvgMs;

			public float P1Low;

			public float P01Low;

			public int FrameCount;
		}

		private struct RendererBreakdown
		{
			public int Total;

			public int Visible;

			public int ShadowCasting;

			public int ShadowCastingHidden;

			public int NoLODGroup;
		}

		private struct LightBreakdown
		{
			public int Active;

			public int Shadowing;

			public int Directional;

			public int PointShadow;

			public int SpotShadow;
		}

		private struct LightInfo
		{
			public string Name;

			public string Type;

			public string ShadowMode;

			public float Range;

			public int Resolution;

			public float CostScore;
		}

		private struct SceneMetrics
		{
			public RendererBreakdown Renderers;

			public LightBreakdown Lights;

			public long TotalSceneTris;

			public int SkinnedRenderers;

			public int TotalParticles;

			public int ActiveParticles;

			public int ActiveParticleCount;

			public int ReflectionProbes;

			public int TrailRenderers;

			public int LineRenderers;

			public int AudioSources;

			public int AudioSourcesPlaying;

			public int UpdatingBehaviours;

			public int LateUpdatingBehaviours;

			public int FixedUpdatingBehaviours;

			public List<LightInfo> LightDetail;

			public List<(string typeName, int count)> TopBehaviourTypes;
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass39_0
		{
			public double tickToMsMod;

			public int baselineFrames;

			public List<(string name, string cat, double n)> countStats;

			public StringBuilder report;

			public bool anyCount;

			public int cellIdx;

			public int totalCells;

			public Sample autoSample;

			public Sample vanillaSample;

			internal (string name, double ms, float callsPerFrame, int calls) <Run>b__3((string name, long ticks, int calls) r)
			{
				return (r.name, (double)r.ticks * tickToMsMod / (double)baselineFrames, (float)r.calls / (float)baselineFrames, r.calls);
			}

			internal void <Run>b__9(Sample v)
			{
				autoSample = v;
			}

			internal void <Run>b__10(Sample v)
			{
				vanillaSample = v;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass39_1
		{
			public HashSet<string> topSet;

			internal bool <Run>b__18(Type t)
			{
				return topSet.Contains(t.Name);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass39_2
		{
			public Sample s;

			internal void <Run>b__21(Sample v)
			{
				s = v;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass39_3
		{
			public Sample ps;

			internal void <Run>b__22(Sample v)
			{
				ps = v;
			}
		}

		[CompilerGenerated]
		private sealed class <Run>d__39 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public CostProbe <>4__this;

			private <>c__DisplayClass39_0 <>8__1;

			private <>c__DisplayClass39_2 <>8__2;

			private <>c__DisplayClass39_3 <>8__3;

			private CursorLockMode <savedLockState>5__2;

			private bool <savedVisible>5__3;

			private QualityPreset <origPreset>5__4;

			private UpscaleMode <origUpscaler>5__5;

			private float <origFog>5__6;

			private bool <origModEnabled>5__7;

			private List<(ProfilerRecorder rec, string name, string cat)> <timeRecs>5__8;

			private List<(ProfilerRecorder rec, string name, string cat)> <countRecs>5__9;

			private List<(ProfilerRecorder rec, string name, string cat)> <memRecs>5__10;

			private double[] <timeTotals>5__11;

			private long[] <countTotals>5__12;

			private long[] <memTotals>5__13;

			private int <gen0Start>5__14;

			private int <gen1Start>5__15;

			private long <monoStart>5__16;

			private float <worstFrameMs>5__17;

			private List<float> <frames>5__18;

			private float <elapsed>5__19;

			private List<(string name, long ticks, int calls)> <modTimingSnapshot>5__20;

			private List<(string name, string cat, double ms)> <timeStats>5__21;

			private List<(string name, string cat, double bytes)> <memStats>5__22;

			private float[] <abMs>5__23;

			private float[] <abFps>5__24;

			private float[] <abWorst>5__25;

			private int[] <abGen1Arr>5__26;

			private long[] <abMonoArr>5__27;

			private bool[] <abOn>5__28;

			private List<(string name, string cat, double bytes)> <perFrameMem>5__29;

			private SceneMetrics <scene>5__30;

			private List<(string label, double totalMs, double perCallUs, int calls)> <scriptTimings>5__31;

			private List<UpscaleMode> <upscalers>5__32;

			private QualityPreset[] <presetLadder>5__33;

			private float[] <fogPasses>5__34;

			private List<(string label, float ms, float shadowD, float lightD, bool isActive)> <sweepResults>5__35;

			private Sample <potatoSample>5__36;

			private int <s>5__37;

			private int <g1Start>5__38;

			private long <mStart>5__39;

			private float <worst>5__40;

			private List<float> <fr>5__41;

			private float <el>5__42;

			private Harmony <harmony>5__43;

			private List<MethodInfo> <patched>5__44;

			private List<UpscaleMode>.Enumerator <>7__wrap44;

			private UpscaleMode <mode>5__46;

			private float[] <>7__wrap46;

			private QualityPreset[] <>7__wrap47;

			private QualityPreset <p>5__49;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Run>d__39(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 12) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<>8__2 = null;
				<>8__3 = null;
				<timeRecs>5__8 = null;
				<countRecs>5__9 = null;
				<memRecs>5__10 = null;
				<timeTotals>5__11 = null;
				<countTotals>5__12 = null;
				<memTotals>5__13 = null;
				<frames>5__18 = null;
				<modTimingSnapshot>5__20 = null;
				<timeStats>5__21 = null;
				<memStats>5__22 = null;
				<abMs>5__23 = null;
				<abFps>5__24 = null;
				<abWorst>5__25 = null;
				<abGen1Arr>5__26 = null;
				<abMonoArr>5__27 = null;
				<abOn>5__28 = null;
				<perFrameMem>5__29 = null;
				<scene>5__30 = default(SceneMetrics);
				<scriptTimings>5__31 = null;
				<upscalers>5__32 = null;
				<presetLadder>5__33 = null;
				<fogPasses>5__34 = null;
				<sweepResults>5__35 = null;
				<fr>5__41 = null;
				<harmony>5__43 = null;
				<patched>5__44 = null;
				<>7__wrap44 = default(List<UpscaleMode>.Enumerator);
				<>7__wrap46 = null;
				<>7__wrap47 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_25d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_25e2: Expected O, but got Unknown
				//IL_2a6f: Unknown result type (might be due to invalid IL or missing references)
				//IL_2a79: Expected O, but got Unknown
				//IL_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_0213: Unknown result type (might be due to invalid IL or missing references)
				//IL_0218: Unknown result type (might be due to invalid IL or missing references)
				//IL_021c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0221: Unknown result type (might be due to invalid IL or missing references)
				//IL_0742: Unknown result type (might be due to invalid IL or missing references)
				//IL_074c: Expected O, but got Unknown
				//IL_074c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0756: Expected O, but got Unknown
				//IL_0762: Unknown result type (might be due to invalid IL or missing references)
				//IL_076c: Expected O, but got Unknown
				//IL_076c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0776: Expected O, but got Unknown
				//IL_265d: Unknown result type (might be due to invalid IL or missing references)
				//IL_2667: Expected O, but got Unknown
				//IL_2da6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0395: Unknown result type (might be due to invalid IL or missing references)
				//IL_039f: Expected O, but got Unknown
				//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_040f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0414: Unknown result type (might be due to invalid IL or missing references)
				//IL_0418: Unknown result type (might be due to invalid IL or missing references)
				//IL_0423: Unknown result type (might be due to invalid IL or missing references)
				//IL_0428: Unknown result type (might be due to invalid IL or missing references)
				//IL_043e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0443: Unknown result type (might be due to invalid IL or missing references)
				//IL_0445: Unknown result type (might be due to invalid IL or missing references)
				//IL_0448: Unknown result type (might be due to invalid IL or missing references)
				//IL_045a: Expected I4, but got Unknown
				//IL_2816: Unknown result type (might be due to invalid IL or missing references)
				//IL_2820: Expected O, but got Unknown
				//IL_04af: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b9: Expected O, but got Unknown
				//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_04c3: Expected O, but got Unknown
				//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_04d9: Expected O, but got Unknown
				//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_04e3: Expected O, but got Unknown
				//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_04f3: Expected O, but got Unknown
				//IL_2977: Unknown result type (might be due to invalid IL or missing references)
				//IL_2981: Expected O, but got Unknown
				//IL_2de6: Unknown result type (might be due to invalid IL or missing references)
				//IL_2df0: Expected O, but got Unknown
				//IL_0d38: Unknown result type (might be due to invalid IL or missing references)
				//IL_0d42: Expected O, but got Unknown
				//IL_24fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_2504: Expected O, but got Unknown
				//IL_1eb1: Unknown result type (might be due to invalid IL or missing references)
				//IL_1ebb: Expected O, but got Unknown
				//IL_1eeb: Unknown result type (might be due to invalid IL or missing references)
				//IL_1ef2: Expected O, but got Unknown
				//IL_1ef2: Unknown result type (might be due to invalid IL or missing references)
				//IL_1ef9: Expected O, but got Unknown
				//IL_1fde: Unknown result type (might be due to invalid IL or missing references)
				//IL_1fe8: Expected O, but got Unknown
				try
				{
					int num = <>1__state;
					CostProbe costProbe = <>4__this;
					Sample sample;
					double num10;
					int num11;
					(ProfilerRecorder, string, string) tuple3;
					int num18;
					int num19;
					long monoUsedSizeLong;
					int num20;
					Sample sample2;
					double num24;
					double num25;
					double num26;
					double num27;
					string text6;
					long num28;
					float num29;
					float num30;
					float num31;
					float num32;
					float num33;
					long num34;
					long num35;
					float num36;
					int num38;
					List<(string, double, float, int)> list;
					switch (num)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass39_0();
						Running = true;
						Progress = 0f;
						costProbe._camTimings.Clear();
						<>2__current = costProbe.WaitForAutotuneIfActive();
						<>1__state = 1;
						return true;
					case 1:
					{
						<>1__state = -1;
						<savedLockState>5__2 = Cursor.lockState;
						<savedVisible>5__3 = Cursor.visible;
						Cursor.lockState = (CursorLockMode)0;
						Cursor.visible = true;
						<origPreset>5__4 = Settings.Preset;
						<origUpscaler>5__5 = Settings.UpscaleModeSetting;
						<origFog>5__6 = Settings.FogDistanceMultiplier;
						<origModEnabled>5__7 = Settings.ModEnabled;
						if (!<origModEnabled>5__7)
						{
							Settings.ModEnabled = true;
							SceneOptimizer.Apply();
							QualityPatch.ApplyQualitySettings();
						}
						<>8__1.report = new StringBuilder();
						<>8__1.report.AppendLine(string.Format("== REPOFidelity frame cost — {0:yyyy-MM-dd HH:mm:ss} (v{1}) ==", DateTime.Now, "1.6.3"));
						<>8__1.report.AppendLine($"GPU:    {SystemInfo.graphicsDeviceName} ({SystemInfo.graphicsMemorySize}MB, {SystemInfo.graphicsDeviceType})");
						<>8__1.report.AppendLine($"CPU:    {SystemInfo.processorType} ({SystemInfo.processorCount} cores, {SystemInfo.systemMemorySize}MB RAM)");
						<>8__1.report.AppendLine("OS:     " + SystemInfo.operatingSystem);
						StringBuilder report = <>8__1.report;
						object[] obj = new object[4]
						{
							Screen.width,
							Screen.height,
							null,
							null
						};
						Resolution currentResolution = Screen.currentResolution;
						RefreshRate refreshRateRatio = ((Resolution)(ref currentResolution)).refreshRateRatio;
						obj[2] = ((RefreshRate)(ref refreshRateRatio)).value;
						obj[3] = (Screen.fullScreen ? "fullscreen" : "windowed");
						report.AppendLine(string.Format("Screen: {0}x{1} @ {2:F0}Hz ({3})", obj));
						<>8__1.report.AppendLine($"Mod:    [{Settings.Preset}] upscaler={Settings.ResolvedUpscaleMode} " + $"scale={Settings.ResolvedRenderScale}% shadowQ={Settings.ResolvedShadowQuality} " + $"shadowD={Settings.ResolvedShadowDistance:F0}m lights={Settings.ResolvedPixelLightCount} " + $"lod={Settings.ResolvedLODBias:F1} AF={Settings.ResolvedAnisotropicFiltering}x");
						<>8__1.report.AppendLine($"Range:  fog={Settings.ResolvedFogMultiplier:F2}x " + $"effectiveFogEnd={Settings.ResolvedEffectiveFogEnd:F0}m " + $"lightD={Settings.ResolvedLightDistance:F0}m shadowBudget={Settings.ResolvedShadowBudget}");
						<>8__1.report.AppendLine($"Flags:  modEnabled={Settings.ModEnabled} optEnabled={Settings.OptimizationsEnabled} cpuPatches={Settings.CpuPatchesActive}");
						<>8__1.report.AppendLine();
						Status = "Measuring (all markers + per-camera + scene)";
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 2;
						return true;
					}
					case 2:
					{
						<>1__state = -1;
						List<ProfilerRecorderHandle> list3 = new List<ProfilerRecorderHandle>();
						ProfilerRecorderHandle.GetAvailable(list3);
						<timeRecs>5__8 = new List<(ProfilerRecorder, string, string)>();
						<countRecs>5__9 = new List<(ProfilerRecorder, string, string)>();
						<memRecs>5__10 = new List<(ProfilerRecorder, string, string)>();
						foreach (ProfilerRecorderHandle item13 in list3)
						{
							ProfilerRecorderDescription description = ProfilerRecorderHandle.GetDescription(item13);
							ProfilerRecorder item11 = ProfilerRecorder.StartNew(((ProfilerRecorderDescription)(ref description)).Category, ((ProfilerRecorderDescription)(ref description)).Name, 256, (ProfilerRecorderOptions)24);
							string name = ((ProfilerRecorderDescription)(ref description)).Name;
							ProfilerCategory category = ((ProfilerRecorderDescription)(ref description)).Category;
							(ProfilerRecorder, string, string) item12 = (item11, name, ((object)(ProfilerCategory)(ref category)).ToString());
							ProfilerMarkerDataUnit unitType = ((ProfilerRecorderDescription)(ref description)).UnitType;
							switch (unitType - 1)
							{
							case 0:
								<timeRecs>5__8.Add(item12);
								break;
							case 2:
								<countRecs>5__9.Add(item12);
								break;
							case 1:
								<memRecs>5__10.Add(item12);
								break;
							}
						}
						Camera.onPreRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreRender, (Delegate?)new CameraCallback(costProbe.OnCamPre));
						Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(costProbe.OnCamPost));
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 3;
						return true;
					}
					case 3:
						<>1__state = -1;
						Progress = 0.03f;
						<timeTotals>5__11 = new double[<timeRecs>5__8.Count];
						<countTotals>5__12 = new long[<countRecs>5__9.Count];
						<memTotals>5__13 = new long[<memRecs>5__10.Count];
						<gen0Start>5__14 = GC.CollectionCount(0);
						<gen1Start>5__15 = GC.CollectionCount(1);
						<monoStart>5__16 = Profiler.GetMonoUsedSizeLong();
						<worstFrameMs>5__17 = 0f;
						ModTiming.Reset();
						<frames>5__18 = new List<float>(2048);
						<elapsed>5__19 = 0f;
						goto IL_06f2;
					case 4:
						<>1__state = -1;
						goto IL_06f2;
					case 5:
						<>1__state = -1;
						<g1Start>5__38 = GC.CollectionCount(1);
						<mStart>5__39 = Profiler.GetMonoUsedSizeLong();
						<worst>5__40 = 0f;
						<fr>5__41 = new List<float>(2048);
						<el>5__42 = 0f;
						goto IL_0e1b;
					case 6:
						<>1__state = -1;
						goto IL_0e1b;
					case 7:
						<>1__state = -1;
						ScriptTiming.Reset();
						<s>5__37 = 0;
						<el>5__42 = 0f;
						goto IL_2073;
					case 8:
						<>1__state = -1;
						goto IL_2073;
					case 9:
						<>1__state = -1;
						<>8__1.autoSample = default(Sample);
						<>2__current = costProbe.SampleFrames(3f, delegate(Sample v)
						{
							<>8__1.autoSample = v;
						});
						<>1__state = 10;
						return true;
					case 10:
						<>1__state = -1;
						<sweepResults>5__35.Add(("Auto", <>8__1.autoSample.AvgMs, Settings.ResolvedShadowDistance, Settings.ResolvedLightDistance, <origPreset>5__4 == QualityPreset.Auto));
						SweepProgress();
						Settings.ApplyPreset(QualityPreset.Ultra);
						Settings.ResolvedUpscaleMode = UpscaleMode.DLAA;
						Settings.ResolvedRenderScale = 100;
						Settings.ResolvedFogMultiplier = 1f;
						QualityPatch.ApplyFogAndDrawDistance();
						SceneOptimizer.Apply();
						QualityPatch.ApplyQualitySettings();
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 11;
						return true;
					case 11:
						<>1__state = -1;
						<>7__wrap44 = <upscalers>5__32.GetEnumerator();
						<>1__state = -3;
						goto IL_2737;
					case 12:
						<>1__state = -3;
						<>8__2.s = default(Sample);
						<>2__current = costProbe.SampleFrames(3f, delegate(Sample v)
						{
							<>8__2.s = v;
						});
						<>1__state = 13;
						return true;
					case 13:
						<>1__state = -3;
						<sweepResults>5__35.Add(($"{<mode>5__46}", <>8__2.s.AvgMs, Settings.ResolvedShadowDistance, Settings.ResolvedLightDistance, <mode>5__46 == <origUpscaler>5__5 && <origPreset>5__4 == Settings.Preset));
						SweepProgress();
						<>8__2 = null;
						goto IL_2737;
					case 14:
						<>1__state = -1;
						<>8__3.ps = default(Sample);
						<>2__current = costProbe.SampleFrames(3f, delegate(Sample v)
						{
							<>8__3.ps = v;
						});
						<>1__state = 15;
						return true;
					case 15:
						<>1__state = -1;
						<sweepResults>5__35.Add(($"{<p>5__49}@{<el>5__42:F1}x", <>8__3.ps.AvgMs, Settings.ResolvedShadowDistance, Settings.ResolvedLightDistance, false));
						if (<p>5__49 == QualityPreset.Potato && Mathf.Approximately(<el>5__42, 1.1f))
						{
							<potatoSample>5__36 = <>8__3.ps;
						}
						SweepProgress();
						<>8__3 = null;
						<g1Start>5__38++;
						goto IL_2915;
					case 16:
						<>1__state = -1;
						<>8__1.vanillaSample = default(Sample);
						<>2__current = costProbe.SampleFrames(3f, delegate(Sample v)
						{
							<>8__1.vanillaSample = v;
						});
						<>1__state = 17;
						return true;
					case 17:
						<>1__state = -1;
						<sweepResults>5__35.Add(("Vanilla (F10)", <>8__1.vanillaSample.AvgMs, QualitySettings.shadowDistance, 0f, false));
						SweepProgress();
						Settings.ModEnabled = <origModEnabled>5__7;
						Settings.Preset = <origPreset>5__4;
						Settings.UpscaleModeSetting = <origUpscaler>5__5;
						Settings.FogDistanceMultiplier = <origFog>5__6;
						SceneOptimizer.Apply();
						QualityPatch.ApplyQualitySettings();
						QualityPatch.ApplyFogAndDrawDistance();
						costProbe.RestoreFrameLimit();
						costProbe.RestorePresetRevertSuppression();
						costProbe._sweepSmoothActive = false;
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 18;
						return true;
					case 18:
					{
						<>1__state = -1;
						float num2 = <sweepResults>5__35.Min<(string, float, float, float, bool)>(((string label, float ms, float shadowD, float lightD, bool isActive) r) => r.ms);
						foreach (var item14 in <sweepResults>5__35)
						{
							string item = item14.label;
							float item2 = item14.ms;
							float item3 = item14.shadowD;
							float item4 = item14.lightD;
							string text = (item14.isActive ? " (active)" : "");
							string text2 = (Mathf.Approximately(item2, num2) ? " ← fastest" : $"  {item2 - num2:+0.00;-0.00}");
							string text3 = ((item4 > 0f) ? $"  shadowD={item3:F0}m lightD={item4:F0}m" : $"  shadowD={item3:F0}m");
							<>8__1.report.AppendLine($"  {item,-16} {item2,6:F2} ms{text3}{text}{text2}");
						}
						float num3 = <sweepResults>5__35.Where<(string, float, float, float, bool)>(((string label, float ms, float shadowD, float lightD, bool isActive) r) => r.label != "Vanilla (F10)").Min<(string, float, float, float, bool)>(((string label, float ms, float shadowD, float lightD, bool isActive) r) => r.ms) - <>8__1.vanillaSample.AvgMs;
						float num4 = <potatoSample>5__36.AvgMs - <>8__1.vanillaSample.AvgMs;
						<>8__1.report.AppendLine($"  Mod overhead vs vanilla (best mod mode): {num3:+0.00;-0.00} ms");
						<>8__1.report.AppendLine($"  Potato vs vanilla:                       {num4:+0.00;-0.00} ms   (negative = Potato wins)");
						<>8__1.report.AppendLine();
						<>8__1.report.AppendLine("== Optimization opportunities (ranked by likely impact) ==");
						BuildOpportunities(<>8__1.report, <timeStats>5__21, <>8__1.countStats, <perFrameMem>5__29, <scene>5__30, <scriptTimings>5__31);
						<>8__1.report.AppendLine();
						AppendConfigFiles(<>8__1.report);
						string text4 = <>8__1.report.ToString();
						bool flag = false;
						try
						{
							File.AppendAllText(OutputPath, text4);
						}
						catch (Exception ex)
						{
							Plugin.Log.LogWarning((object)("Cost probe save failed: " + ex.Message));
						}
						try
						{
							flag = TrySystemClipboard(text4);
						}
						catch (Exception ex2)
						{
							Plugin.Log.LogWarning((object)("Clipboard copy failed: " + ex2.Message));
						}
						Plugin.Log.LogInfo((object)(flag ? ("Cost probe: appended to " + OutputPath + " (copied to clipboard)") : ("Cost probe: appended to " + OutputPath + " (clipboard unavailable — read the file)")));
						Cursor.lockState = <savedLockState>5__2;
						Cursor.visible = <savedVisible>5__3;
						Status = (flag ? "Done (clipboard)" : "Done (file only)");
						Progress = 1f;
						Running = false;
						<>2__current = (object)new WaitForSeconds(5f);
						<>1__state = 19;
						return true;
					}
					case 19:
						{
							<>1__state = -1;
							Status = "";
							return false;
						}
						IL_2737:
						if (<>7__wrap44.MoveNext())
						{
							<mode>5__46 = <>7__wrap44.Current;
							<>8__2 = new <>c__DisplayClass39_2();
							Status = $"Sweep: {<mode>5__46}";
							Settings.UpscaleModeSetting = <mode>5__46;
							<>2__current = (object)new WaitForSeconds(1.5f);
							<>1__state = 12;
							return true;
						}
						<>m__Finally1();
						<>7__wrap44 = default(List<UpscaleMode>.Enumerator);
						<potatoSample>5__36 = default(Sample);
						<>7__wrap46 = <fogPasses>5__34;
						<s>5__37 = 0;
						goto IL_293d;
						IL_0e1b:
						if (<el>5__42 < 8f)
						{
							float unscaledDeltaTime = Time.unscaledDeltaTime;
							<fr>5__41.Add(unscaledDeltaTime);
							<el>5__42 += unscaledDeltaTime;
							float num5 = unscaledDeltaTime * 1000f;
							if (num5 > <worst>5__40)
							{
								<worst>5__40 = num5;
							}
							Progress = 0.25f + 0.04f * ((float)(<s>5__37 - 1) + <el>5__42 / 8f);
							<>2__current = null;
							<>1__state = 6;
							return true;
						}
						sample = ComputeSample(<fr>5__41);
						<abMs>5__23[<s>5__37] = sample.AvgMs;
						<abFps>5__24[<s>5__37] = sample.AvgFps;
						<abWorst>5__25[<s>5__37] = <worst>5__40;
						<abGen1Arr>5__26[<s>5__37] = GC.CollectionCount(1) - <g1Start>5__38;
						<abMonoArr>5__27[<s>5__37] = (Profiler.GetMonoUsedSizeLong() - <mStart>5__39) / 1024;
						<fr>5__41 = null;
						<s>5__37++;
						goto IL_0ec6;
						IL_293d:
						if (<s>5__37 < <>7__wrap46.Length)
						{
							<el>5__42 = <>7__wrap46[<s>5__37];
							<>7__wrap47 = <presetLadder>5__33;
							<g1Start>5__38 = 0;
							goto IL_2915;
						}
						<>7__wrap46 = null;
						Status = "Sweep: Vanilla (mod OFF)";
						Settings.ModEnabled = false;
						QualityPatch.RestoreVanillaQuality();
						SceneOptimizer.Apply();
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 16;
						return true;
						IL_2915:
						if (<g1Start>5__38 < <>7__wrap47.Length)
						{
							<p>5__49 = <>7__wrap47[<g1Start>5__38];
							<>8__3 = new <>c__DisplayClass39_3();
							Status = $"Sweep: {<p>5__49} @ fog {<el>5__42:F1}x";
							Settings.ApplyPreset(<p>5__49);
							Settings.ResolvedFogMultiplier = <el>5__42;
							QualityPatch.ApplyFogAndDrawDistance();
							SceneOptimizer.Apply();
							QualityPatch.ApplyQualitySettings();
							<>2__current = (object)new WaitForSeconds(1.5f);
							<>1__state = 14;
							return true;
						}
						<>7__wrap47 = null;
						<s>5__37++;
						goto IL_293d;
						IL_220b:
						<>8__1.report.AppendLine($"== Script cost per type (Harmony-instrumented, {4f:F0}s, top {20} types) ==");
						if (<scriptTimings>5__31.Count == 0)
						{
							<>8__1.report.AppendLine("  (no script methods captured)");
						}
						else
						{
							<>8__1.report.AppendLine("  ms/frame   calls/f   µs/call   method");
							foreach (var (text5, num6, num7, num8) in <scriptTimings>5__31)
							{
								<>8__1.report.AppendLine($"  {num6,7:F3}    {num8,5}    {num7,7:F2}   {text5}");
							}
							double num9 = <scriptTimings>5__31.Sum<(string, double, double, int)>(((string label, double totalMs, double perCallUs, int calls) x) => x.totalMs);
							<>8__1.report.AppendLine("  ──────");
							<>8__1.report.AppendLine($"  {num9,7:F3}   (sum of instrumented methods)");
						}
						<>8__1.report.AppendLine();
						costProbe._savedVSyncCount = QualitySettings.vSyncCount;
						costProbe._savedTargetFrameRate = Application.targetFrameRate;
						QualitySettings.vSyncCount = 0;
						Application.targetFrameRate = -1;
						costProbe._frameLimitUncapped = true;
						Settings.PushPresetRevertSuppression();
						costProbe._presetRevertSuppressed = true;
						Status = "Sweep: Auto / DLSS / FSR / Off / Potato / Vanilla";
						<>8__1.report.AppendLine($"== Sweep (Auto = autotune's picks; rest normalized Ultra + DLAA + fog 1.0×, VSync off + uncapped, {3f}s each) ==");
						<upscalers>5__32 = new List<UpscaleMode>();
						if (GPUDetector.IsUpscalerSupported(UpscaleMode.DLSS))
						{
							<upscalers>5__32.Add(UpscaleMode.DLSS);
						}
						if (GPUDetector.IsUpscalerSupported(UpscaleMode.FSR_Temporal))
						{
							<upscalers>5__32.Add(UpscaleMode.FSR_Temporal);
						}
						<upscalers>5__32.Add(UpscaleMode.Off);
						<presetLadder>5__33 = new QualityPreset[5]
						{
							QualityPreset.Potato,
							QualityPreset.Low,
							QualityPreset.Medium,
							QualityPreset.High,
							QualityPreset.Ultra
						};
						<fogPasses>5__34 = new float[2] { 1.1f, 0.3f };
						<sweepResults>5__35 = new List<(string, float, float, float, bool)>();
						<>8__1.totalCells = 1 + <upscalers>5__32.Count + <presetLadder>5__33.Length * <fogPasses>5__34.Length + 1;
						<>8__1.cellIdx = 0;
						costProbe._sweepStartProgress = 0.38f;
						costProbe._sweepEndProgress = 0.98f;
						costProbe._sweepExpectedDuration = (float)<>8__1.totalCells * 4.5f;
						costProbe._sweepStartTime = Time.unscaledTime;
						costProbe._sweepSmoothActive = true;
						Status = "Sweep: Auto (autotune's picks)";
						Settings.ApplyPreset(QualityPreset.Auto);
						QualityPatch.ApplyFogAndDrawDistance();
						SceneOptimizer.Apply();
						QualityPatch.ApplyQualitySettings();
						<>2__current = (object)new WaitForSeconds(1.5f);
						<>1__state = 9;
						return true;
						IL_2073:
						if (<el>5__42 < 4f)
						{
							<el>5__42 += Time.unscaledDeltaTime;
							<s>5__37++;
							Progress = 0.28f + 0.09f * (<el>5__42 / 4f);
							<>2__current = null;
							<>1__state = 8;
							return true;
						}
						foreach (MethodInfo item15 in <patched>5__44)
						{
							try
							{
								<harmony>5__43.Unpatch((MethodBase)item15, (HarmonyPatchType)1, <harmony>5__43.Id);
							}
							catch
							{
							}
							try
							{
								<harmony>5__43.Unpatch((MethodBase)item15, (HarmonyPatchType)2, <harmony>5__43.Id);
							}
							catch
							{
							}
						}
						num10 = 1000.0 / (double)Stopwatch.Frequency;
						num11 = Mathf.Max(1, <s>5__37);
						foreach (MethodInfo item16 in <patched>5__44)
						{
							var (num12, num13) = ScriptTiming.Read(item16);
							if (num13 != 0)
							{
								double item5 = (double)num12 * num10 / (double)num11;
								double item6 = ((num13 == 0) ? 0.0 : ((double)num12 * 1000000.0 / (double)Stopwatch.Frequency / (double)num13));
								string item7 = item16.DeclaringType.Name + "." + item16.Name;
								<scriptTimings>5__31.Add((item7, item5, item6, num13 / num11));
							}
						}
						<scriptTimings>5__31.Sort(((string label, double totalMs, double perCallUs, int calls) a, (string label, double totalMs, double perCallUs, int calls) b) => b.totalMs.CompareTo(a.totalMs));
						ScriptTiming.Clear();
						<harmony>5__43 = null;
						<patched>5__44 = null;
						goto IL_220b;
						IL_06f2:
						if (<elapsed>5__19 < 8f)
						{
							float unscaledDeltaTime2 = Time.unscaledDeltaTime;
							<frames>5__18.Add(unscaledDeltaTime2);
							<elapsed>5__19 += unscaledDeltaTime2;
							float num14 = unscaledDeltaTime2 * 1000f;
							if (num14 > <worstFrameMs>5__17)
							{
								<worstFrameMs>5__17 = num14;
							}
							Progress = 0.03f + 0.22f * (<elapsed>5__19 / 8f);
							for (int i = 0; i < <timeRecs>5__8.Count; i++)
							{
								ref double reference = ref <timeTotals>5__11[i];
								double num15 = reference;
								tuple3 = <timeRecs>5__8[i];
								reference = num15 + (double)((ProfilerRecorder)(ref tuple3.Item1)).LastValue;
							}
							for (int j = 0; j < <countRecs>5__9.Count; j++)
							{
								ref long reference2 = ref <countTotals>5__12[j];
								long num16 = reference2;
								tuple3 = <countRecs>5__9[j];
								reference2 = num16 + ((ProfilerRecorder)(ref tuple3.Item1)).LastValue;
							}
							for (int k = 0; k < <memRecs>5__10.Count; k++)
							{
								ref long reference3 = ref <memTotals>5__13[k];
								long num17 = reference3;
								tuple3 = <memRecs>5__10[k];
								reference3 = num17 + ((ProfilerRecorder)(ref tuple3.Item1)).LastValue;
							}
							<>2__current = null;
							<>1__state = 4;
							return true;
						}
						<modTimingSnapshot>5__20 = ModTiming.Read().ToList();
						num18 = GC.CollectionCount(0) - <gen0Start>5__14;
						num19 = GC.CollectionCount(1) - <gen1Start>5__15;
						monoUsedSizeLong = Profiler.GetMonoUsedSizeLong();
						Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreRender, (Delegate?)new CameraCallback(costProbe.OnCamPre));
						Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(costProbe.OnCamPost));
						Progress = 0.25f;
						num20 = Mathf.Max(1, <frames>5__18.Count);
						<timeStats>5__21 = new List<(string, string, double)>(<timeRecs>5__8.Count);
						<>8__1.countStats = new List<(string, string, double)>(<countRecs>5__9.Count);
						<memStats>5__22 = new List<(string, string, double)>(<memRecs>5__10.Count);
						for (int l = 0; l < <timeRecs>5__8.Count; l++)
						{
							<timeStats>5__21.Add((<timeRecs>5__8[l].name, <timeRecs>5__8[l].cat, <timeTotals>5__11[l] / (double)num20 / 1000000.0));
						}
						for (int m = 0; m < <countRecs>5__9.Count; m++)
						{
							<>8__1.countStats.Add((<countRecs>5__9[m].name, <countRecs>5__9[m].cat, (double)<countTotals>5__12[m] / (double)num20));
						}
						for (int n = 0; n < <memRecs>5__10.Count; n++)
						{
							<memStats>5__22.Add((<memRecs>5__10[n].name, <memRecs>5__10[n].cat, (double)<memTotals>5__13[n] / (double)num20));
						}
						for (int num21 = 0; num21 < <timeRecs>5__8.Count; num21++)
						{
							tuple3 = <timeRecs>5__8[num21];
							((ProfilerRecorder)(ref tuple3.Item1)).Dispose();
						}
						for (int num22 = 0; num22 < <countRecs>5__9.Count; num22++)
						{
							tuple3 = <countRecs>5__9[num22];
							((ProfilerRecorder)(ref tuple3.Item1)).Dispose();
						}
						for (int num23 = 0; num23 < <memRecs>5__10.Count; num23++)
						{
							tuple3 = <memRecs>5__10[num23];
							((ProfilerRecorder)(ref tuple3.Item1)).Dispose();
						}
						sample2 = ComputeSample(<frames>5__18);
						<timeStats>5__21.Sort(((string name, string cat, double ms) a, (string name, string cat, double ms) b) => b.ms.CompareTo(a.ms));
						<>8__1.countStats.Sort(((string name, string cat, double n) a, (string name, string cat, double n) b) => b.n.CompareTo(a.n));
						<memStats>5__22.Sort(((string name, string cat, double bytes) a, (string name, string cat, double bytes) b) => b.bytes.CompareTo(a.bytes));
						num24 = LookupMs(<timeStats>5__21, "CPU Main Thread Frame Time");
						num25 = LookupMs(<timeStats>5__21, "CPU Render Thread Frame Time");
						num26 = LookupMs(<timeStats>5__21, "CPU Total Frame Time");
						num27 = LookupMs(<timeStats>5__21, "GPU Frame Time");
						if (num27 > 100.0 || num27 < 0.0)
						{
							num27 = 0.0;
						}
						text6 = ((num27 <= 0.0) ? "CPU (main thread) [GPU marker unavailable]" : ((num27 > num24 + 0.2) ? "GPU" : ((num24 > num27 + 0.2) ? "CPU (main thread)" : "balanced CPU/GPU")));
						<>8__1.report.AppendLine($"Baseline:     {sample2.AvgMs:F2} ms ({sample2.AvgFps:F0} fps)  1%={sample2.P1Low:F0} fps  0.1%={sample2.P01Low:F0} fps  worstFrame={<worstFrameMs>5__17:F1} ms  ({sample2.FrameCount} frames)");
						if (num26 > 0.0)
						{
							<>8__1.report.AppendLine($"CPU total:    {num26:F2} ms    main={num24:F2}   render={num25:F2}");
						}
						if (num27 > 0.0)
						{
							<>8__1.report.AppendLine($"GPU total:    {num27:F2} ms");
						}
						<>8__1.report.AppendLine("Bottleneck:   " + text6);
						num28 = (monoUsedSizeLong - <monoStart>5__16) / 1024;
						num29 = (float)num18 / 8f;
						<>8__1.report.AppendLine($"GC:           gen0={num18} gen1={num19} over {8f:F0}s  ({num29:F2}/s)  mono Δ={num28:+0;-0} KB");
						<>8__1.report.AppendLine();
						<abMs>5__23 = new float[4] { sample2.AvgMs, 0f, 0f, 0f };
						<abFps>5__24 = new float[4] { sample2.AvgFps, 0f, 0f, 0f };
						<abWorst>5__25 = new float[4] { <worstFrameMs>5__17, 0f, 0f, 0f };
						<abGen1Arr>5__26 = new int[4] { num19, 0, 0, 0 };
						<abMonoArr>5__27 = new long[4] { num28, 0L, 0L, 0L };
						<abOn>5__28 = new bool[4] { true, false, true, false };
						<s>5__37 = 1;
						goto IL_0ec6;
						IL_0ec6:
						if (<s>5__37 < 4)
						{
							Status = string.Format("A/B sample {0}/4 (patches {1})", <s>5__37 + 1, <abOn>5__28[<s>5__37] ? "ON" : "OFF");
							Settings.AllocationFixesEnabled = <abOn>5__28[<s>5__37];
							<>2__current = (object)new WaitForSeconds(1.5f);
							<>1__state = 5;
							return true;
						}
						Settings.AllocationFixesEnabled = true;
						num30 = (<abMs>5__23[0] + <abMs>5__23[2]) / 2f;
						num31 = (<abMs>5__23[1] + <abMs>5__23[3]) / 2f;
						num32 = (<abWorst>5__25[0] + <abWorst>5__25[2]) / 2f;
						num33 = (<abWorst>5__25[1] + <abWorst>5__25[3]) / 2f;
						num34 = (<abMonoArr>5__27[0] + <abMonoArr>5__27[2]) / 2;
						num35 = (<abMonoArr>5__27[1] + <abMonoArr>5__27[3]) / 2;
						num36 = <abMs>5__23[2] - <abMs>5__23[0];
						<>8__1.report.AppendLine("== A/B compare (allocation patches on/off, ON-OFF-ON-OFF, same scene) ==");
						for (int num37 = 0; num37 < 4; num37++)
						{
							string text7 = (<abOn>5__28[num37] ? "ON " : "OFF");
							<>8__1.report.AppendLine($"  #{num37 + 1} {text7}:  {<abMs>5__23[num37]:F2} ms ({<abFps>5__24[num37]:F0} fps)  worst={<abWorst>5__25[num37]:F1}  gen1={<abGen1Arr>5__26[num37]}  mono Δ={<abMonoArr>5__27[num37]:+0;-0} KB");
						}
						<>8__1.report.AppendLine($"  ON  avg :  {num30:F2} ms   worst {num32:F1}   mono {num34:+0;-0} KB");
						<>8__1.report.AppendLine($"  OFF avg :  {num31:F2} ms   worst {num33:F1}   mono {num35:+0;-0} KB");
						<>8__1.report.AppendLine($"  Patches effect (OFF − ON): {num31 - num30:+0.00;-0.00} ms   worst {num33 - num32:+0.0;-0.0} ms   mono {num35 - num34:+0;-0} KB  (positive = patches helped)");
						<>8__1.report.AppendLine($"  Order bias check (ON#2 − ON#1): {num36:+0.00;-0.00} ms  (large negative = consistent second-window-faster bias, treat OFF − ON delta with caution)");
						<>8__1.report.AppendLine();
						<>8__1.report.AppendLine("== Frame cost — profiler markers ranked highest→lowest (ms/frame) ==");
						num38 = 0;
						foreach (var (arg, arg2, num39) in <timeStats>5__21)
						{
							if (!(num39 < 0.01))
							{
								<>8__1.report.AppendLine($"  {num39,7:F2} ms  [{arg2,-12}] {arg}");
								if (++num38 >= 80)
								{
									break;
								}
							}
						}
						if (num38 == 0)
						{
							<>8__1.report.AppendLine("  (no profiler time markers captured — Unity build may strip them)");
						}
						<>8__1.report.AppendLine();
						<>8__1.tickToMsMod = 1000.0 / (double)Stopwatch.Frequency;
						<>8__1.baselineFrames = Mathf.Max(1, <frames>5__18.Count);
						list = (from r in <modTimingSnapshot>5__20
							select (r.name, (double)r.ticks * <>8__1.tickToMsMod / (double)<>8__1.baselineFrames, (float)r.calls / (float)<>8__1.baselineFrames, r.calls) into r
							where r.calls > 0
							orderby r.ms descending
							select r).ToList();
						<>8__1.report.AppendLine($"== Mod-internal cost (Stopwatch spans over {8f:F0}s baseline, ms/frame) ==");
						if (list.Count == 0)
						{
							<>8__1.report.AppendLine("  (no mod spans hit — mod may be disabled or pipeline idle)");
						}
						else
						{
							<>8__1.report.AppendLine("  ms/frame   calls/f   name");
							double num40 = 0.0;
							foreach (var item17 in list)
							{
								<>8__1.report.AppendLine(string.Format("  {0,7:F3}    {1,5:F1}   {2}", item17.Item2, item17.Item3, item17.Item1.Substring("REPOFidelity.".Length)));
								num40 += item17.Item2;
							}
							<>8__1.report.AppendLine("  ──────");
							<>8__1.report.AppendLine($"  {num40,7:F3}   (sum of instrumented mod spans)");
						}
						<>8__1.report.AppendLine();
						<>8__1.report.AppendLine("== Draw stats (per frame avg) ==");
						<>8__1.anyCount = false;
						EmitCount("Draw calls:", "Draw Calls Count");
						EmitCount("Batches:", "Batches Count");
						EmitCount("SetPass calls:", "SetPass Calls Count");
						EmitCount("Triangles:", "Triangles Count");
						EmitCount("Vertices:", "Vertices Count");
						EmitCount("Shadow casters:", "Shadow Casters Count");
						EmitCount("Used textures:", "Used Textures Count");
						EmitCount("Render textures:", "Render Textures Count");
						if (!<>8__1.anyCount)
						{
							<>8__1.report.AppendLine("  (no count markers captured)");
						}
						<>8__1.report.AppendLine();
						if (<>8__1.countStats.Count > 0)
						{
							<>8__1.report.AppendLine("== All count markers, ranked (top 20) ==");
							int num41 = 0;
							foreach (var (arg3, arg4, num42) in <>8__1.countStats)
							{
								if (!(num42 < 1.0))
								{
									<>8__1.report.AppendLine($"  {FmtBig(num42),10}  [{arg4,-12}] {arg3}");
									if (++num41 >= 20)
									{
										break;
									}
								}
							}
							<>8__1.report.AppendLine();
						}
						<perFrameMem>5__29 = <memStats>5__22.Where<(string, string, double)>(((string name, string cat, double bytes) x) => x.name.IndexOf("In Frame", StringComparison.OrdinalIgnoreCase) >= 0 || x.name.IndexOf("Alloc", StringComparison.OrdinalIgnoreCase) >= 0).ToList();
						if (<perFrameMem>5__29.Count > 0)
						{
							<>8__1.report.AppendLine("== Allocations per frame (GC / buffer uploads) ==");
							foreach (var (arg5, arg6, num43) in <perFrameMem>5__29)
							{
								if (!(num43 < 1.0))
								{
									<>8__1.report.AppendLine($"  {FmtBytes(num43),10}  [{arg6,-12}] {arg5}");
								}
							}
							<>8__1.report.AppendLine();
						}
						<>8__1.report.AppendLine("== Per-camera render cost (CPU Stopwatch around onPreRender/onPostRender) ==");
						if (costProbe._camTimings.Count == 0)
						{
							<>8__1.report.AppendLine("  (no camera events fired during sample — unusual)");
						}
						else
						{
							foreach (var item18 in (from kv in costProbe._camTimings
								select (kv.Key, kv.Value.TotalMs / (double)Mathf.Max(1, kv.Value.Frames), kv.Value.Frames) into x
								orderby x.ms descending
								select x).ToList())
							{
								Camera item8 = item18.Item1;
								double item9 = item18.Item2;
								int item10 = item18.Item3;
								string arg7 = (((Object)(object)item8 != (Object)null) ? ((Object)item8).name : "(destroyed)");
								<>8__1.report.AppendLine($"  {item9,7:F2} ms  {arg7}  ({item10} renders)");
							}
						}
						costProbe._camTimings.Clear();
						<>8__1.report.AppendLine();
						<scene>5__30 = GatherSceneMetrics();
						<>8__1.report.AppendLine("== Scene composition ==");
						<>8__1.report.AppendLine($"  Renderers:                     {<scene>5__30.Renderers.Total}");
						<>8__1.report.AppendLine($"    Visible:                       {<scene>5__30.Renderers.Visible} ({Pct(<scene>5__30.Renderers.Visible, <scene>5__30.Renderers.Total)})");
						<>8__1.report.AppendLine($"    Shadow casting:                {<scene>5__30.Renderers.ShadowCasting} ({Pct(<scene>5__30.Renderers.ShadowCasting, <scene>5__30.Renderers.Total)})");
						<>8__1.report.AppendLine($"    Shadow casting + off-screen:   {<scene>5__30.Renderers.ShadowCastingHidden} ({Pct(<scene>5__30.Renderers.ShadowCastingHidden, <scene>5__30.Renderers.Total)})  ← off-screen shadow work");
						<>8__1.report.AppendLine($"    No LODGroup:                   {<scene>5__30.Renderers.NoLODGroup} ({Pct(<scene>5__30.Renderers.NoLODGroup, <scene>5__30.Renderers.Total)})");
						<>8__1.report.AppendLine("    Tris (sum of sharedMesh):      " + FmtBig(<scene>5__30.TotalSceneTris));
						<>8__1.report.AppendLine($"  Skinned mesh renderers:         {<scene>5__30.SkinnedRenderers}");
						<>8__1.report.AppendLine($"  Particle systems:               {<scene>5__30.TotalParticles} total, {<scene>5__30.ActiveParticles} emitting, {FmtBig(<scene>5__30.ActiveParticleCount)} particles alive");
						<>8__1.report.AppendLine($"  Reflection probes:              {<scene>5__30.ReflectionProbes}");
						<>8__1.report.AppendLine($"  Trail / Line renderers:         {<scene>5__30.TrailRenderers} / {<scene>5__30.LineRenderers}");
						<>8__1.report.AppendLine($"  Audio sources (playing):        {<scene>5__30.AudioSourcesPlaying} / {<scene>5__30.AudioSources}");
						<>8__1.report.AppendLine($"  Lights:                         {<scene>5__30.Lights.Active} active, {<scene>5__30.Lights.Shadowing} casting shadow");
						<>8__1.report.AppendLine($"    Directional + shadow:          {<scene>5__30.Lights.Directional}");
						<>8__1.report.AppendLine($"    Point + shadow:                {<scene>5__30.Lights.PointShadow}  (×6 cubemap faces)");
						<>8__1.report.AppendLine($"    Spot + shadow:                 {<scene>5__30.Lights.SpotShadow}");
						<>8__1.report.AppendLine($"  MonoBehaviours w/ Update:       {<scene>5__30.UpdatingBehaviours}");
						<>8__1.report.AppendLine($"  MonoBehaviours w/ LateUpdate:   {<scene>5__30.LateUpdatingBehaviours}");
						<>8__1.report.AppendLine($"  MonoBehaviours w/ FixedUpdate:  {<scene>5__30.FixedUpdatingBehaviours}");
						<>8__1.report.AppendLine();
						AppendMultiplayerSection(<>8__1.report);
						if (<scene>5__30.TopBehaviourTypes.Count > 0)
						{
							<>8__1.report.AppendLine("== MonoBehaviour types with Update, ranked by live instance count (top 20) ==");
							foreach (var (arg8, num44) in <scene>5__30.TopBehaviourTypes.Take(20))
							{
								<>8__1.report.AppendLine($"  {num44,5}×  {arg8}");
							}
							<>8__1.report.AppendLine();
						}
						if (<scene>5__30.LightDetail.Count > 0)
						{
							<>8__1.report.AppendLine("== Per-light shadow cost proxy, ranked (top 20) ==");
							<>8__1.report.AppendLine("  score   type         range     res   shadow     name");
							foreach (LightInfo item19 in <scene>5__30.LightDetail.OrderByDescending((LightInfo x) => x.CostScore).Take(20))
							{
								<>8__1.report.AppendLine($"  {item19.CostScore,5:F0}   {item19.Type,-12} {item19.Range,5:F0}m   {item19.Resolution,5}   {item19.ShadowMode,-8}  {item19.Name}");
							}
							<>8__1.report.AppendLine("  (proxy = faces × res² × range² for shadowers, 0 otherwise — higher = more shadow map work)");
							<>8__1.report.AppendLine();
						}
						<scriptTimings>5__31 = new List<(string, double, double, int)>();
						if (<scene>5__30.TopBehaviourTypes.Count > 0)
						{
							<>c__DisplayClass39_1 CS$<>8__locals0 = new <>c__DisplayClass39_1();
							Status = "Script profiling (Harmony)";
							List<Type> list2 = new List<Type>();
							MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>();
							foreach (MonoBehaviour val in array)
							{
								if (((Behaviour)val).isActiveAndEnabled)
								{
									Type type = ((object)val).GetType();
									if (!list2.Contains(type))
									{
										list2.Add(type);
									}
								}
							}
							CS$<>8__locals0.topSet = (from x in <scene>5__30.TopBehaviourTypes.Take(20)
								select x.typeName).ToHashSet();
							list2 = list2.Where((Type t) => CS$<>8__locals0.topSet.Contains(t.Name)).ToList();
							<harmony>5__43 = new Harmony("REPOFidelity.CostProbe.ScriptTiming");
							MethodInfo method = typeof(ScriptTiming).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public);
							MethodInfo? method2 = typeof(ScriptTiming).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public);
							HarmonyMethod prefix = new HarmonyMethod(method);
							HarmonyMethod postfix = new HarmonyMethod(method2);
							ScriptTiming.Clear();
							<patched>5__44 = new List<MethodInfo>();
							foreach (Type item20 in list2)
							{
								PatchIfPresent(item20, "Update", <harmony>5__43, prefix, postfix, <patched>5__44);
							}
							foreach (Type item21 in list2)
							{
								PatchIfPresent(item21, "LateUpdate", <harmony>5__43, prefix, postfix, <patched>5__44);
							}
							foreach (Type item22 in list2)
							{
								PatchIfPresent(item22, "FixedUpdate", <harmony>5__43, prefix, postfix, <patched>5__44);
							}
							<>2__current = (object)new WaitForSeconds(1.5f);
							<>1__state = 7;
							return true;
						}
						goto IL_220b;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				void EmitCount(string label, string marker)
				{
					double num46 = LookupCount(((<>c__DisplayClass39_0)this).countStats, marker);
					if (!(num46 <= 0.0))
					{
						((<>c__DisplayClass39_0)this).report.AppendLine($"  {label,-22} {FmtBig(num46)}");
						((<>c__DisplayClass39_0)this).anyCount = true;
					}
				}
				void SweepProgress()
				{
					((<>c__DisplayClass39_0)this).cellIdx++;
					Progress = 0.38f + 0.6f * ((float)((<>c__DisplayClass39_0)this).cellIdx / (float)((<>c__DisplayClass39_0)this).totalCells);
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap44).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RunSafe>d__36 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public CostProbe <>4__this;

			private IEnumerator <inner>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RunSafe>d__36(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<inner>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Expected O, but got Unknown
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Expected O, but got Unknown
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Expected O, but got Unknown
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Expected O, but got Unknown
				int num = <>1__state;
				CostProbe costProbe = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
				}
				else
				{
					<>1__state = -1;
					<inner>5__2 = costProbe.Run();
				}
				bool flag;
				try
				{
					flag = <inner>5__2.MoveNext();
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"Cost probe failed: {arg}");
					Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreRender, (Delegate?)new CameraCallback(costProbe.OnCamPre));
					Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(costProbe.OnCamPost));
					costProbe.RestoreFrameLimit();
					costProbe.RestorePresetRevertSuppression();
					Settings.AllocationFixesEnabled = true;
					Running = false;
					Status = "ERROR";
					return false;
				}
				if (!flag)
				{
					return false;
				}
				<>2__current = <inner>5__2.Current;
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SampleFrames>d__52 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float seconds;

			public Action<Sample> onDone;

			private List<float> <frames>5__2;

			private float <elapsed>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SampleFrames>d__52(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<frames>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(1.5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<frames>5__2 = new List<float>(512);
					<elapsed>5__3 = 0f;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (<elapsed>5__3 < seconds)
				{
					float unscaledDeltaTime = Time.unscaledDeltaTime;
					<frames>5__2.Add(unscaledDeltaTime);
					<elapsed>5__3 += unscaledDeltaTime;
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				onDone(ComputeSample(<frames>5__2));
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <WaitForAutotuneIfActive>d__29 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForAutotuneIfActive>d__29(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (!UpscalerManager.BenchmarkActive)
					{
						return false;
					}
					Status = "Waiting for autotune to finish";
					goto IL_004e;
				case 1:
					<>1__state = -1;
					goto IL_004e;
				case 2:
					{
						<>1__state = -1;
						return false;
					}
					IL_004e:
					if (UpscalerManager.BenchmarkActive)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<>2__current = (object)new WaitForSeconds(1.5f);
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static string Status = "";

		internal static float Progress;

		private const float WarmupSeconds = 1.5f;

		private const float SampleSeconds = 8f;

		private const float SettleSeconds = 1.5f;

		private const float UpscalerSampleSeconds = 3f;

		private const float ScriptSampleSeconds = 4f;

		private const int ScriptTopN = 20;

		private static readonly string OutputPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "frame_cost.txt");

		private readonly Dictionary<Camera, CamTiming> _camTimings = new Dictionary<Camera, CamTiming>();

		private int _savedVSyncCount;

		private int _savedTargetFrameRate;

		private bool _frameLimitUncapped;

		private bool _presetRevertSuppressed;

		private float _sweepStartTime;

		private float _sweepExpectedDuration;

		private float _sweepStartProgress;

		private float _sweepEndProgress;

		private bool _sweepSmoothActive;

		private static readonly Dictionary<Type, (bool upd, bool late, bool fixedU)> _methodCache = new Dictionary<Type, (bool, bool, bool)>();

		internal static CostProbe? Instance { get; private set; }

		internal static bool Running { get; private set; }

		internal static void Toggle()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			if (Running)
			{
				Abort();
				return;
			}
			if ((Object)(object)Instance == (Object)null)
			{
				GameObject val = new GameObject("REPOFidelity_CostProbe");
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<CostProbe>();
			}
			((MonoBehaviour)Instance).StartCoroutine(Instance.RunSafe());
		}

		[IteratorStateMachine(typeof(<WaitForAutotuneIfActive>d__29))]
		private IEnumerator WaitForAutotuneIfActive()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForAutotuneIfActive>d__29(0);
		}

		internal static void Abort()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			if (Running)
			{
				if ((Object)(object)Instance != (Object)null)
				{
					((MonoBehaviour)Instance).StopAllCoroutines();
					Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreRender, (Delegate?)new CameraCallback(Instance.OnCamPre));
					Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(Instance.OnCamPost));
					Instance._camTimings.Clear();
					Instance.RestoreFrameLimit();
					Instance.RestorePresetRevertSuppression();
					Settings.AllocationFixesEnabled = true;
				}
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
				Running = false;
				Status = "";
				Plugin.Log.LogInfo((object)"Cost probe cancelled");
			}
		}

		private void RestoreFrameLimit()
		{
			if (_frameLimitUncapped)
			{
				QualitySettings.vSyncCount = _savedVSyncCount;
				Application.targetFrameRate = _savedTargetFrameRate;
				_frameLimitUncapped = false;
			}
		}

		private void RestorePresetRevertSuppression()
		{
			if (_presetRevertSuppressed)
			{
				Settings.PopPresetRevertSuppression();
				_presetRevertSuppressed = false;
			}
		}

		private static void AppendConfigFiles(StringBuilder report)
		{
			string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";
			AppendFileSection(report, "autotune.json", Path.Combine(path, "autotune.json"));
			AppendFileSection(report, "settings.json", Path.Combine(path, "settings.json"));
		}

		private static void AppendFileSection(StringBuilder report, string label, string path)
		{
			report.AppendLine("== " + label + " ==");
			try
			{
				report.AppendLine(File.Exists(path) ? File.ReadAllText(path).TrimEnd() : "(missing)");
			}
			catch (Exception ex)
			{
				report.AppendLine("(read failed: " + ex.Message + ")");
			}
			report.AppendLine();
		}

		private void Update()
		{
			if (!Running)
			{
				return;
			}
			if ((Object)(object)GameDirector.instance != (Object)null)
			{
				GameDirector.instance.SetDisableInput(1f);
			}
			if (_sweepSmoothActive && _sweepExpectedDuration > 0f)
			{
				float num = Mathf.Clamp01((Time.unscaledTime - _sweepStartTime) / _sweepExpectedDuration);
				float num2 = Mathf.Lerp(_sweepStartProgress, _sweepEndProgress, num);
				if (num2 > Progress)
				{
					Progress = num2;
				}
			}
		}

		[IteratorStateMachine(typeof(<RunSafe>d__36))]
		private IEnumerator RunSafe()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RunSafe>d__36(0)
			{
				<>4__this = this
			};
		}

		private void OnCamPre(Camera cam)
		{
			if (Running && !((Object)(object)cam == (Object)null))
			{
				if (!_camTimings.TryGetValue(cam, out CamTiming value))
				{
					value = new CamTiming();
					_camTimings[cam] = value;
				}
				value.Sw.Restart();
			}
		}

		private void OnCamPost(Camera cam)
		{
			if (Running && !((Object)(object)cam == (Object)null) && _camTimings.TryGetValue(cam, out CamTiming value))
			{
				value.Sw.Stop();
				value.TotalMs += value.Sw.Elapsed.TotalMilliseconds;
				value.Frames++;
			}
		}

		[IteratorStateMachine(typeof(<Run>d__39))]
		private IEnumerator Run()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Run>d__39(0)
			{
				<>4__this = this
			};
		}

		private static bool TrySystemClipboard(string text)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			GUIUtility.systemCopyBuffer = text;
			if (GUIUtility.systemCopyBuffer == text)
			{
				return true;
			}
			if ((int)Application.platform == 13)
			{
				return TryLinuxClipboardFallback(text);
			}
			return false;
		}

		private static bool TryLinuxClipboardFallback(string text)
		{
			(string, string)[] array = new(string, string)[3]
			{
				("wl-copy", ""),
				("xclip", "-selection clipboard"),
				("xsel", "--clipboard --input")
			};
			for (int i = 0; i < array.Length; i++)
			{
				var (fileName, arguments) = array[i];
				try
				{
					using Process process = Process.Start(new ProcessStartInfo(fileName, arguments)
					{
						RedirectStandardInput = true,
						UseShellExecute = false,
						CreateNoWindow = true
					});
					if (process != null)
					{
						process.StandardInput.Write(text);
						process.StandardInput.Close();
						if (process.WaitForExit(2000) && process.ExitCode == 0)
						{
							return true;
						}
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static void PatchIfPresent(Type type, string methodName, Harmony harmony, HarmonyMethod prefix, HarmonyMethod postfix, List<MethodInfo> patched)
		{
			MethodInfo method = type.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method == null)
			{
				return;
			}
			try
			{
				ScriptTiming.Register(method);
				harmony.Patch((MethodBase)method, prefix, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				patched.Add(method);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Probe: can't patch " + type.Name + "." + methodName + ": " + ex.Message));
			}
		}

		private static void AppendMultiplayerSection(StringBuilder report)
		{
			//IL_0027: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			if (array.Length == 0)
			{
				return;
			}
			Camera main = Camera.main;
			Vector3 val = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : Vector3.zero);
			float resolvedEffectiveFogEnd = Settings.ResolvedEffectiveFogEnd;
			float num = ((resolvedEffectiveFogEnd > 0f) ? (resolvedEffectiveFogEnd * 1.1f) : float.PositiveInfinity);
			report.AppendLine($"== Multiplayer / per-player (fog cutoff {num:F0}m) ==");
			report.AppendLine($"  PlayerAvatars: {array.Length}");
			int num2 = 0;
			int num3 = 0;
			PlayerAvatar[] array2 = array;
			foreach (PlayerAvatar val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				float num4 = (((Object)(object)main != (Object)null) ? Vector3.Distance(((Component)val2).transform.position, val) : 0f);
				bool flag = num4 > num;
				if (flag)
				{
					num2++;
				}
				int num5 = 0;
				Renderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Renderer>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					if ((int)componentsInChildren[j].shadowCastingMode != 0)
					{
						num5++;
					}
				}
				num3 += num5;
				string text = (val2.isLocal ? "local" : "remote");
				string text2 = (flag ? " past-fog" : "");
				report.AppendLine(string.Format("    [{0,-6}] {1,-20} {2,5:F0}m  {3,3} casters{4}", text, val2.playerName ?? "(unknown)", num4, num5, text2));
			}
			report.AppendLine($"  Total shadow-casting player renderers: {num3}  ({num2} players past fog)");
			FlashlightController[] array3 = Object.FindObjectsOfType<FlashlightController>();
			if (array3.Length != 0)
			{
				List<(FlashlightController, float)> list = new List<(FlashlightController, float)>();
				FlashlightController[] array4 = array3;
				foreach (FlashlightController val3 in array4)
				{
					if (!((Object)(object)val3.spotlight == (Object)null))
					{
						float item = (((Object)(object)main != (Object)null) ? Vector3.Distance(((Component)val3.spotlight).transform.position, val) : 0f);
						list.Add((val3, item));
					}
				}
				list.Sort(((FlashlightController fl, float dist) a, (FlashlightController fl, float dist) b) => a.dist.CompareTo(b.dist));
				int num6 = 0;
				int num7 = 0;
				int num8 = 0;
				foreach (var item2 in list)
				{
					if (item2.Item2 > num)
					{
						num8++;
					}
					else if (num6 < 4)
					{
						num6++;
					}
					else
					{
						num7++;
					}
				}
				report.AppendLine($"  Flashlights: {list.Count} total — {num6} within budget, {num7} culled over budget, {num8} past fog");
			}
			int num9 = Object.FindObjectsOfType<PlayerAvatarEyelids>().Length;
			int num10 = Object.FindObjectsOfType<PlayerExpression>().Length;
			int num11 = Object.FindObjectsOfType<PlayerAvatarOverchargeVisuals>().Length;
			report.AppendLine($"  Cosmetic components: Eyelids×{num9}  Expression×{num10}  Overcharge×{num11}");
			report.AppendLine("  (components past fog cutoff skip their Update — see per-player distances above)");
			report.AppendLine();
		}

		private static double LookupMs(List<(string name, string cat, double ms)> list, string marker)
		{
			foreach (var (text, _, result) in list)
			{
				if (text == marker)
				{
					return result;
				}
			}
			return 0.0;
		}

		private static double LookupCount(List<(string name, string cat, double n)> list, string marker)
		{
			foreach (var (text, _, result) in list)
			{
				if (text == marker)
				{
					return result;
				}
			}
			return 0.0;
		}

		private static double LookupBytes(List<(string name, string cat, double bytes)> list, string marker)
		{
			foreach (var (text, _, result) in list)
			{
				if (text == marker)
				{
					return result;
				}
			}
			return 0.0;
		}

		private static string FmtBig(double n)
		{
			if (n >= 1000000.0)
			{
				return $"{n / 1000000.0:F2}M";
			}
			if (n >= 1000.0)
			{
				return $"{n / 1000.0:F1}K";
			}
			return $"{n:F0}";
		}

		private static string FmtBytes(double b)
		{
			if (b >= 1048576.0)
			{
				return $"{b / 1048576.0:F2} MB";
			}
			if (b >= 1024.0)
			{
				return $"{b / 1024.0:F1} KB";
			}
			return $"{b:F0} B";
		}

		private static string Pct(int n, int total)
		{
			if (total <= 0)
			{
				return "-";
			}
			return $"{100.0 * (double)n / (double)total:F0}%";
		}

		[IteratorStateMachine(typeof(<SampleFrames>d__52))]
		private IEnumerator SampleFrames(float seconds, Action<Sample> onDone)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SampleFrames>d__52(0)
			{
				seconds = seconds,
				onDone = onDone
			};
		}

		private static Sample ComputeSample(List<float> frames)
		{
			if (frames.Count == 0)
			{
				return default(Sample);
			}
			float num = 0f;
			for (int i = 0; i < frames.Count; i++)
			{
				num += frames[i];
			}
			float num2 = num / (float)frames.Count * 1000f;
			frames.Sort();
			Sample result = default(Sample);
			result.AvgFps = 1000f / num2;
			result.AvgMs = num2;
			result.P1Low = PercentileLow(frames, 0.01f);
			result.P01Low = PercentileLow(frames, 0.001f);
			result.FrameCount = frames.Count;
			return result;
		}

		private static float PercentileLow(List<float> sorted, float percentile)
		{
			int num = Mathf.Max(1, Mathf.CeilToInt((float)sorted.Count * percentile));
			float num2 = 0f;
			for (int num3 = sorted.Count - 1; num3 >= sorted.Count - num; num3--)
			{
				num2 += sorted[num3];
			}
			return 1f / (num2 / (float)num);
		}

		private static (bool upd, bool late, bool fixedU) GetMethodFlags(Type t)
		{
			if (_methodCache.TryGetValue(t, out (bool, bool, bool) value))
			{
				return value;
			}
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			Type type = t;
			while (type != null && type != typeof(MonoBehaviour) && type != typeof(Behaviour) && type != typeof(object))
			{
				if (!flag && type.GetMethod("Update", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null)
				{
					flag = true;
				}
				if (!flag2 && type.GetMethod("LateUpdate", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null)
				{
					flag2 = true;
				}
				if (!flag3 && type.GetMethod("FixedUpdate", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null)
				{
					flag3 = true;
				}
				if (flag && flag2 && flag3)
				{
					break;
				}
				type = type.BaseType;
			}
			(bool, bool, bool) tuple = (flag, flag2, flag3);
			_methodCache[t] = tuple;
			return tuple;
		}

		private static SceneMetrics GatherSceneMetrics()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Invalid comparison between Unknown and I4
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected I4, but got Unknown
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Invalid comparison between Unknown and I4
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected I4, but got Unknown
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Invalid comparison between Unknown and I4
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Invalid comparison between Unknown and I4
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			SceneMetrics sceneMetrics = default(SceneMetrics);
			sceneMetrics.LightDetail = new List<LightInfo>();
			sceneMetrics.TopBehaviourTypes = new List<(string, int)>();
			SceneMetrics result = sceneMetrics;
			MeshRenderer[] array = Object.FindObjectsOfType<MeshRenderer>();
			foreach (MeshRenderer obj in array)
			{
				result.Renderers.Total++;
				bool isVisible = ((Renderer)obj).isVisible;
				bool num = (int)((Renderer)obj).shadowCastingMode > 0;
				if (isVisible)
				{
					result.Renderers.Visible++;
				}
				if (num)
				{
					result.Renderers.ShadowCasting++;
				}
				if (num && !isVisible)
				{
					result.Renderers.ShadowCastingHidden++;
				}
				if ((Object)(object)((Component)obj).GetComponentInParent<LODGroup>() == (Object)null)
				{
					result.Renderers.NoLODGroup++;
				}
				MeshFilter component = ((Component)obj).GetComponent<MeshFilter>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
				{
					Mesh sharedMesh = component.sharedMesh;
					long num2 = 0L;
					for (int j = 0; j < sharedMesh.subMeshCount; j++)
					{
						num2 += sharedMesh.GetIndexCount(j);
					}
					result.TotalSceneTris += num2 / 3;
				}
			}
			result.SkinnedRenderers = Object.FindObjectsOfType<SkinnedMeshRenderer>().Length;
			ParticleSystem[] array2 = Object.FindObjectsOfType<ParticleSystem>();
			foreach (ParticleSystem val in array2)
			{
				result.TotalParticles++;
				if (val.isPlaying && val.particleCount > 0)
				{
					result.ActiveParticles++;
					result.ActiveParticleCount += val.particleCount;
				}
			}
			result.ReflectionProbes = Object.FindObjectsOfType<ReflectionProbe>().Length;
			result.TrailRenderers = Object.FindObjectsOfType<TrailRenderer>().Length;
			result.LineRenderers = Object.FindObjectsOfType<LineRenderer>().Length;
			AudioSource[] array3 = Object.FindObjectsOfType<AudioSource>();
			foreach (AudioSource obj2 in array3)
			{
				result.AudioSources++;
				if (obj2.isPlaying)
				{
					result.AudioSourcesPlaying++;
				}
			}
			Light[] array4 = Object.FindObjectsOfType<Light>();
			foreach (Light val2 in array4)
			{
				if (!((Behaviour)val2).enabled || !((Component)val2).gameObject.activeInHierarchy)
				{
					continue;
				}
				result.Lights.Active++;
				bool flag = (int)val2.shadows > 0;
				if (flag)
				{
					result.Lights.Shadowing++;
				}
				LightType type = val2.type;
				switch ((int)type)
				{
				case 1:
					if (flag)
					{
						result.Lights.Directional++;
					}
					break;
				case 2:
					if (flag)
					{
						result.Lights.PointShadow++;
					}
					break;
				case 0:
					if (flag)
					{
						result.Lights.SpotShadow++;
					}
					break;
				}
				int num3 = val2.shadowCustomResolution;
				if (num3 <= 0)
				{
					LightShadowResolution shadowResolution = val2.shadowResolution;
					num3 = (int)shadowResolution switch
					{
						3 => 4096, 
						2 => 2048, 
						1 => 1024, 
						0 => 512, 
						_ => 1024, 
					};
				}
				float num4 = (((int)val2.type == 2) ? 6f : (((int)val2.type == 1) ? ((float)QualitySettings.shadowCascades) : 1f));
				float num5 = (((int)val2.type == 1) ? 2500f : (val2.range * val2.range));
				float costScore = (flag ? (num4 * ((float)num3 / 1024f) * ((float)num3 / 1024f) * (num5 / 100f)) : 0f);
				List<LightInfo> lightDetail = result.LightDetail;
				LightInfo item = new LightInfo
				{
					Name = ((Object)val2).name
				};
				type = val2.type;
				item.Type = ((object)(LightType)(ref type)).ToString();
				item.Range = val2.range;
				item.Resolution = num3;
				object shadowMode;
				if (!flag)
				{
					shadowMode = "Off";
				}
				else
				{
					LightShadows shadows = val2.shadows;
					shadowMode = ((object)(LightShadows)(ref shadows)).ToString();
				}
				item.ShadowMode = (string)shadowMode;
				item.CostScore = costScore;
				lightDetail.Add(item);
			}
			Dictionary<Type, int> dictionary = new Dictionary<Type, int>();
			MonoBehaviour[] array5 = Object.FindObjectsOfType<MonoBehaviour>();
			foreach (MonoBehaviour val3 in array5)
			{
				if (!((Behaviour)val3).isActiveAndEnabled)
				{
					continue;
				}
				Type type2 = ((object)val3).GetType();
				var (flag2, flag3, flag4) = GetMethodFlags(type2);
				if (flag2)
				{
					result.UpdatingBehaviours++;
				}
				if (flag3)
				{
					result.LateUpdatingBehaviours++;
				}
				if (flag4)
				{
					result.FixedUpdatingBehaviours++;
				}
				if (flag2)
				{
					if (!dictionary.TryGetValue(type2, out var value))
					{
						value = 0;
					}
					dictionary[type2] = value + 1;
				}
			}
			foreach (KeyValuePair<Type, int> item2 in dictionary.OrderByDescending((KeyValuePair<Type, int> k) => k.Value))
			{
				result.TopBehaviourTypes.Add((item2.Key.Name, item2.Value));
			}
			return result;
		}

		private static void BuildOpportunities(StringBuilder r, List<(string name, string cat, double ms)> timeStats, List<(string name, string cat, double n)> countStats, List<(string name, string cat, double bytes)> memStats, SceneMetrics scene, List<(string label, double totalMs, double perCallUs, int calls)> scriptTimings)
		{
			List<(double, string)> list = new List<(double, string)>();
			double num = LookupMs(timeStats, "Physics.Simulate") + LookupMs(timeStats, "FixedUpdate.PhysicsFixedUpdate");
			double num2 = LookupMs(timeStats, "Animators.Update");
			double num3 = LookupMs(timeStats, "Particles.Update");
			double num4 = LookupMs(timeStats, "Camera.ImageEffects");
			double num5 = LookupBytes(memStats, "GC Allocated In Frame");
			int num6 = 0;
			foreach (var (text, num7, num8, num9) in scriptTimings)
			{
				if (num7 < 0.05 || num6 >= 3)
				{
					break;
				}
				list.Add((num7 * 200.0, $"Top script cost: {text} — {num7:F3} ms/frame ({num9} calls at {num8:F1} µs each). " + "Rate-limit, cache, or Harmony-prefix-skip when state hasn't changed."));
				num6++;
			}
			if (scene.Renderers.ShadowCastingHidden > 0 && scene.Renderers.Total > 0)
			{
				double num10 = (double)scene.Renderers.ShadowCastingHidden / (double)scene.Renderers.Total;
				list.Add((num10 * 300.0, $"{scene.Renderers.ShadowCastingHidden} off-screen shadow casters ({num10 * 100.0:F0}% of scene renderers). " + "Prefabs that don't need to cast shadows should set shadowCastingMode=Off — cost isn't directly visible in retail markers but cubemap passes are real."));
			}
			if (scene.Renderers.NoLODGroup > 300)
			{
				list.Add(((double)scene.Renderers.NoLODGroup / 4.0, $"{scene.Renderers.NoLODGroup} renderers have no LODGroup ({Pct(scene.Renderers.NoLODGroup, scene.Renderers.Total)}). Distant small objects render at full detail — most impactful when main-cam render cost is high."));
			}
			if (scene.Lights.PointShadow > 8)
			{
				list.Add((scene.Lights.PointShadow * 10, $"{scene.Lights.PointShadow} point lights with shadows × 6 faces = {scene.Lights.PointShadow * 6} cubemap passes/frame. Shadow budget + resolution tiering are the highest-leverage knobs."));
			}
			if (num > 0.3)
			{
				list.Add((num * 70.0, $"Physics costs {num:F2} ms/frame. Trim layer collision matrix, raise fixed timestep interval, switch non-dynamic rigidbodies to kinematic."));
			}
			if (num2 > 0.2)
			{
				list.Add((num2 * 60.0, $"Animators.Update costs {num2:F2} ms/frame across {scene.SkinnedRenderers} skinned renderers. Set Animator.cullingMode=BasedOnRenderers / CullCompletely on distant characters."));
			}
			if (num3 > 0.2)
			{
				list.Add((num3 * 60.0, $"Particles.Update costs {num3:F2} ms/frame across {scene.ActiveParticles} active systems ({FmtBig(scene.ActiveParticleCount)} particles alive). Distance-cull emit rate."));
			}
			if (num4 > 0.3)
			{
				list.Add((num4 * 50.0, $"Camera.ImageEffects (post-processing stack) costs {num4:F2} ms/frame. Audit which OnRenderImage passes are doing work."));
			}
			if (num5 > 1024.0)
			{
				list.Add((num5 / 64.0, "GC allocates " + FmtBytes(num5) + "/frame — hunt per-frame boxing, closures, and ToArray/ToList calls."));
			}
			double num11 = LookupCount(countStats, "Draw Calls Count");
			if (num11 > 1500.0)
			{
				list.Add((num11 / 40.0, $"{num11:F0} draw calls / frame. Static batching or GPU instancing on recurring prefabs would cut CPU cost."));
			}
			if (scene.ReflectionProbes > 1)
			{
				list.Add((scene.ReflectionProbes * 3, $"{scene.ReflectionProbes} reflection probes — each realtime probe updating adds CPU+GPU cost. Mark as baked or type=Custom when possible."));
			}
			if (list.Count == 0)
			{
				r.AppendLine("  (no high-cost categories detected — baseline looks clean)");
				return;
			}
			list.Sort(((double priority, string text) a, (double priority, string text) b) => b.priority.CompareTo(a.priority));
			int num12 = 1;
			foreach (var item2 in list)
			{
				string item = item2.Item2;
				r.AppendLine($"  {num12++}. {item}");
			}
		}
	}
	internal static class DLSSDownloader
	{
		private const string DllName = "nvngx_dlss.dll";

		private const int MinDllSize = 10000000;

		internal static string GetDllPath()
		{
			return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "nvngx_dlss.dll");
		}

		internal static bool EnsureAvailable()
		{
			string dllPath = GetDllPath();
			int num;
			if (File.Exists(dllPath))
			{
				num = ((new FileInfo(dllPath).Length >= 10000000) ? 1 : 0);
				if (num != 0)
				{
					Plugin.Log.LogDebug((object)$"DLSS DLL: {dllPath} ({new FileInfo(dllPath).Length / 1024 / 1024}MB)");
					return (byte)num != 0;
				}
			}
			else
			{
				num = 0;
			}
			Plugin.Log.LogWarning((object)"nvngx_dlss.dll missing or invalid — DLSS/DLAA disabled. Reinstall the mod.");
			return (byte)num != 0;
		}
	}
	internal static class FrameTimeMeter
	{
		internal class Meter
		{
			public readonly string Name;

			public readonly string ShortName;

			private readonly float[] _samples;

			private int _index;

			private int _count;

			private float _sum;

			public float LastUs;

			public float AverageUs
			{
				get
				{
					if (_count <= 0)
					{
						return 0f;
					}
					return _sum / (float)_count;
				}
			}

			public float AverageMs => AverageUs / 1000f;

			public Meter(string name, string shortName, int windowSize = 120)
			{
				Name = name;
				ShortName = shortName;
				_samples = new float[windowSize];
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			public void Record(float microseconds)
			{
				LastUs = microseconds;
				_sum -= _samples[_index];
				_samples[_index] = microseconds;
				_sum += microseconds;
				_index = (_index + 1) % _samples.Length;
				if (_count < _samples.Length)
				{
					_count++;
				}
			}
		}

		private static readonly Stopwatch _sw = Stopwatch.StartNew();

		internal static readonly Meter EnemyDirector = new Meter("EnemyDirector Throttle", "EnemyDir");

		internal static readonly Meter RoomVolumeCheck = new Meter("RoomVolume NonAlloc", "RoomVol");

		internal static readonly Meter SemiFuncCache = new Meter("SemiFunc Cache", "SemiFunc");

		internal static readonly Meter PhysGrabObjectFix = new Meter("PhysGrabObject Fix", "PhysGrab");

		internal static readonly Meter LightManagerBatch = new Meter("LightManager Batch", "LightMgr");

		internal static readonly Meter SceneApply = new Meter("SceneOptimizer Apply", "SceneApl");

		internal static readonly Meter[] All = new Meter[6] { EnemyDirector, RoomVolumeCheck, SemiFuncCache, PhysGrabObjectFix, LightManagerBatch, SceneApply };

		internal static bool Active
		{
			get
			{
				if (!Settings.DebugOverlay)
				{
					return OptimizerBenchmark.Running;
				}
				return true;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static long Begin()
		{
			if (!Active)
			{
				return 0L;
			}
			return _sw.ElapsedTicks;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void End(Meter meter, long startTicks)
		{
			if (startTicks != 0L)
			{
				float microseconds = (float)((double)(_sw.ElapsedTicks - startTicks) / 10.0);
				meter.Record(microseconds);
			}
		}
	}
	internal enum GpuVendor
	{
		Nvidia,
		Amd,
		Intel,
		Apple,
		Unknown
	}
	internal enum GpuTier
	{
		High,
		Mid,
		Low
	}
	internal static class GPUDetector
	{
		private static readonly Regex ArcDiscretePattern = new Regex("\\b[AB]\\d{3}\\b", RegexOptions.Compiled);

		public static string GpuName { get; private set; } = "Unknown";


		public static GpuVendor Vendor { get; private set; } = GpuVendor.Unknown;


		public static GpuTier Tier { get; private set; } = GpuTier.Low;


		public static bool DlssAvailable { get; private set; }

		public static int VramMb { get; private set; }

		public static bool IsD3D11 { get; private set; }

		public static bool IsIntegratedGpu { get; private set; }

		public static void Detect()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			GpuName = SystemInfo.graphicsDeviceName ?? "Unknown";
			VramMb = SystemInfo.graphicsMemorySize;
			Vendor = DetectVendor(GpuName, SystemInfo.graphicsDeviceVendor);
			Tier = DetectTier(VramMb);
			IsD3D11 = (int)SystemInfo.graphicsDeviceType == 2;
			IsIntegratedGpu = DetectIntegrated(GpuName, VramMb, Vendor);
			DlssAvailable = Vendor == GpuVendor.Nvidia && IsD3D11 && !IsIntegratedGpu && GpuName.ToUpperInvariant().Contains("RTX");
			Plugin.Log.LogInfo((object)($"GPU: {GpuName} | Vendor: {Vendor} | VRAM: {VramMb}MB | " + $"API: {SystemInfo.graphicsDeviceType} | iGPU: {IsIntegratedGpu} | Tier: {Tier}"));
		}

		public static bool IsUpscalerSupported(UpscaleMode mode)
		{
			switch (mode)
			{
			case UpscaleMode.Auto:
				return true;
			case UpscaleMode.Off:
				return true;
			case UpscaleMode.DLAA:
			case UpscaleMode.DLSS:
				return DlssAvailable;
			case UpscaleMode.FSR_Temporal:
				return true;
			default:
				return false;
			}
		}

		public static string[] GetAvailableUpscalerNames()
		{
			List<string> list = new List<string>();
			foreach (UpscaleMode value in Enum.GetValues(typeof(UpscaleMode)))
			{
				if (value != UpscaleMode.FSR && value != UpscaleMode.FSR4 && value != UpscaleMode.DLAA && IsUpscalerSupported(value))
				{
					string item = ((value == UpscaleMode.FSR_Temporal) ? "FSR" : value.ToString());
					list.Add(item);
				}
			}
			return list.ToArray();
		}

		private static GpuVendor DetectVendor(string name, string vendorString)
		{
			string text = (name + " " + vendorString).ToUpperInvariant();
			if (text.Contains("NVIDIA"))
			{
				return GpuVendor.Nvidia;
			}
			if (text.Contains("AMD") || text.Contains("ATI"))
			{
				return GpuVendor.Amd;
			}
			if (text.Contains("INTEL"))
			{
				return GpuVendor.Intel;
			}
			if (text.Contains("APPLE"))
			{
				return GpuVendor.Apple;
			}
			return GpuVendor.Unknown;
		}

		private static GpuTier DetectTier(int vramMb)
		{
			if (vramMb >= 8000)
			{
				return GpuTier.High;
			}
			if (vramMb >= 6000)
			{
				return GpuTier.Mid;
			}
			return GpuTier.Low;
		}

		private static bool DetectIntegrated(string name, int vramMb, GpuVendor vendor)
		{
			string text = name.ToUpperInvariant();
			if (vendor == GpuVendor.Intel && (text.Contains("UHD") || text.Contains("IRIS") || text.Contains("HD GRAPHICS") || (text.Contains("ARC") && !ArcDiscretePattern.IsMatch(text))))
			{
				return true;
			}
			if (vendor == GpuVendor.Amd && ((text.Contains("VEGA") && !text.Contains("VEGA 56") && !text.Contains("VEGA 64")) || (text.Contains("RADEON GRAPHICS") && !text.Contains("RX"))))
			{
				return true;
			}
			if (vramMb > 0 && vramMb < 2048)
			{
				return true;
			}
			return false;
		}
	}
	internal static class LightDiagnostics
	{
		private struct LightEntry
		{
			public string Name;

			public LightType Type;

			public LightShadows ShadowMode;

			public int ShadowRes;

			public ShadowResolution GlobalShadowRes;

			public int EffectiveRes;

			public float Range;

			public float Intensity;

			public Color Color;

			public bool Enabled;

			public bool CastsShadows;

			public LightRenderMode RenderMode;

			public bool HasLightAnimator;

			public bool HasItemLight;

			public bool HasFlashlight;

			public bool HasExplosion;

			public int ShadowFaces;

			public float ShadowCost;

			public int RenderersInRange;

			public int EstDrawCalls;
		}

		private static readonly string OutputPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "light_diagnostics.txt");

		internal static void Run()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Invalid comparison between Unknown and I4
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected I4, but got Unknown
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Expected I4, but got Unknown
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0830: Unknown result type (might be due to invalid IL or missing references)
			//IL_0849: Unknown result type (might be due to invalid IL or missing references)
			//IL_088d: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f8: Unknown result type (might be due to invalid IL or missing references)
			Light[] array = Object.FindObjectsOfType<Light>();
			if (array.Length == 0)
			{
				Plugin.Log.LogInfo((object)"Light diagnostics: no lights found");
				return;
			}
			List<LightEntry> list = new List<LightEntry>();
			Light[] array2 = array;
			foreach (Light val in array2)
			{
				LightEntry lightEntry = default(LightEntry);
				lightEntry.Name = GetPath(((Component)val).transform);
				lightEntry.Type = val.type;
				lightEntry.ShadowMode = val.shadows;
				lightEntry.ShadowRes = val.shadowCustomResolution;
				lightEntry.GlobalShadowRes = QualitySettings.shadowResolution;
				lightEntry.Range = val.range;
				lightEntry.Intensity = val.intensity;
				lightEntry.Color = val.color;
				lightEntry.Enabled = ((Behaviour)val).enabled && ((Component)val).gameObject.activeInHierarchy;
				lightEntry.CastsShadows = (int)val.shadows > 0;
				lightEntry.RenderMode = val.renderMode;
				LightEntry item = lightEntry;
				GameObject gameObject = ((Component)val).gameObject;
				item.HasLightAnimator = (Object)(object)gameObject.GetComponent<LightAnimator>() != (Object)null;
				item.HasItemLight = (Object)(object)gameObject.GetComponent<ItemLight>() != (Object)null;
				item.HasFlashlight = (Object)(object)gameObject.GetComponent<FlashlightController>() != (Object)null;
				item.HasExplosion = (Object)(object)gameObject.GetComponentInParent<ParticlePrefabExplosion>() != (Object)null;
				LightType type = val.type;
				item.ShadowFaces = (int)type switch
				{
					2 => 6, 
					0 => 1, 
					1 => QualitySettings.shadowCascades, 
					_ => 0, 
				};
				int num = (item.EffectiveRes = ((item.ShadowRes > 0) ? item.ShadowRes : GlobalResValue()));
				if (item.CastsShadows && item.Enabled)
				{
					item.ShadowCost = (float)item.ShadowFaces * ((float)num * (float)num / 1048576f);
				}
				else
				{
					item.ShadowCost = 0f;
				}
				if (item.CastsShadows && item.Enabled)
				{
					int num2 = 0;
					Collider[] array3 = Physics.OverlapSphere(((Component)val).transform.position, val.range);
					HashSet<Renderer> hashSet = new HashSet<Renderer>();
					Collider[] array4 = array3;
					for (int j = 0; j < array4.Length; j++)
					{
						Renderer component = ((Component)array4[j]).GetComponent<Renderer>();
						if ((Object)(object)component != (Object)null && (int)component.shadowCastingMode != 0 && hashSet.Add(component))
						{
							num2++;
						}
					}
					item.RenderersInRange = num2;
					item.EstDrawCalls = num2 * item.ShadowFaces;
				}
				list.Add(item);
			}
			list.Sort((LightEntry a, LightEntry b) => b.ShadowCost.CompareTo(a.ShadowCost));
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("══════════════════════════════════════════════════════════════");
			stringBuilder.AppendLine($"  LIGHT DIAGNOSTICS — {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
			stringBuilder.AppendLine("══════════════════════════════════════════════════════════════");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"  Total lights:         {array.Length}");
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			int num8 = 0;
			int num9 = 0;
			int num10 = 0;
			int num11 = 0;
			int num12 = 0;
			int num13 = 0;
			float num14 = 0f;
			int num15 = 0;
			foreach (LightEntry item2 in list)
			{
				if (item2.Enabled)
				{
					num3++;
				}
				if (item2.CastsShadows && item2.Enabled)
				{
					num4++;
				}
				LightType type = item2.Type;
				switch ((int)type)
				{
				case 2:
					num5++;
					break;
				case 0:
					num6++;
					break;
				case 1:
					num7++;
					break;
				default:
					num8++;
					break;
				}
				if (item2.HasLightAnimator)
				{
					num9++;
				}
				else if (item2.HasItemLight)
				{
					num10++;
				}
				else if (item2.HasFlashlight)
				{
					num11++;
				}
				else if (item2.HasExplosion)
				{
					num12++;
				}
				else
				{
					num13++;
				}
				num14 += item2.ShadowCost;
				num15 += item2.EstDrawCalls;
			}
			stringBuilder.AppendLine($"  Active:               {num3}");
			stringBuilder.AppendLine($"  Casting shadows:      {num4}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"  By type:              Point={num5}  Spot={num6}  Directional={num7}  Area={num8}");
			stringBuilder.AppendLine($"  By component:         Plain={num13}  LightAnimator={num9}  ItemLight={num10}  Flashlight={num11}  Explosion={num12}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"  Global shadow res:    {QualitySettings.shadowResolution}");
			stringBuilder.AppendLine($"  Shadow distance:      {QualitySettings.shadowDistance:F0}m");
			stringBuilder.AppendLine($"  Shadow cascades:      {QualitySettings.shadowCascades}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"  Total shadow cost:    {num14:F1} (relative units: faces x res²/1M)");
			stringBuilder.AppendLine($"  Est shadow draw calls:{num15}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("──────────────────────────────────────────────────────────────");
			stringBuilder.AppendLine("  COST BY CATEGORY");
			stringBuilder.AppendLine("──────────────────────────────────────────────────────────────");
			float num16 = 0f;
			float num17 = 0f;
			float num18 = 0f;
			float num19 = 0f;
			float num20 = 0f;
			int num21 = 0;
			int num22 = 0;
			int num23 = 0;
			int num24 = 0;
			int num25 = 0;
			foreach (LightEntry item3 in list)
			{
				if (item3.HasLightAnimator)
				{
					num17 += item3.ShadowCost;
					num22 += item3.EstDrawCalls;
				}
				else if (item3.HasItemLight)
				{
					num18 += item3.ShadowCost;
					num23 += item3.EstDrawCalls;
				}
				else if (item3.HasFlashlight)
				{
					num19 += item3.ShadowCost;
					num24 += item3.EstDrawCalls;
				}
				else if (item3.HasExplosion)
				{
					num20 += item3.ShadowCost;
					num25 += item3.EstDrawCalls;
				}
				else
				{
					num16 += item3.ShadowCost;
					num21 += item3.EstDrawCalls;
				}
			}
			stringBuilder.AppendLine($"  Plain Light:      cost={num16,8:F1}  est draw calls={num21,6}");
			stringBuilder.AppendLine($"  LightAnimator:    cost={num17,8:F1}  est dra