Decompiled source of UltraPerformance v1.0.0
plugins/UltraPerformance.dll
Decompiled 4 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ULTRAKILL.Cheats; using ULTRAKILL.Enemy; using ULTRAKILL.Portal; using ULTRAKILL.Portal.Geometry; using Unity.Collections; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; using Unity.Profiling; using Unity.Profiling.LowLevel.Unsafe; using Unity.Profiling.Memory; using UnityEngine; using UnityEngine.LowLevel; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("UltraPerformance")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a47a3999bb5c48b80967441d712dfab41759e444")] [assembly: AssemblyProduct("UltraPerformance")] [assembly: AssemblyTitle("UltraPerformance")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UltraPerformance { public static class BatchAudit { private struct Key : IEquatable<Key> { public int mesh; public int mat; public bool Equals(Key o) { if (mesh == o.mesh) { return mat == o.mat; } return false; } public override int GetHashCode() { return (mesh * 397) ^ mat; } } public static string Run() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(8192); Renderer[] array = Object.FindObjectsOfType<Renderer>(false); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; Dictionary<Key, int> dictionary = new Dictionary<Key, int>(1024); HashSet<int> hashSet = new HashSet<int>(); HashSet<int> hashSet2 = new HashSet<int>(); HashSet<int> hashSet3 = new HashSet<int>(); HashSet<int> hashSet4 = new HashSet<int>(); HashSet<int> hashSet5 = new HashSet<int>(); int num6 = 0; foreach (Renderer val in array) { if ((Object)(object)val == (Object)null || !val.enabled) { continue; } num++; if (val.isVisible) { num2++; } if (val.isPartOfStaticBatch) { num3++; } if ((int)val.shadowCastingMode != 0) { num5++; } int mesh = 0; MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { mesh = ((Object)component.sharedMesh).GetInstanceID(); } else { SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); if (val2 != null && (Object)(object)val2.sharedMesh != (Object)null) { mesh = ((Object)val2.sharedMesh).GetInstanceID(); } } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null) { continue; } foreach (Material val3 in sharedMaterials) { if ((Object)(object)val3 == (Object)null) { continue; } int instanceID = ((Object)val3).GetInstanceID(); hashSet.Add(instanceID); if (val3.enableInstancing) { num4++; hashSet4.Add(instanceID); } else { hashSet5.Add(instanceID); } Shader shader = val3.shader; if ((Object)(object)shader != (Object)null) { int instanceID2 = ((Object)shader).GetInstanceID(); if (!hashSet2.Contains(instanceID2) && !hashSet3.Contains(instanceID2)) { bool flag = false; try { LocalKeywordSpace keywordSpace = shader.keywordSpace; string[] keywordNames = ((LocalKeywordSpace)(ref keywordSpace)).keywordNames; for (int k = 0; k < keywordNames.Length; k++) { if (keywordNames[k] == "INSTANCING_ON") { flag = true; break; } } } catch { } if (flag) { hashSet2.Add(instanceID2); } else { hashSet3.Add(instanceID2); } } } Key key = new Key { mesh = mesh, mat = instanceID }; dictionary.TryGetValue(key, out var value); dictionary[key] = value + 1; } } foreach (KeyValuePair<Key, int> item in dictionary) { _ = item; num6++; } stringBuilder.Append("BATCHING AUDIT\n"); stringBuilder.AppendFormat(" renderers enabled {0}\n", num); stringBuilder.AppendFormat(" currently visible {0}\n", num2); stringBuilder.AppendFormat(" part of a static batch {0} ({1:F0}%)\n", num3, (num > 0) ? (100.0 * (double)num3 / (double)num) : 0.0); stringBuilder.AppendFormat(" casting shadows {0} (each doubles submission)\n", num5); stringBuilder.AppendFormat(" distinct materials {0}\n", hashSet.Count); stringBuilder.AppendFormat(" material slots w/ instancing {0}\n", num4); stringBuilder.AppendFormat(" materials WITH instancing {0}\n", hashSet4.Count); stringBuilder.AppendFormat(" materials WITHOUT instancing {0}\n", hashSet5.Count); stringBuilder.AppendFormat(" shaders WITH INSTANCING_ON {0} <-- instancing is only possible on these\n", hashSet2.Count); stringBuilder.AppendFormat(" shaders WITHOUT it {0} <-- enableInstancing does nothing here\n", hashSet3.Count); stringBuilder.AppendFormat(" unique mesh+material pairs {0} <-- floor if instancing were perfect\n", num6); List<KeyValuePair<Key, int>> list = new List<KeyValuePair<Key, int>>(dictionary); list.Sort((KeyValuePair<Key, int> a, KeyValuePair<Key, int> b) => b.Value.CompareTo(a.Value)); int num7 = 0; int num8 = 0; for (int num9 = 0; num9 < list.Count; num9++) { if (list[num9].Value > 1) { num7++; num8 += list[num9].Value - 1; } } stringBuilder.AppendFormat(" pairs appearing >1x {0}\n", num7); stringBuilder.AppendFormat(" redundant submissions {0} <-- theoretical instancing saving\n", num8); stringBuilder.Append(" biggest repeat groups (count x mesh/material pair):\n"); for (int num10 = 0; num10 < Math.Min(10, list.Count) && list[num10].Value >= 2; num10++) { Object obj2 = Resources.InstanceIDToObject(list[num10].Key.mat); Material val4 = (Material)(object)((obj2 is Material) ? obj2 : null); Object obj3 = Resources.InstanceIDToObject(list[num10].Key.mesh); Mesh val5 = (Mesh)(object)((obj3 is Mesh) ? obj3 : null); stringBuilder.AppendFormat(" {0,5} x {1} / {2}{3}\n", list[num10].Value, ((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "(no mesh)", ((Object)(object)val4 != (Object)null) ? ((Object)val4).name : "(null mat)", ((Object)(object)val4 != (Object)null && !val4.enableInstancing) ? " [instancing OFF]" : ""); } return stringBuilder.ToString(); } } public static class CameraProf { private class Row { public string Name; public long PreCull; public long PreRender; public long CullTicks; public long RenderTicks; public int Calls; } [CompilerGenerated] private static class <>O { public static CameraCallback <0>__OnPreCull; public static CameraCallback <1>__OnPreRender; public static CameraCallback <2>__OnPostRender; } private static readonly Dictionary<int, Row> _rows = new Dictionary<int, Row>(8); private static readonly Dictionary<int, OpaqueSortMode> _sortOriginals = new Dictionary<int, OpaqueSortMode>(8); private static bool _installed; private static bool _sortApplied; public static bool Installed => _installed; private static void ApplySortMode(Camera cam) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)cam).GetInstanceID(); OpaqueSortMode value; if (Cfg.NoDistanceSort.Value) { if ((int)cam.opaqueSortMode != 2) { if (!_sortOriginals.ContainsKey(instanceID)) { _sortOriginals[instanceID] = cam.opaqueSortMode; } cam.opaqueSortMode = (OpaqueSortMode)2; } _sortApplied = true; } else if (_sortApplied && _sortOriginals.TryGetValue(instanceID, out value) && cam.opaqueSortMode != value) { cam.opaqueSortMode = value; } } public static void Install() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown if (!_installed) { CameraCallback onPreCull = Camera.onPreCull; object obj = <>O.<0>__OnPreCull; if (obj == null) { CameraCallback val = OnPreCull; <>O.<0>__OnPreCull = val; obj = (object)val; } Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)onPreCull, (Delegate?)obj); CameraCallback onPreRender = Camera.onPreRender; object obj2 = <>O.<1>__OnPreRender; if (obj2 == null) { CameraCallback val2 = OnPreRender; <>O.<1>__OnPreRender = val2; obj2 = (object)val2; } Camera.onPreRender = (CameraCallback)Delegate.Combine((Delegate?)(object)onPreRender, (Delegate?)obj2); CameraCallback onPostRender = Camera.onPostRender; object obj3 = <>O.<2>__OnPostRender; if (obj3 == null) { CameraCallback val3 = OnPostRender; <>O.<2>__OnPostRender = val3; obj3 = (object)val3; } Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)onPostRender, (Delegate?)obj3); _installed = true; } } public static void Uninstall() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown if (_installed) { CameraCallback onPreCull = Camera.onPreCull; object obj = <>O.<0>__OnPreCull; if (obj == null) { CameraCallback val = OnPreCull; <>O.<0>__OnPreCull = val; obj = (object)val; } Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)onPreCull, (Delegate?)obj); CameraCallback onPreRender = Camera.onPreRender; object obj2 = <>O.<1>__OnPreRender; if (obj2 == null) { CameraCallback val2 = OnPreRender; <>O.<1>__OnPreRender = val2; obj2 = (object)val2; } Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)onPreRender, (Delegate?)obj2); CameraCallback onPostRender = Camera.onPostRender; object obj3 = <>O.<2>__OnPostRender; if (obj3 == null) { CameraCallback val3 = OnPostRender; <>O.<2>__OnPostRender = val3; obj3 = (object)val3; } Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)onPostRender, (Delegate?)obj3); _installed = false; } } private static Row Get(Camera cam) { int instanceID = ((Object)cam).GetInstanceID(); if (!_rows.TryGetValue(instanceID, out var value)) { value = new Row { Name = (string.IsNullOrEmpty(((Object)cam).name) ? "(unnamed)" : ((Object)cam).name) }; _rows[instanceID] = value; } return value; } private static void OnPreCull(Camera cam) { if (!((Object)(object)cam == (Object)null)) { ApplySortMode(cam); if (Cfg.Measure.Value) { Get(cam).PreCull = Prof.Now; } } } private static void OnPreRender(Camera cam) { if (Cfg.Measure.Value && !((Object)(object)cam == (Object)null)) { Row row = Get(cam); row.PreRender = Prof.Now; if (row.PreCull != 0L) { row.CullTicks += row.PreRender - row.PreCull; } } } private static void OnPostRender(Camera cam) { if (Cfg.Measure.Value && !((Object)(object)cam == (Object)null)) { Row row = Get(cam); if (row.PreRender != 0L) { row.RenderTicks += Prof.Now - row.PreRender; } row.Calls++; row.PreCull = 0L; row.PreRender = 0L; } } public static void Reset() { foreach (KeyValuePair<int, Row> row in _rows) { row.Value.CullTicks = 0L; row.Value.RenderTicks = 0L; row.Value.Calls = 0; } } public static List<(string name, double callsPerFrame, double cullMs, double renderMs)> Export(int frames) { int num = Math.Max(frames, 1); List<(string, double, double, double)> list = new List<(string, double, double, double)>(); foreach (KeyValuePair<int, Row> row in _rows) { Row value = row.Value; if (value.Calls != 0) { list.Add((value.Name, (double)value.Calls / (double)num, (double)value.CullTicks * Prof.TickToMs / (double)num, (double)value.RenderTicks * Prof.TickToMs / (double)num)); } } list.Sort(((string, double, double, double) a, (string, double, double, double) b) => (b.Item3 + b.Item4).CompareTo(a.Item3 + a.Item4)); return list; } public static void AppendReport(StringBuilder sb, int frames, double avgFrameMs) { if (!_installed || _rows.Count == 0) { return; } List<(string, double, double, double)> list = Export(frames); if (list.Count == 0) { return; } double num = 0.0; foreach (var item in list) { num += item.Item3 + item.Item4; } sb.AppendFormat(" cameras: {0:F2} ms/f on the main thread across {1} cameras (cull = preCull->preRender, render = preRender->postRender; main camera includes portal passes)\n", num, list.Count); foreach (var item2 in list) { if (!(item2.Item3 + item2.Item4 < 0.01)) { sb.AppendFormat(" {0,-30} {1,6:F1}/f cull {2,7:F3} ms/f render {3,7:F3} ms/f {4,5:F1}%\n", item2.Item1, item2.Item2, item2.Item3, item2.Item4, (avgFrameMs > 0.0) ? (100.0 * (item2.Item3 + item2.Item4) / avgFrameMs) : 0.0); } } } } public static class Capture { private static int _seq; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; private static string Esc(string s) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length + 8); foreach (char c in s) { switch (c) { case '"': stringBuilder.Append("\\\""); continue; case '\\': stringBuilder.Append("\\\\"); continue; case '\n': stringBuilder.Append("\\n"); continue; case '\r': stringBuilder.Append("\\r"); continue; case '\t': stringBuilder.Append("\\t"); continue; } if (c < ' ') { stringBuilder.AppendFormat(Inv, "\\u{0:x4}", (int)c); } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private static string N(double v) { if (double.IsNaN(v) || double.IsInfinity(v)) { return "null"; } return v.ToString("G9", Inv); } public static string Write(string directory) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) int frames = Math.Max(Prof.Frames, 1); StringBuilder stringBuilder = new StringBuilder(65536); stringBuilder.Append("{\n"); stringBuilder.AppendFormat(Inv, " \"captureIndex\": {0},\n", _seq); stringBuilder.AppendFormat(Inv, " \"realtimeSinceStartup\": {0},\n", N(Time.realtimeSinceStartup)); stringBuilder.AppendFormat(Inv, " \"frameCount\": {0},\n", Time.frameCount); string s = ""; try { Scene activeScene = SceneManager.GetActiveScene(); s = ((Scene)(ref activeScene)).name; } catch { } stringBuilder.Append(" \"context\": {\n"); stringBuilder.AppendFormat(Inv, " \"scene\": \"{0}\",\n", Esc(s)); stringBuilder.AppendFormat(Inv, " \"resolution\": \"{0}x{1}\",\n", Screen.width, Screen.height); stringBuilder.AppendFormat(Inv, " \"fullScreen\": {0},\n", Screen.fullScreen ? "true" : "false"); stringBuilder.AppendFormat(Inv, " \"targetFrameRate\": {0},\n", Application.targetFrameRate); stringBuilder.AppendFormat(Inv, " \"vSyncCount\": {0},\n", QualitySettings.vSyncCount); stringBuilder.AppendFormat(Inv, " \"cpu\": \"{0}\",\n", Esc(SystemInfo.processorType)); stringBuilder.AppendFormat(Inv, " \"cpuCores\": {0},\n", SystemInfo.processorCount); stringBuilder.AppendFormat(Inv, " \"gpu\": \"{0}\",\n", Esc(SystemInfo.graphicsDeviceName)); stringBuilder.AppendFormat(Inv, " \"gfxApi\": \"{0}\",\n", Esc(((object)SystemInfo.graphicsDeviceType/*cast due to .constrained prefix*/).ToString())); stringBuilder.AppendFormat(Inv, " \"gfxMultiThreaded\": {0},\n", SystemInfo.graphicsMultiThreaded ? "true" : "false"); stringBuilder.AppendFormat(Inv, " \"systemMemoryMB\": {0}\n", SystemInfo.systemMemorySize); stringBuilder.Append(" },\n"); stringBuilder.Append(" \"frame\": {\n"); stringBuilder.AppendFormat(Inv, " \"frames\": {0},\n", Prof.Frames); stringBuilder.AppendFormat(Inv, " \"avgMs\": {0},\n", N(Prof.AvgFrameMs)); stringBuilder.AppendFormat(Inv, " \"worstMs\": {0},\n", N(Prof.WorstFrameMs)); stringBuilder.AppendFormat(Inv, " \"fps\": {0}\n", N((Prof.AvgFrameMs > 0.0) ? (1000.0 / Prof.AvgFrameMs) : 0.0)); stringBuilder.Append(" },\n"); stringBuilder.AppendFormat(Inv, " \"knobs\": \"{0}\",\n", Esc(Plugin.KnobLine())); stringBuilder.Append(" \"gauges\": {\n"); stringBuilder.AppendFormat(Inv, " \"visions\": {0}, \"visionsPeak\": {1},\n", Prof.GaugeVisions, Prof.GaugePeakVisions); stringBuilder.AppendFormat(Inv, " \"targets\": {0}, \"targetsPeak\": {1},\n", Prof.GaugeTargets, Prof.GaugePeakTargets); stringBuilder.AppendFormat(Inv, " \"portalSequences\": {0}, \"portalSequencesPeak\": {1},\n", Prof.GaugeSequences, Prof.GaugePeakSequences); stringBuilder.AppendFormat(Inv, " \"portalPasses\": {0}, \"portalPassesPeak\": {1},\n", Prof.GaugePasses, Prof.GaugePeakPasses); stringBuilder.AppendFormat(Inv, " \"onscreenPortals\": {0}, \"renderPortals\": {1}\n", Prof.GaugeOnscreenPortals, Prof.GaugeRenderPortals); stringBuilder.Append(" },\n"); stringBuilder.Append(" \"timers\": [\n"); List<(string, double, double, double)> list = Prof.ExportTimers(); for (int i = 0; i < list.Count; i++) { (string, double, double, double) tuple = list[i]; stringBuilder.AppendFormat(Inv, " {{\"name\": \"{0}\", \"msPerFrame\": {1}, \"callsPerFrame\": {2}, \"usPerCall\": {3}}}{4}\n", Esc(tuple.Item1), N(tuple.Item2), N(tuple.Item3), N(tuple.Item4), (i < list.Count - 1) ? "," : ""); } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"counters\": [\n"); List<(string, double)> list2 = Prof.ExportCounters(); for (int j = 0; j < list2.Count; j++) { stringBuilder.AppendFormat(Inv, " {{\"name\": \"{0}\", \"perFrame\": {1}}}{2}\n", Esc(list2[j].Item1), N(list2[j].Item2), (j < list2.Count - 1) ? "," : ""); } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"playerLoop\": [\n"); List<(string, int, double, double)> list3 = (List<(string, int, double, double)>)(PlayerLoopProf.Installed ? ((IList)PlayerLoopProf.Export(frames)) : ((IList)new List<(string, int, double, double)>())); for (int k = 0; k < list3.Count; k++) { stringBuilder.AppendFormat(Inv, " {{\"name\": \"{0}\", \"depth\": {1}, \"msPerFrame\": {2}, \"callsPerFrame\": {3}}}{4}\n", Esc(list3[k].Item1), list3[k].Item2, N(list3[k].Item3), N(list3[k].Item4), (k < list3.Count - 1) ? "," : ""); } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"scripts\": [\n"); List<(string, double, double)> list4 = (List<(string, double, double)>)(ScriptSweep.Active ? ((IList)ScriptSweep.Export(frames)) : ((IList)new List<(string, double, double)>())); for (int l = 0; l < list4.Count; l++) { stringBuilder.AppendFormat(Inv, " {{\"name\": \"{0}\", \"msPerFrame\": {1}, \"callsPerFrame\": {2}}}{3}\n", Esc(list4[l].Item1), N(list4[l].Item2), N(list4[l].Item3), (l < list4.Count - 1) ? "," : ""); } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"engineCounters\": [\n"); List<(string, double, double, string)> list5 = EngineStats.Export(); for (int m = 0; m < list5.Count; m++) { stringBuilder.AppendFormat(Inv, " {{\"name\": \"{0}\", \"avg\": {1}, \"peak\": {2}, \"unit\": \"{3}\"}}{4}\n", Esc(list5[m].Item1), N(list5[m].Item2), N(list5[m].Item3), Esc(list5[m].Item4), (m < list5.Count - 1) ? "," : ""); } stringBuilder.Append(" ]\n"); stringBuilder.Append("}\n"); Paths.Ensure(directory); string text = Paths.Join(directory, string.Format(Inv, "capture-{0:000}.json", _seq)); File.WriteAllText(text, stringBuilder.ToString()); _seq++; return text; } public static void WriteMemorySnapshot(string directory, Action<string, bool> done) { try { Paths.Ensure(directory); MemoryProfiler.TakeSnapshot(Paths.Join(directory, string.Format(Inv, "capture-{0:000}.snap", Math.Max(_seq - 1, 0))), (Action<string, bool>)delegate(string p, bool ok) { done(p, ok); }, (CaptureFlags)3); } catch (Exception ex) { Plugin.Log.LogWarning((object)("memory snapshot failed: " + ex.Message)); } } } public static class Cfg { public static ConfigEntry<bool> FixVisionFilterAlloc; public static ConfigEntry<bool> FixIdolTrySeeHoist; public static ConfigEntry<bool> FixEnemyTrackerListAlloc; public static ConfigEntry<bool> FixMannequinOverlapAlloc; public static ConfigEntry<bool> FixExceptionSpam; public static ConfigEntry<bool> CullByMaxDistance; public static ConfigEntry<float> MaxVisionDistance; public static ConfigEntry<bool> CullCulledSequences; public static ConfigEntry<float> MannequinClingIncrement; public static ConfigEntry<bool> FixFraudTweaksExplosions; public static ConfigEntry<bool> FastFraudTweaksBounds; public static ConfigEntry<string> KnownGameBuild; public static ConfigEntry<float> PortalMinPixelArea; public static ConfigEntry<float> PortalMinPixelAreaFraction; public static ConfigEntry<float> PortalMaxDistance; public static ConfigEntry<int> PortalMaxRecursions; public static ConfigEntry<bool> PortalAdaptiveRecursion; public static ConfigEntry<int> PortalAdaptiveNearDepth; public static ConfigEntry<int> PortalAdaptiveFarDepth; public static ConfigEntry<float> PortalAdaptiveNearSize; public static ConfigEntry<float> PortalAdaptiveFarSize; public static ConfigEntry<bool> PortalFallbackForAll; public static ConfigEntry<int> PortalFallbackTexSize; public static ConfigEntry<int> PortalFallbackRefreshFrames; public static ConfigEntry<bool> NoDistanceSort; public static ConfigEntry<int> JobWorkerCount; public static ConfigEntry<bool> Measure; public static ConfigEntry<float> ReportInterval; public static ConfigEntry<bool> LogReports; public static ConfigEntry<bool> MeasureCullPotential; public static ConfigEntry<bool> OverlayOnByDefault; public static ConfigEntry<KeyCode> OverlayKey; public static ConfigEntry<KeyCode> DumpKey; public static ConfigEntry<bool> InstrumentCameraRender; public static ConfigEntry<bool> DumpAllCounters; public static ConfigEntry<bool> ScriptSweep; public static ConfigEntry<float> SpikeLogThresholdMs; public static ConfigEntry<bool> PlayerLoopProfile; public static ConfigEntry<int> PlayerLoopDepth; public static ConfigEntry<KeyCode> CaptureKey; public static ConfigEntry<string> CaptureDir; public static ConfigEntry<bool> CaptureMemorySnapshot; public static ConfigEntry<KeyCode> TraceKey; public static ConfigEntry<float> TraceSeconds; public static ConfigEntry<KeyCode> BatchAuditKey; public static void Init(ConfigFile c) { FixVisionFilterAlloc = c.Bind<bool>("Fixes (safe)", "VisionFilterAlloc", true, "Enemy.GetVisionFilter() allocates a new filter array every FixedUpdate for every enemy (50 times a second each). Returns cached filters instead. Behaviour identical."); FixIdolTrySeeHoist = c.Bind<bool>("Fixes (safe)", "IdolTrySeeHoist", true, "Idol.PickNewTarget() repeats the same vision query inside a 7 x N loop. Runs it once. Target choice is unchanged, including the original scoring quirk."); FixEnemyTrackerListAlloc = c.Bind<bool>("Fixes (safe)", "EnemyTrackerListAlloc", false, "Caches EnemyTracker.GetCurrentEnemies() once per frame instead of rebuilding the list on every call. Off by default: the saving is small, and an enemy that dies mid-frame stays in the list until the next frame."); FixMannequinOverlapAlloc = c.Bind<bool>("Fixes (safe)", "MannequinOverlapAlloc", true, "Mannequin.CheckClings() uses the allocating Physics.OverlapSphere while airborne. Switches to the non-allocating version. Behaviour identical."); FixExceptionSpam = c.Bind<bool>("Fixes (safe)", "ExceptionSpam", true, "FadeOut.Update and Explosion.FixedUpdate can throw a NullReferenceException every frame. Each one costs a stack trace and a log write. The exception aborts the method anyway, so skipping the call when it would throw is behaviour-identical."); CullByMaxDistance = c.Bind<bool>("Fixes (behaviour)", "CullByMaxDistance", false, "Enforces Vision.maxDistance, which the game declares but never reads: enemies ignore targets further than MaxVisionDistance. Changes AI behaviour."); MaxVisionDistance = c.Bind<float>("Fixes (behaviour)", "MaxVisionDistance", 120f, "Distance used by CullByMaxDistance. 120 is the value the game declares."); CullCulledSequences = c.Bind<bool>("Fixes (behaviour)", "CullCulledSequences", false, "Enemy vision skips portal paths the renderer has already culled. Changes AI behaviour: Puppets, Idols, Ferrymen and Stalkers can currently see through culled portal paths and would stop."); MannequinClingIncrement = c.Bind<float>("Fixes (behaviour)", "MannequinClingIncrement", 0f, "0 = game default (1.5). Mannequin wall-walking fires two raycasts per step; a larger step fires fewer (3.0 halves them). Changes AI behaviour: cling-walk targets get coarser."); FixFraudTweaksExplosions = c.Bind<bool>("Compat", "FixFraudTweaksExplosions", true, "FraudTweaks 1.6.0's explosion patch calls a portal function this game version no longer has, and throws an exception on every explosion tick. Removes just that patch so the game's own portal check runs. Does nothing if FraudTweaks is not installed or ships a version that matches the game."); FastFraudTweaksBounds = c.Bind<bool>("Compat", "FastFraudTweaksBounds", true, "FraudTweaks' out-of-bounds blocker check scales with the square of the number of blockers and allocates every frame (13 ms per frame in a custom level with 647 blockers). Replaces it with a linear version that does the same checks (and skips a deleted blocker instead of throwing every frame). Does nothing if FraudTweaks is not installed."); KnownGameBuild = c.Bind<string>("Compat", "KnownGameBuild", "", "Written by the plugin. When the game updates, the plugin logs which of its patches still applied. Clear this to silence the warning once."); PortalMinPixelArea = c.Bind<float>("Portal render", "MinPixelArea", 0f, "0 = game default (2). Portals covering fewer screen pixels than this are not rendered. COST: skipped portals render black. Prefer MinPixelAreaFraction."); PortalMinPixelAreaFraction = c.Bind<float>("Portal render", "MinPixelAreaFraction", 0f, "0 = off. Same as MinPixelArea but as a fraction of the screen, so one value works at any resolution. 0.005 = skip portals smaller than 0.5% of the screen. COST: skipped portals render black."); PortalMaxDistance = c.Bind<float>("Portal render", "MaxDistance", 0f, "0 = game default (unlimited). Portals further than this are not rendered. COST: they render black."); PortalMaxRecursions = c.Bind<int>("Portal render", "MaxRecursions", 0, "0 = game default (3). Limits how many portals deep a portal view renders. Every level of depth is another full scene render, so this is the largest portal setting. At the limit the far side shows a recent snapshot instead of a live view (see FallbackForAllPortals)."); PortalAdaptiveRecursion = c.Bind<bool>("Portal render", "AdaptiveRecursion", false, "Recursion depth by apparent size: the portal you are looking through keeps full depth, small and distant ones drop to AdaptiveFarDepth. Never raises a portal above the level's own setting. Overrides MaxRecursions. Measured 110 -> 240 fps in a portal-heavy Fraud scene."); PortalAdaptiveNearDepth = c.Bind<int>("Portal render", "AdaptiveNearDepth", 3, "Depth for portals that fill a lot of the view. 3 = the game's default."); PortalAdaptiveFarDepth = c.Bind<int>("Portal render", "AdaptiveFarDepth", 1, "Depth for small or distant portals."); PortalAdaptiveNearSize = c.Bind<float>("Portal render", "AdaptiveNearSize", 0.25f, "Apparent size (portal size / distance) at or above which a portal gets AdaptiveNearDepth. 0.25 is about a 5-unit portal at 20 units. Lower = more portals at full depth."); PortalAdaptiveFarSize = c.Bind<float>("Portal render", "AdaptiveFarSize", 0.08f, "Apparent size below which a portal gets AdaptiveFarDepth. In between it gets one level less than AdaptiveNearDepth."); PortalFallbackForAll = c.Bind<bool>("Portal render", "FallbackForAllPortals", true, "Only acts while MaxRecursions or AdaptiveRecursion is on. Without it, portals at the depth limit render black; with it they show a snapshot of their far side, refreshed every frame the portal is rendered. COST: one small copy per visible portal per frame."); PortalFallbackTexSize = c.Bind<int>("Portal render", "FallbackTextureSize", 512, "Width in pixels of the fallback snapshots (height follows the portal's shape). The game uses 256 for its own."); PortalFallbackRefreshFrames = c.Bind<int>("Portal render", "FallbackRefreshFrames", 8, "A portal only ever seen through other portals is never rendered itself, so its snapshot would go stale. Every this many frames one limited portal renders one level deeper, in rotation, to refresh the ones behind it. 0 = off."); NoDistanceSort = c.Bind<bool>("Render", "NoDistanceSort", false, "Sorts opaque objects by material instead of by distance, which can cut material switches on the main thread. COST: more overdraw on the GPU. Measure before keeping it."); JobWorkerCount = c.Bind<int>("Threads", "JobWorkerCount", 0, "0 = game default. Unity sizes its job thread pool from the CPU's thread count and ignores CPU affinity, so a game pinned to fewer cores runs more worker threads than it has cores. Lower values (6, 4) can reduce contention there. Measure before keeping it."); Measure = c.Bind<bool>("Profiler", "Enabled", false, "Master switch for the profiler: the periodic report, every hotkey, and the opt-in diagnostics below (ScriptSweep, PlayerLoopProfile, InstrumentCameraRender), which only install when this is on. Off: the fixes run with no measurement overhead and the plugin reads no input."); ReportInterval = c.Bind<float>("Profiler", "ReportInterval", 5f, "Seconds between reports. Counters reset each report."); LogReports = c.Bind<bool>("Profiler", "LogToConsole", true, "Write each report to the BepInEx log."); MeasureCullPotential = c.Bind<bool>("Profiler", "MeasureCullPotential", false, "Report how many enemy-vision candidates CullByMaxDistance / CullCulledSequences would remove, without applying them."); OverlayOnByDefault = c.Bind<bool>("Profiler", "OverlayOnByDefault", false, "Show the on-screen overlay from startup."); OverlayKey = c.Bind<KeyCode>("Profiler", "OverlayKey", (KeyCode)291, "Toggle the on-screen overlay."); DumpKey = c.Bind<KeyCode>("Profiler", "DumpKey", (KeyCode)292, "Write a full report to the log now."); InstrumentCameraRender = c.Bind<bool>("Profiler", "InstrumentCameraRender", false, "Times UnityEngine.Camera.Render itself, separating Unity's culling and submission from the portal renderer's own per-pass work. Patches a core engine method, so off unless you need it."); DumpAllCounters = c.Bind<bool>("Profiler", "DumpAllCounters", false, "At startup, log every engine profiler counter this game build exposes."); ScriptSweep = c.Bind<bool>("Profiler", "ScriptSweep", false, "Times every MonoBehaviour Update / LateUpdate / FixedUpdate in the game and in other mods (including other mods' patches on them) and ranks them in the report. Adds overhead to every call: turn it on for one measurement run, then off."); SpikeLogThresholdMs = c.Bind<float>("Profiler", "SpikeLogThresholdMs", 12f, "With ScriptSweep on: when a frame takes at least this many ms, log the scripts that took the most time in that frame. 0 = off. At most one log per half second."); PlayerLoopProfile = c.Bind<bool>("Profiler", "PlayerLoopProfile", false, "Times every Unity PlayerLoop phase (FixedUpdate, Update, rendering, ...), a complete non-overlapping breakdown of the frame. Cheap. The original loop is captured first, so other mods' additions survive."); PlayerLoopDepth = c.Bind<int>("Profiler", "PlayerLoopDepth", 2, "1 = the seven top-level phases. 2 = also the engine systems inside them (e.g. FinishFrameRendering, PlayerUpdateCanvases)."); CaptureKey = c.Bind<KeyCode>("Profiler", "CaptureKey", (KeyCode)284, "Write everything the profiler knows to one JSON file: timers, counters, player loop, script sweep, engine counters, settings and machine info."); CaptureDir = c.Bind<string>("Profiler", "CaptureDir", "", "Where capture and trace files go. Empty = an UltraPerformance folder next to the BepInEx config. Under Proton, a path starting with '/' is treated as relative to the Steam folder; use Z:/... instead."); CaptureMemorySnapshot = c.Bind<bool>("Profiler", "CaptureMemorySnapshot", false, "Also write a Unity .snap memory snapshot with each capture. Stalls the game briefly; large file."); TraceKey = c.Bind<KeyCode>("Profiler", "TraceKey", (KeyCode)290, "Start a per-frame trace: one CSV row per frame with every timer, player-loop phase and engine counter. Press again to stop early."); TraceSeconds = c.Bind<float>("Profiler", "TraceSeconds", 10f, "How long a trace runs before it is written."); BatchAuditKey = c.Bind<KeyCode>("Profiler", "BatchAuditKey", (KeyCode)283, "Log a one-shot rendering audit: renderers, materials, static batching, instancing, plus the quality settings. Uses FindObjectsOfType, so expect a brief hitch."); } } [HarmonyPatch(typeof(Enemy), "GetVisionFilter")] internal static class Patch_Enemy_GetVisionFilter { private static readonly VisionTypeFilter None = default(VisionTypeFilter); private static readonly VisionTypeFilter PlayerOnly = new VisionTypeFilter((TargetType[])(object)new TargetType[1] { (TargetType)1 }); private static readonly VisionTypeFilter EnemyOnly = new VisionTypeFilter((TargetType[])(object)new TargetType[1] { (TargetType)2 }); private static readonly VisionTypeFilter PlayerAndEnemy = new VisionTypeFilter((TargetType[])(object)new TargetType[2] { (TargetType)1, (TargetType)2 }); private static bool Prefix(Enemy __instance, ref VisionTypeFilter __result, out long __state) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) __state = Prof.Now; if (!Cfg.FixVisionFilterAlloc.Value) { return true; } EnemyIdentifier eid = __instance.eid; if (!Object.op_Implicit((Object)(object)eid)) { __result = None; return false; } if (EnemiesHateEnemies.Active) { __result = PlayerAndEnemy; return false; } if ((int)eid.enemyType == 7 || (int)eid.enemyType == 12) { __result = PlayerAndEnemy; return false; } EnemyTarget target = eid.target; if (target != null && target.isEnemy) { __result = EnemyOnly; return false; } if (target != null && target.isPlayer) { __result = PlayerOnly; return false; } if (eid.attackEnemies) { __result = PlayerAndEnemy; return false; } __result = PlayerOnly; return false; } private static void Postfix(long __state) { Prof.Add(T.Enemy_GetVisionFilter, __state); } } [HarmonyPatch(typeof(EnemyTracker), "GetCurrentEnemies")] internal static class Patch_EnemyTracker_GetCurrentEnemies { private static readonly List<EnemyIdentifier> _cache = new List<EnemyIdentifier>(128); private static int _cacheFrame = -1; internal static void Invalidate() { _cacheFrame = -1; } private static bool Prefix(EnemyTracker __instance, ref List<EnemyIdentifier> __result, out long __state) { __state = Prof.Now; if (!Cfg.FixEnemyTrackerListAlloc.Value) { return true; } int frameCount = Time.frameCount; if (_cacheFrame != frameCount) { _cacheFrame = frameCount; _cache.Clear(); List<EnemyIdentifier> enemies = __instance.enemies; if (enemies != null) { for (int num = enemies.Count - 1; num >= 0; num--) { EnemyIdentifier val = enemies[num]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || val.dead) { __instance.RemoveEnemy(num); } else if (((Component)val).gameObject.activeInHierarchy) { _cache.Add(val); } } } } __result = _cache; return false; } private static void Postfix(long __state) { Prof.Add(T.EnemyTracker_GetCurrentEnemies, __state); } } [HarmonyPatch(typeof(EnemyTracker), "GetEnemiesOfType")] internal static class Patch_EnemyTracker_GetEnemiesOfType { private static bool Prefix(EnemyTracker __instance, EnemyType type, ref List<EnemyIdentifier> __result) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!Cfg.FixEnemyTrackerListAlloc.Value) { return true; } List<EnemyIdentifier> currentEnemies = __instance.GetCurrentEnemies(); List<EnemyIdentifier> list = new List<EnemyIdentifier>(currentEnemies.Count); for (int i = 0; i < currentEnemies.Count; i++) { if ((Object)(object)currentEnemies[i] != (Object)null && currentEnemies[i].enemyType == type) { list.Add(currentEnemies[i]); } } __result = list; return false; } } [HarmonyPatch(typeof(EnemyScanner), "Tick")] internal static class Patch_EnemyScanner_Tick { private static void Prefix(out long __state) { __state = Prof.Now; } private static void Postfix(long __state) { Prof.Add(T.EnemyScanner_Tick, __state); } } [HarmonyPatch(typeof(Idol), "PickNewTarget")] internal static class Patch_Idol_PickNewTarget { private static bool Prefix(Idol __instance, bool ignoreIfAlreadyTargeting, out long __state) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Invalid comparison between Unknown and I4 //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) __state = Prof.Now; if (!Cfg.FixIdolTrySeeHoist.Value) { return true; } if (ignoreIfAlreadyTargeting && ((Object)(object)__instance.target != (Object)null || ((Object)(object)__instance.overrideTarget != (Object)null && !((object)__instance.overrideTarget).Equals((object?)null)))) { return false; } EnemyTracker instance = MonoSingleton<EnemyTracker>.Instance; if ((Object)(object)instance == (Object)null) { return false; } List<EnemyIdentifier> currentEnemies = instance.GetCurrentEnemies(); if (currentEnemies == null || currentEnemies.Count <= 0) { return false; } Vector3 position = ((Component)__instance).transform.position; TargetDataRef val = default(TargetDataRef); bool flag = __instance.vision.TrySee(__instance.nearestQuery, ref val); float num = (flag ? Vector3.Distance(((TargetDataRef)(ref val)).position, position) : 0f); Vector3 val2 = (flag ? Vector3.zero : MonoSingleton<PlayerTracker>.Instance.GetPlayer().position); int num2 = ((!Object.op_Implicit((Object)(object)__instance.target) || __instance.target.dead) ? 1 : Mathf.Max(instance.GetEnemyRank(__instance.target), 2)); for (int num3 = 7; num3 > num2; num3--) { bool flag2 = false; float num4 = float.PositiveInfinity; __instance.tempTarget = null; for (int i = 0; i < currentEnemies.Count; i++) { EnemyIdentifier val3 = currentEnemies[i]; if ((Object)(object)val3 == (Object)null || ((Object)(object)val3 != (Object)(object)__instance.target && (val3.blessed || (int)val3.enemyType == 21))) { continue; } int enemyRank = instance.GetEnemyRank(val3); if (enemyRank == num3 || (enemyRank <= 2 && num3 == 2)) { float num5 = (flag ? num : Vector3.Distance(val2, ((Component)val3).transform.position)); if (num5 < num4) { num4 = num5; __instance.tempTarget = val3; flag2 = true; } } } if (flag2) { __instance.ChangeTarget(__instance.tempTarget); break; } } return false; } private static void Postfix(long __state) { Prof.Add(T.Idol_PickNewTarget, __state); } } public static class EngineStats { private class Counter { public string Name; public ProfilerRecorder Rec; public ProfilerMarkerDataUnit Unit; public double Accum; public long Samples; public double Peak; } private static readonly List<Counter> _counters = new List<Counter>(); private static bool _failed; private static readonly string[] Wanted = new string[33] { "Main Thread", "Render Thread", "CPU Main Thread Frame Time", "CPU Render Thread Frame Time", "CPU Total Frame Time", "GPU Frame Time", "FrameTime.GPU", "Gfx.WaitForPresentOnGfxThread", "WaitForTargetFPS", "Draw Calls Count", "SetPass Calls Count", "Batches Count", "Dynamic Batched Draw Calls Count", "Static Batched Draw Calls Count", "Instanced Batched Draw Calls Count", "Triangles Count", "Vertices Count", "Shadow Casters Count", "Used Textures Count", "Render Textures Count", "Visible Skinned Meshes Count", "GC Allocated In Frame", "GC Used Memory", "GC Reserved Memory", "System Used Memory", "Total Reserved Memory", "Physics.Simulate", "Active Dynamic Bodies", "Active Kinematic Bodies", "Animators Count", "Playable Directors Count", "Particle Systems Count", "AudioSources Count" }; public static bool Available { get { if (!_failed) { return _counters.Count > 0; } return false; } } public static void Initialize(bool dumpAll) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Invalid comparison between Unknown and I4 //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 try { List<ProfilerRecorderHandle> list = new List<ProfilerRecorderHandle>(); ProfilerRecorderHandle.GetAvailable(list); if (dumpAll) { DumpAvailable(list); } HashSet<string> hashSet = new HashSet<string>(Wanted, StringComparer.Ordinal); ProfilerRecorder rec = default(ProfilerRecorder); foreach (ProfilerRecorderHandle item in list) { ProfilerRecorderHandle current = item; if (((ProfilerRecorderHandle)(ref current)).Valid) { ProfilerRecorderDescription description; try { description = ProfilerRecorderHandle.GetDescription(current); } catch { continue; } string name = ((ProfilerRecorderDescription)(ref description)).Name; if (hashSet.Contains(name) && ((int)((ProfilerRecorderDescription)(ref description)).DataType == 2 || (int)((ProfilerRecorderDescription)(ref description)).DataType == 4 || (int)((ProfilerRecorderDescription)(ref description)).DataType == 3 || (int)((ProfilerRecorderDescription)(ref description)).DataType == 5 || (int)((ProfilerRecorderDescription)(ref description)).DataType == 6 || (int)((ProfilerRecorderDescription)(ref description)).DataType == 7)) { ((ProfilerRecorder)(ref rec))..ctor(current, 1, (ProfilerRecorderOptions)24); ((ProfilerRecorder)(ref rec)).Start(); _counters.Add(new Counter { Name = name, Rec = rec, Unit = ((ProfilerRecorderDescription)(ref description)).UnitType }); } } } Plugin.Log.LogInfo((object)($"engine counters attached: {_counters.Count} of {list.Count} available" + (dumpAll ? " (full list dumped above)" : ""))); } catch (Exception ex) { _failed = true; Plugin.Log.LogWarning((object)("engine counters unavailable in this build: " + ex.Message)); } } private static void DumpAvailable(List<ProfilerRecorderHandle> handles) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) StringBuilder stringBuilder = new StringBuilder(8192); stringBuilder.Append("all profiler counters exposed by this player build:\n"); List<string> list = new List<string>(); foreach (ProfilerRecorderHandle handle in handles) { ProfilerRecorderHandle current = handle; if (((ProfilerRecorderHandle)(ref current)).Valid) { try { ProfilerRecorderDescription description = ProfilerRecorderHandle.GetDescription(current); ProfilerCategory category = ((ProfilerRecorderDescription)(ref description)).Category; list.Add($" [{((ProfilerCategory)(ref category)).Name}] {((ProfilerRecorderDescription)(ref description)).Name} ({((ProfilerRecorderDescription)(ref description)).UnitType})"); } catch { } } } list.Sort(StringComparer.Ordinal); foreach (string item in list) { stringBuilder.Append(item).Append('\n'); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } public static void Sample() { if (_failed) { return; } for (int i = 0; i < _counters.Count; i++) { Counter counter = _counters[i]; if (((ProfilerRecorder)(ref counter.Rec)).Valid) { double lastValueAsDouble = ((ProfilerRecorder)(ref counter.Rec)).LastValueAsDouble; counter.Accum += lastValueAsDouble; counter.Samples++; if (lastValueAsDouble > counter.Peak) { counter.Peak = lastValueAsDouble; } } } } public static List<(string name, double avg, double peak, string unit)> Export() { List<(string, double, double, string)> list = new List<(string, double, double, string)>(); for (int i = 0; i < _counters.Count; i++) { Counter counter = _counters[i]; if (counter.Samples != 0L) { list.Add((counter.Name, counter.Accum / (double)counter.Samples, counter.Peak, ((object)Unsafe.As<ProfilerMarkerDataUnit, ProfilerMarkerDataUnit>(ref counter.Unit)/*cast due to .constrained prefix*/).ToString())); } } return list; } public static string[] CounterNames() { string[] array = new string[_counters.Count]; for (int i = 0; i < _counters.Count; i++) { array[i] = _counters[i].Name; } return array; } public static int WriteLastValues(float[] dest, int offset) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 for (int i = 0; i < _counters.Count; i++) { double num = 0.0; Counter counter = _counters[i]; if (((ProfilerRecorder)(ref counter.Rec)).Valid) { num = ((ProfilerRecorder)(ref counter.Rec)).LastValueAsDouble; } if ((int)counter.Unit == 1) { num /= 1000000.0; } dest[offset + i] = (float)num; } return _counters.Count; } public static void Reset() { for (int i = 0; i < _counters.Count; i++) { _counters[i].Accum = 0.0; _counters[i].Samples = 0L; _counters[i].Peak = 0.0; } } private static string Format(double v, ProfilerMarkerDataUnit unit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected I4, but got Unknown switch (unit - 1) { case 0: return (v / 1000000.0).ToString("F2") + " ms"; case 1: if (v >= 1048576.0) { return (v / 1048576.0).ToString("F1") + " MB"; } if (v >= 1024.0) { return (v / 1024.0).ToString("F1") + " KB"; } return v.ToString("F0") + " B"; case 3: return v.ToString("F1") + " %"; case 4: return v.ToString("F0") + " Hz"; default: return v.ToString("F0"); } } public static void AppendReport(StringBuilder sb) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (_failed || _counters.Count == 0) { return; } sb.Append(" engine counters (per frame avg | peak):\n"); for (int i = 0; i < _counters.Count; i++) { Counter counter = _counters[i]; if (counter.Samples != 0L) { double num = counter.Accum / (double)counter.Samples; if (num != 0.0 || counter.Peak != 0.0) { sb.AppendFormat(" {0,-34} {1,12} | {2}\n", counter.Name, Format(num, counter.Unit), Format(counter.Peak, counter.Unit)); } } } } public static void Dispose() { for (int i = 0; i < _counters.Count; i++) { try { ((ProfilerRecorder)(ref _counters[i].Rec)).Dispose(); } catch { } } _counters.Clear(); } } [HarmonyPatch(typeof(FadeOut), "Update")] internal static class Patch_FadeOut_Update { private static bool Prefix(FadeOut __instance) { if (!Cfg.FixExceptionSpam.Value) { return true; } AudioSource[] auds = __instance.auds; if (auds == null || auds.Length == 0) { return false; } if (__instance.origVol == null || __instance.origVol.Count < auds.Length) { return false; } for (int i = 0; i < auds.Length; i++) { if ((Object)(object)auds[i] == (Object)null) { return false; } } if (!__instance.fading && __instance.distance && (Object)(object)__instance.player == (Object)null) { return false; } return true; } } [HarmonyPatch(typeof(Explosion), "FixedUpdate")] internal static class Patch_Explosion_FixedUpdate { private static bool Prefix(Explosion __instance) { if (!Cfg.FixExceptionSpam.Value) { return true; } return (Object)(object)__instance.scol != (Object)null; } } public static class FrameTrace { private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; private static float[] _data; private static string[] _columns; private static int _stride; private static int _capacity; private static int _rows; private static bool _running; private static float _endTime; private static long[] _prevTimerTicks; private static long[] _prevPhaseTicks; private static int _fixedStepsThisFrame; public static bool Running => _running; public static int Rows => _rows; public static void NoteFixedStep() { if (_running) { _fixedStepsThisFrame++; } } public static void Start(float seconds, int maxFrames = 40000) { if (!_running) { List<string> list = new List<string> { "frame", "dtMs" }; for (int i = 0; i < 19; i++) { T t = (T)i; list.Add("t." + t); } string[] array = (PlayerLoopProf.Installed ? PlayerLoopProf.PhaseNames() : new string[0]); for (int j = 0; j < array.Length; j++) { list.Add("pl." + array[j]); } string[] array2 = EngineStats.CounterNames(); for (int k = 0; k < array2.Length; k++) { list.Add("ec." + array2[k].Replace(' ', '_')); } list.Add("timeScale"); list.Add("fixedSteps"); list.Add("portalPasses"); list.Add("onscreenPortals"); list.Add("visions"); list.Add("targets"); _columns = list.ToArray(); _stride = _columns.Length; _capacity = maxFrames; _data = new float[((long)_capacity * (long)_stride > int.MaxValue) ? 1 : (_capacity * _stride)]; _rows = 0; _prevTimerTicks = new long[19]; _prevPhaseTicks = new long[array.Length]; Prof.SnapshotTicks(_prevTimerTicks); if (array.Length != 0) { PlayerLoopProf.SnapshotTicks(_prevPhaseTicks); } _endTime = Time.realtimeSinceStartup + seconds; _running = true; Plugin.Log.LogInfo((object)$"frame trace started: {seconds:F1}s, {_stride} columns, capacity {_capacity} frames"); } } public static void Record() { if (!_running) { return; } if (_rows >= _capacity || Time.realtimeSinceStartup >= _endTime) { Stop(); return; } int num = _rows * _stride; int num2 = 0; _data[num + num2++] = Time.frameCount; _data[num + num2++] = Time.unscaledDeltaTime * 1000f; int num3 = 19; for (int i = 0; i < num3; i++) { long num4 = Prof.TicksOf(i); long num5 = _prevTimerTicks[i]; if (num4 < num5) { num5 = 0L; } _data[num + num2++] = (float)((double)(num4 - num5) * Prof.TickToMs); _prevTimerTicks[i] = num4; } if (_prevPhaseTicks.Length != 0) { for (int j = 0; j < _prevPhaseTicks.Length; j++) { long num6 = PlayerLoopProf.TicksOf(j); long num7 = _prevPhaseTicks[j]; if (num6 < num7) { num7 = 0L; } _data[num + num2++] = (float)((double)(num6 - num7) * Prof.TickToMs); _prevPhaseTicks[j] = num6; } } num2 += EngineStats.WriteLastValues(_data, num + num2); _data[num + num2++] = Time.timeScale; _data[num + num2++] = _fixedStepsThisFrame; _fixedStepsThisFrame = 0; _data[num + num2++] = Prof.GaugePasses; _data[num + num2++] = Prof.GaugeOnscreenPortals; _data[num + num2++] = Prof.GaugeVisions; _data[num + num2++] = Prof.GaugeTargets; _rows++; } public static string Stop() { if (!_running) { return null; } _running = false; string dir = Paths.Resolve(Cfg.CaptureDir.Value); Paths.Ensure(dir); string text = Paths.Join(dir, $"trace-{Time.frameCount}.csv"); StringBuilder stringBuilder = new StringBuilder(_rows * _stride * 8 + 1024); for (int i = 0; i < _columns.Length; i++) { if (i > 0) { stringBuilder.Append(','); } stringBuilder.Append(_columns[i]); } stringBuilder.Append('\n'); for (int j = 0; j < _rows; j++) { int num = j * _stride; for (int k = 0; k < _stride; k++) { if (k > 0) { stringBuilder.Append(','); } float num2 = _data[num + k]; stringBuilder.Append(num2.ToString((k < 1) ? "F0" : "G6", Inv)); } stringBuilder.Append('\n'); } File.WriteAllText(text, stringBuilder.ToString()); Plugin.Log.LogInfo((object)$"frame trace written: {text} ({_rows} frames x {_stride} columns)"); try { Plugin.Log.LogInfo((object)("capture written: " + Capture.Write(Paths.Resolve(Cfg.CaptureDir.Value)))); } catch (Exception ex) { Plugin.Log.LogWarning((object)("capture alongside trace failed: " + ex.Message)); } _data = null; return text; } } public static class JobWorkers { private static int _original = -1; public static int Original => _original; public static void Apply() { try { if (_original < 0) { _original = JobsUtility.JobWorkerCount; } int value = Cfg.JobWorkerCount.Value; int num = ((value <= 0) ? _original : Mathf.Clamp(value, 1, JobsUtility.JobWorkerMaximumCount)); if (JobsUtility.JobWorkerCount != num) { JobsUtility.JobWorkerCount = num; Plugin.Log.LogInfo((object)$"job workers: {num} (game default {_original}, max {JobsUtility.JobWorkerMaximumCount})"); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("job worker count not applied: " + ex.Message)); } } public static string Describe() { int value = Cfg.JobWorkerCount.Value; if (value > 0) { return value.ToString(); } return $"game({_original})"; } } [HarmonyPatch(typeof(Mannequin), "EvaluateMaxClingWalkDistance")] internal static class Patch_Mannequin_EvaluateMaxClingWalkDistance { private static bool Prefix(Mannequin __instance, Vector3 origin, Vector3 movementDirection, Vector3 backToWallDirection, float maxDistance, float incrementLength, ref float __result, out long __state) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) __state = Prof.Now; float num = Cfg.MannequinClingIncrement.Value; if (num <= 0f) { return true; } if (num < incrementLength) { num = incrementLength; } float num2 = 0f; Vector3 val = origin; Vector3 val2 = __instance.clingNormal * __instance.clungMovementTolerance; int num3 = LayerMask.op_Implicit(LayerMaskDefaults.Get((LMD)1)); int num4 = 0; bool flag = false; RaycastHit val3 = default(RaycastHit); RaycastHit val4 = default(RaycastHit); while (num2 < maxDistance) { num4++; bool flag2 = Physics.Raycast(new Ray(val + val2, backToWallDirection), ref val3, __instance.clungMovementTolerance * 2f, num3, (QueryTriggerInteraction)1); if (!(Vector3.Angle(((RaycastHit)(ref val3)).normal, __instance.clingNormal) < 5f)) { flag2 = false; } if (!flag2) { flag = true; break; } num4++; if (Physics.Raycast(new Ray(val + val2 - ((Vector3)(ref movementDirection)).normalized * 0.1f, movementDirection), ref val4, num * 1.25f, num3, (QueryTriggerInteraction)1)) { flag = true; break; } num2 += num; val += movementDirection * num; } Prof.Count(C.ClingRays, num4); __result = ((!flag && num2 == 0f) ? 0f : (num2 - num * 1.5f)); return false; } private static void Postfix(long __state) { Prof.Add(T.Mannequin_EvalClingWalk, __state); } } [HarmonyPatch(typeof(Mannequin), "RelocateWhileClinging")] internal static class Patch_Mannequin_RelocateWhileClinging { private static void Prefix(out long __state) { __state = Prof.Now; } private static void Postfix(long __state) { Prof.Add(T.Mannequin_RelocateClinging, __state); } } [HarmonyPatch(typeof(Mannequin), "CheckClings")] internal static class Patch_Mannequin_CheckClings { private static readonly Collider[] _buf = (Collider[])(object)new Collider[16]; private static bool Prefix(Mannequin __instance, out long __state) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) __state = Prof.Now; if (!Cfg.FixMannequinOverlapAlloc.Value) { return true; } bool firstClingCheck = __instance.firstClingCheck; __instance.firstClingCheck = false; int num = LayerMask.op_Implicit(LayerMaskDefaults.Get((LMD)1)); RaycastHit val = default(RaycastHit); if (Physics.Raycast(((Component)__instance).transform.position, Vector3.up, ref val, firstClingCheck ? 9.5f : 7f, num, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val)).normal.y <= 0f) { __instance.ClingToSurface(val); return false; } Vector3 velocity = __instance.rb.velocity; if (!firstClingCheck) { Vector3 val2 = new Vector3(velocity.x, 0f, velocity.z); if (!(((Vector3)(ref val2)).magnitude > 3f)) { goto IL_0112; } } Bounds bounds = __instance.col.bounds; Vector3 center = ((Bounds)(ref bounds)).center; if (Physics.OverlapSphereNonAlloc(center, 2f, _buf, num) > 0 && Physics.Raycast(center, _buf[0].ClosestPoint(center) - center, ref val, firstClingCheck ? 3.5f : 2f, num, (QueryTriggerInteraction)1)) { __instance.ClingToSurface(val); } goto IL_0112; IL_0112: return false; } private static void Postfix(long __state) { Prof.Add(T.Mannequin_CheckClings, __state); } } internal static class ModCompat { private const string FraudTweaksId = "FraudTweaks"; public static void Apply(Harmony harmony) { try { FixExplosions(harmony); } catch (Exception ex) { Plugin.Log.LogWarning((object)("compat: FraudTweaks explosion fix failed: " + ex.Message)); } try { FraudTweaksBounds.Install(harmony); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("compat: FraudTweaks bounds fix failed: " + ex2.Message)); } } private static void FixExplosions(Harmony harmony) { if (!Cfg.FixFraudTweaksExplosions.Value) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(Explosion), "CheckPortalOverlaps", (Type[])null, (Type[])null); if (methodInfo == null) { return; } List<Patch> list = Harmony.GetPatchInfo((MethodBase)methodInfo)?.Prefixes.Where((Patch p) => p.owner == "FraudTweaks").ToList(); if (list == null || list.Count == 0) { return; } if (!FraudTweaksApiMissing()) { Plugin.Log.LogInfo((object)"compat: FraudTweaks explosion prefix links against this game build, left in place."); return; } foreach (Patch item in list) { harmony.Unpatch((MethodBase)methodInfo, item.PatchMethod); } Plugin.Log.LogInfo((object)"compat: removed FraudTweaks' Explosion.CheckPortalOverlaps prefix - it calls a Portal.GetTransform overload this game build no longer has and threw on every explosion tick. The game's native portal check runs instead."); } private static bool FraudTweaksApiMissing() { MethodInfo methodInfo = AccessTools.Method(typeof(Portal), "GetTransform", new Type[1] { typeof(PortalSide) }, (Type[])null); if (!(methodInfo == null)) { return methodInfo.ReturnType.FullName != "ULTRAKILL.Portal.Geometry.PortalTransform"; } return true; } } internal static class FraudTweaksBounds { private static List<Bounds> _bounds; private static List<Transform> _parents; private static Dictionary<GameObject, bool> _active; private static readonly List<GameObject> _keys = new List<GameObject>(256); private static readonly List<BoxCollider> _cols = new List<BoxCollider>(16); private static int _loggedCount = -1; public static void Install(Harmony harmony) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown if (!Cfg.FastFraudTweaksBounds.Value) { return; } MethodInfo theirs = AccessTools.Method("FraudTweaks.LevelSpecifics.LevelFinder:BoundsRunner", (Type[])null, (Type[])null); Type type = AccessTools.TypeByName("FraudTweaks.FraudTweaks"); MethodInfo methodInfo = AccessTools.Method(typeof(StatsManager), "Update", (Type[])null, (Type[])null); if (theirs == null || type == null || methodInfo == null) { return; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo != null && patchInfo.Prefixes.Any((Patch p) => p.PatchMethod == theirs)) { _bounds = AccessTools.Field(type, "OutofboundsList")?.GetValue(null) as List<Bounds>; _parents = AccessTools.Field(type, "OutofboundsParents")?.GetValue(null) as List<Transform>; _active = AccessTools.Field(type, "OutofboundsActive")?.GetValue(null) as Dictionary<GameObject, bool>; if (_bounds == null || _parents == null || _active == null) { Plugin.Log.LogWarning((object)"compat: FraudTweaks bounds state has changed shape, leaving its BoundsRunner alone."); return; } harmony.Unpatch((MethodBase)methodInfo, theirs); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(FraudTweaksBounds), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"compat: replaced FraudTweaks' OopsBlocker BoundsRunner (O(n^2) + allocations per frame) with a linear one."); } } private static void Prefix() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) int count = _bounds.Count; if (count == 0) { return; } if (count != _loggedCount) { _loggedCount = count; Plugin.Log.LogInfo((object)("compat: FraudTweaks is tracking " + count + " OopsBlockers in this level.")); } NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.playerCollider == (Object)null) { return; } Bounds bounds = ((Collider)instance.playerCollider).bounds; Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; _keys.Clear(); foreach (KeyValuePair<GameObject, bool> item in _active) { _keys.Add(item.Key); } for (int i = 0; i < count && i < _parents.Count; i++) { Transform val = _parents[i]; if ((Object)(object)val == (Object)null || i >= _keys.Count) { continue; } GameObject val2 = _keys[i]; if ((Object)(object)val2 == (Object)null) { continue; } Bounds val3 = _bounds[i]; int num; if (((Bounds)(ref val3)).Contains(min)) { val3 = _bounds[i]; num = (((Bounds)(ref val3)).Contains(max) ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; bool flag2 = false; if (flag) { ((Component)val).GetComponentsInChildren<BoxCollider>(false, _cols); for (int j = 0; j < _cols.Count; j++) { Bounds bounds2 = ((Collider)_cols[j]).bounds; if (((Bounds)(ref bounds2)).Contains(min) && ((Bounds)(ref bounds2)).Contains(max)) { flag2 = true; break; } } } bool flag3 = _active[val2]; GameObject gameObject = ((Component)val).gameObject; if (!flag2 && flag) { if (flag3 && !gameObject.activeSelf) { gameObject.SetActive(true); _active[val2] = flag3; } } else if (gameObject.activeSelf) { gameObject.SetActive(false); _active[val2] = flag3; } } } } internal static class Paths { public static string Join(string dir, string file) { if (string.IsNullOrEmpty(dir)) { return file; } return dir.TrimEnd('/', '\\') + "/" + file; } public static string Resolve(string configured) { if (!string.IsNullOrEmpty(configured)) { return configured; } return Path.Combine(Paths.ConfigPath, "UltraPerformance"); } public static void Ensure(string dir) { try { Directory.CreateDirectory(dir); } catch { } } } public static class PlayerLoopProf { [StructLayout(LayoutKind.Sequential, Size = 1)] private struct Begin<T> { } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct End<T> { } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct FrameEnd { } private class Phase { public string Name; public int Depth; public long Start; public long Ticks; public int Calls; } [CompilerGenerated] private static class <>O { public static UpdateFunction <0>__Record; } private static readonly List<Phase> _phases = new List<Phase>(); private static PlayerLoopSystem _original; private static bool _installed; public static bool Installed => _installed; public static void Install() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown if (_installed) { return; } _original = PlayerLoop.GetCurrentPlayerLoop(); PlayerLoopSystem currentPlayerLoop = PlayerLoop.GetCurrentPlayerLoop(); PlayerLoopSystem[] subSystemList = currentPlayerLoop.subSystemList; if (subSystemList == null || subSystemList.Length == 0) { Plugin.Log.LogWarning((object)"player loop is empty; not instrumenting"); return; } List<PlayerLoopSystem> list = new List<PlayerLoopSystem>(Wrap(subSystemList, "", Cfg.PlayerLoopDepth.Value)); PlayerLoopSystem item = new PlayerLoopSystem { type = typeof(End<FrameEnd>) }; object obj = <>O.<0>__Record; if (obj == null) { UpdateFunction val = FrameTrace.Record; <>O.<0>__Record = val; obj = (object)val; } item.updateDelegate = (UpdateFunction)obj; list.Add(item); currentPlayerLoop.subSystemList = list.ToArray(); PlayerLoop.SetPlayerLoop(currentPlayerLoop); _installed = true; Plugin.Log.LogInfo((object)$"player loop instrumented: {_phases.Count} top-level phases wrapped"); } private static PlayerLoopSystem[] Wrap(PlayerLoopSystem[] systems, string prefix, int depth) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) List<PlayerLoopSystem> list = new List<PlayerLoopSystem>(systems.Length * 3); for (int i = 0; i < systems.Length; i++) { PlayerLoopSystem val = systems[i]; if (val.type == null) { list.Add(val); continue; } if (depth > 1 && val.subSystemList != null && val.subSystemList.Length != 0) { val.subSystemList = Wrap(val.subSystemList, prefix + val.type.Name + ".", depth - 1); } int idx = _phases.Count; _phases.Add(new Phase { Name = prefix + val.type.Name, Depth = ((prefix.Length != 0) ? 1 : 0) }); bool flag = val.type.Name == "FixedUpdate" && prefix.Length == 0; list.Add(new PlayerLoopSystem { type = typeof(Begin<>).MakeGenericType(val.type), updateDelegate = (flag ? ((UpdateFunction)delegate { _phases[idx].Start = Prof.Now; FrameTrace.NoteFixedStep(); }) : ((UpdateFunction)delegate { _phases[idx].Start = Prof.Now; })) }); list.Add(val); list.Add(new PlayerLoopSystem { type = typeof(End<>).MakeGenericType(val.type), updateDelegate = (UpdateFunction)delegate { Phase phase = _phases[idx]; phase.Ticks += Prof.Now - phase.Start; phase.Calls++; } }); } return list.ToArray(); } public static void Uninstall() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (_installed) { PlayerLoop.SetPlayerLoop(_original); _installed = false; } } public static List<(string name, int depth, double msf, double cpf)> Export(int frames) { List<(string, int, double, double)> list = new List<(string, int, double, double)>(); for (int i = 0; i < _phases.Count; i++) { Phase phase = _phases[i]; list.Add((phase.Name, phase.Depth, (double)phase.Ticks * Prof.TickToMs / (double)Math.Max(frames, 1), (double)phase.Calls / (double)Math.Max(frames, 1))); } return list; } public static string[] PhaseNames() { string[] array = new string[_phases.Count]; for (int i = 0; i < _phases.Count; i++) { array[i] = _phases[i].Name; } return array; } public static long TicksOf(int i) { return _phases[i].Ticks; } public static void SnapshotTicks(long[] dest) { int num = Math.Min(dest.Length, _phases.Count); for (int i = 0; i < num; i++) { dest[i] = _phases[i].Ticks; } } public static void Reset() { for (int i = 0; i < _phases.Count; i++) { _phases[i].Ticks = 0L; _phases[i].Calls = 0; } } public static void AppendReport(StringBuilder sb, int frames, double avgFrameMs) { if (!_installed || _phases.Count == 0) { return; } double num = 0.0; for (int i = 0; i < _phases.Count; i++) { if (_phases[i].Depth == 0) { num += (double)_phases[i].Ticks * Prof.TickToMs; } } num /= (double)Math.Max(frames, 1); sb.AppendFormat(" player loop: {0:F2} ms/f across {1} phases (frame is {2:F2} ms)\n", num, _phases.Count, avgFrameMs); List<Phase> list = new List<Phase>(_phases); list.Sort((Phase a, Phase b) => b.Ticks.CompareTo(a.Ticks)); for (int num2 = 0; num2 < list.Count; num2++) { Phase phase = list[num2]; double num3 = (double)phase.Ticks * Prof.TickToMs / (double)Math.Max(frames, 1); if (!(num3 < 0.02)) { sb.AppendFormat(" {0}{1,-40} {2,7:F3} ms/f {3,5:F1}% {4,6:F1} calls/f\n", (phase.Depth == 0) ? "" : " ", phase.Name, num3, (avgFrameMs > 0.0) ? (100.0 * num3 / avgFrameMs) : 0.0, (double)phase.Calls / (double)Math.Max(frames, 1)); } } } } [BepInPlugin("reedo.ultraperformance", "UltraPerformance", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "reedo.ultraperformance"; internal static ManualLogSource Log; internal static Plugin Instance; private Harmony _harmony; private float _sinceReport; private bool _overlay; private string _overlayText = ""; private GUIStyle _style; private readonly List<string> _patchFailures = new List<string>(); private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Cfg.Init(((BaseUnityPlugin)this).Config); _overlay = Cfg.OverlayOnByDefault.Value; _harmony = new Harmony("reedo.ultraperformance"); ApplyClass(typeof(Patch_TargetTracker_UpdateData)); ApplyClass(typeof(Patch_PortalScene_Sync)); ApplyClass(typeof(Patch_Vision_TrySee)); ApplyClass(typeof(Patch_Enemy_GetVisionFilter)); ApplyClass(typeof(Patch_EnemyTracker_GetCurrentEnemies)); ApplyClass(typeof(Patch_EnemyTracker_GetEnemiesOfType)); ApplyClass(typeof(Patch_EnemyScanner_Tick)); ApplyClass(typeof(Patch_Idol_PickNewTarget)); ApplyClass(typeof(Patch_Mannequin_EvaluateMaxClingWalkDistance)); ApplyClass(typeof(Patch_Mannequin_RelocateWhileClinging)); ApplyClass(typeof(Patch_Mannequin_CheckClings)); ApplyClass(typeof(Patch_FadeOut_Update)); ApplyClass(typeof(Patch_Explosion_FixedUpdate)); ApplyClass(typeof(Patch_PortalRender_Setup)); ApplyClass(typeof(Patch_PortalRender_Render)); ApplyClass(typeof(Patch_PortalRender_DepthPrepass)); ApplyClass(typeof(Patch_PortalRender_UpdatePortalLights)); ApplyClass(typeof(Patch_PortalManager_UpdateAwareRenderers)); ApplyManual("TargetDataExtensions.IsObstructed", delegate { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_005f: Expected O, but got Unknown MethodInfo methodInfo = Patch_IsObstructed.Target(); if (methodInfo == null) { throw new Exception("method not found"); } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(Patch_IsObstructed), "Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.Method(typeof(Patch_IsObstructed), "Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); }); if (Cfg.Measure.Value && Cfg.InstrumentCameraRender.Value) { ApplyManual("Camera.Render (diagnostic)", delegate { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_005f: Expected O, but got Unknown MethodInfo methodInfo = Patch_Camera_Render.Target(); if (methodInfo == null) { throw new Exception("method not found"); } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(Patch_Camera_Render), "Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.Method(typeof(Patch_Camera_Render), "Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); }); } EngineStats.Initialize(Cfg.DumpAllCounters.Value); CameraProf.Install(); JobWorkers.Apply(); if (Cfg.Measure.Value && Cfg.PlayerLoopProfile.Value) { ApplyManual("player loop profile", PlayerLoopProf.Install); } Prof.Reset(); Log.LogInfo((object)("UltraPerformance ready. " + ((_patchFailures.Count == 0) ? "all patches applied." : (_patchFailures.Count + " patch group(s) failed: " + string.Join(", ", _patchFailures))))); CheckGameBuild(); Log.LogInfo((object)$"overlay={Cfg.OverlayKey.Value} dump={Cfg.DumpKey.Value} config={((BaseUnityPlugin)this).Config.ConfigFilePath}"); } private void CheckGameBuild() { string text; try { text = typeof(EnemyIdentifier).Assembly.ManifestModule.ModuleVersionId.ToString("N"); } catch (Exception ex) { Log.LogWarning((object)("could not read game build id: " + ex.Message)); return; } string value = Cfg.KnownGameBuild.Value; if (string.IsNullOrEmpty(value)) { Log.LogInfo((object)("game build id " + text + " recorded.")); } else if (value != text) { Log.LogWarning((object)("GAME UPDATED since this plugin last ran (build " + value + " -> " + text + "). " + ((_patchFailures.Count == 0) ? "Every patch group still applied, but re-check behaviour before trusting the game-code fixes." : ("These patch groups no longer apply and are OFF: " + string.Join(", ", _patchFailures) + ". Engine-level features are unaffected.")))); } Cfg.KnownGameBuild.Value = text; } private void Start() { try { ModCompat.Apply(_harmony); } catch (Exception ex) { Log.LogWarning((object)("mod compat fixes failed: " + ex.Message)); } if (Cfg.Measure.Value && Cfg.ScriptSweep.Value) { ApplyManual("script sweep", delegate { ScriptSweep.Initialize(_harmony); }); } } private void ApplyClass(Type t) { ApplyManual(t.Name, delegate { _harmony.CreateClassProcessor(t).Patch(); }); } private void ApplyManual(string label, Action apply) { try { apply(); } catch (Exception ex) { _patchFailures.Add(label); Log.LogWarning((object)("patch group '" + label + "' failed (continuing without it): " + ex.Message)); } } private void Update() { ScriptSweep.EndFrame(Time.unscaledDeltaTime * 1000f); if (!Cfg.Measure.Value) { return; } HandleProfilerKeys(); HandleTuningKeys(); Prof.FrameTick(Time.unscaledDeltaTime); EngineStats.Sample(); _sinceReport += Time.unscaledDeltaTime; if (!(_sinceReport >= Mathf.Max(0.5f, Cfg.ReportInterval.Value))) { return; } _sinceReport = 0f; if (Prof.Frames > 0) { if (Cfg.LogReports.Value) { Log.LogInfo((object)("\n" + Prof.BuildReport(compact: false))); } if (_overlay) { _overlayText = Prof.BuildReport(compact: true); } } ResetWindow(); } private void HandleProfilerKeys() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(Cfg.OverlayKey.Value)) { _overlay = !_overlay; Log.LogInfo((object)("overlay " + (_overlay ? "on" : "off"))); } if (Input.GetKeyDown(Cfg.DumpKey.Value)) { Log.LogInfo((object)("\n" + Prof.BuildReport(compact: false))); } if (Input.GetKeyDown(Cfg.BatchAuditKey.Value)) { try { Log.LogInfo((object)("\n" + SettingsDump.Run() + "\n" + BatchAudit.Run())); } catch (Exception ex) { Log.LogError((object)("batch audit failed: " + ex)); } } if (Input.GetKeyDown(Cfg.TraceKey.Value)) { if (FrameTrace.Running) { FrameTrace.Stop(); } else { FrameTrace.Start(Cfg.TraceSeconds.Value); } } if (!Input.GetKeyDown(Cfg.CaptureKey.Value)) { return; } try { string text = Capture.Write(Paths.Resolve(Cfg.CaptureDir.Value)); Log.LogInfo((object)("CAPTURE written: " + text)); if (Cfg.CaptureMemorySnapshot.Value) { Capture.WriteMemorySnapshot(Paths.Resolve(Cfg.CaptureDir.Value), delegate(string p, bool ok) { Log.LogInfo((object)("memory snapshot " + (ok ? "written" : "FAILED") + ": " + p)); }); } } catch (Exception ex2) { Log.LogError((object)("capture failed: " + ex2)); } } private void HandleTuningKeys() { if (Input.GetKeyDown((KeyCode)287)) { if (!Cfg.PortalAdaptiveRecursion.Value && Cfg.PortalMaxRecursions.Value == 0) { Cfg.PortalAdaptiveRecursion.Value = true; } else if (Cfg.PortalAdaptiveRecursion.Value) { Cfg.PortalAdaptiveRecursion.Value = false; Cfg.PortalMaxRecursions.Value = 2; } else if (Cfg.PortalMaxRecursions.Value == 2) { Cfg.PortalMaxRecursions.Value = 1; } else { Cfg.PortalMaxRecursions.Value = 0; } Announce(); } if (Input.GetKeyDown((KeyCode)288)) { int value = Cfg.JobWorkerCount.Value; Cfg.JobWorkerCount.Value = value switch { 4 => 2, 6 => 4, 0 => 6, _ => 0, }; JobWorkers.Apply(); Announce(); } if (Input.GetKeyDown((KeyCode)289)) { Cfg.NoDistanceSort.Value = !Cfg.NoDistanceSort.Value; Announce(); } } private static void ResetWindow() { if (!FrameTrace.Running) { Prof.Reset(); EngineStats.Reset(); ScriptSweep.Reset(); PlayerLoopProf.Reset(); CameraProf.Reset(); } } internal static string KnobLine() { return string.Format("knobs: recursion={0} fallback={2} sort={3} workers={4} minAreaFrac={1}", Cfg.PortalAdaptiveRecursion.Value ? $"adaptive {Cfg.PortalAdaptiveNearDepth.Value}/{Cfg.PortalAdaptiveFarDepth.Value} @near>{Cfg.PortalAdaptiveNearSize.Value:0.###}" : ((Cfg.PortalMaxRecursions.Value == 0) ? "game(3)" : ("flat " + Cfg.PortalMaxRecursions.Value)), (Cfg.PortalMinPixelAreaFraction.Value <= 0f) ? "game" : Cfg.PortalMinPixelAreaFraction.Value.ToString("0.###"), PortalFallback.Describe(), Cfg.NoDistanceSort.Value ? "noDistance" : "game", JobWorkers.Describe()); } private void Announce() { ResetWindow(); _sinceReport = 0f; Log.LogInfo((object)KnobLine()); } private void OnGUI() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (_overlay && _overlayText.Length != 0) { if (_style == null) { _style = new GUIStyle(GUI.skin.label) { fontSize = 13, alignment = (TextAnchor)0, richText = false }; _style.normal.textColor = Color.white; } Rect val = new Rect(8f, 8f, 780f, 220f); GUI.color = new Color(0f, 0f, 0f, 0.55f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUI.Label(new Rect(14f, 12f, 768f, 212f), _overlayText, _style); } } } public static class PortalFallback { private static readonly Dictionary<int, bool> _originalFlags = new Dictionary<int, bool>(); private static readonly List<(Portal portal, RenderTexture tex)> _owned = new List<(Portal, RenderTexture)>(); private static bool _active; private static bool _hooked; private static int _cursor; public static bool Active => _active; public static int Flagged { get; private set; } public static int Allocated { get; private set; } public static long Boosts { get; private set; } public static void Apply(List<Portal> portals, bool clampActive) { if (!clampActive || !Cfg.PortalFallbackForAll.Value) { if (_active) { Restore(portals); } return; } _active = true; int num = 0; int size = Mathf.Clamp(Cfg.PortalFallbackTexSize.Value, 64, 4096); for (int i = 0; i < portals.Count; i++) { Portal val = portals[i]; if ((Object)(object)val == (Object)null) { continue; } if (!val.supportInfiniteRecursion) { int instanceID = ((Object)val).GetInstanceID(); if (!_originalFlags.ContainsKey(instanceID)) { _originalFlags[instanceID] = false; } val.supportInfiniteRecursion = true; } if ((Object)(object)val.fakeEnterTex == (Object)null || (Object)(object)val.fakeExitTex == (Object)null) { Allocate(val, size); } num++; } Flagged = num; } private static void Allocate(Portal p, int size) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) float num = 1f; if (p.shape is PlaneShape val && val.height > 0f && val.width > 0f) { num = val.width / val.height; } int num2 = Mathf.Clamp(Mathf.RoundToInt((float)size / num), 16, 4096); if ((Object)(object)p.fakeEnterTex == (Object)null) { p.fakeEnterTex = new RenderTexture(size, num2, 0, (RenderTextureFormat)0) { name = "UltraPerformance fake enter" }; _owned.Add((p, p.fakeEnterTex)); } if ((Object)(object)p.fakeExitTex == (Object)null) { p.fakeExitTex = new RenderTexture(size, num2, 0, (RenderTextureFormat)0) { name = "UltraPerformance fake exit" }; _owned.Add((p, p.fakeExitTex)); } Allocated++; if (!_hooked) { SceneManager.sceneUnloaded += OnSceneUnloaded; _hooked = true; } } private static void OnSceneUnloaded(Scene _) { int num = 0; for (int num2 = _owned.Count - 1; num2 >= 0; num2--) { var (val, val2) = _owned[num2];