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