Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MEL Performance v0.1.0
plugins/VSM.Perf/VSM.Perf.dll
Decompiled 2 weeks 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.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Profiling; using Unity.Profiling.LowLevel.Unsafe; using UnityEngine; using UnityEngine.Events; using UnityEngine.Profiling; using UnityEngine.UI; using VSM.Perf.Infra; using VSM.Perf.Logic; using VSM.Perf.Runtime; using Valheim.SettingsGui; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("VSM.Perf")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+0defb453dde03b7e7af06426a514a561b6c81bb7")] [assembly: AssemblyProduct("VSM.Perf")] [assembly: AssemblyTitle("VSM.Perf")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.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 VSM.Perf { [BepInPlugin("vsm.perf", "MEL Performance", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class PerfPlugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigFile Cfg; internal static string DataDir; private Harmony _harmony; public static ConfigEntry<bool> Enabled; public static ConfigEntry<KeyboardShortcut> OverlayKey; public static ConfigEntry<bool> OverlayOnStart; public static ConfigEntry<bool> DeferAssetUnload; public static ConfigEntry<int> PointShadowBudget; public static ConfigEntry<PointShadowQuality> PointShadowResolution; public static ConfigEntry<float> SunSmallShadowCull; public static ConfigEntry<float> SunShadowDistance; public static ConfigEntry<bool> DepthNormalsOff; public static ConfigEntry<float> SpawnBudgetMs; public static ConfigEntry<float> SpawnMaxExtraDelay; public static ConfigEntry<bool> HorizonIntegration; public static ConfigEntry<string> ProfilerExtraTargets; public static ConfigEntry<int> BenchSeconds; internal static bool On { get { if (Enabled != null) { return Enabled.Value; } return false; } } private void Awake() { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Cfg = ((BaseUnityPlugin)this).Config; try { BindConfig(); } catch (Exception ex) { Log.LogError((object)("vsm.perf: error preparando la configuración; el mod queda apagado: " + ex)); return; } Log.LogInfo((object)("vsm.perf 0.1.0 | Valheim " + Env.GameVersion + " | Unity " + Application.unityVersion + " | headless=" + Env.IsHeadless)); if (Env.IsHeadless) { Log.LogInfo((object)"vsm.perf: servidor dedicado: nada que hacer (mod de cliente)."); return; } try { DataDir = Path.Combine(Paths.ConfigPath, "vsm.perf"); PerfLocalization.Register(Log, Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), PerfTexts.Spanish()); _harmony = new Harmony("vsm.perf"); SafePatch.PatchAll(Log, _harmony, typeof(PerfPlugin).Assembly); SettingsRow.SavePatched = IsPatchedByUs(AccessTools.DeclaredMethod(typeof(AccessibilitySettings), "OnOkAsync", new Type[1] { typeof(OkActionCompletedHandler) }, (Type[])null)); ((Component)this).gameObject.AddComponent<PerfController>(); Log.LogInfo((object)("vsm.perf: " + (Enabled.Value ? "encendido" : "apagado (se enciende en Ajustes → Accesibilidad → MEL Performance)") + ".")); } catch (Exception ex2) { Log.LogError((object)("vsm.perf: no se pudo iniciar; el mod queda apagado: " + ex2)); } } private void BindConfig() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Expected O, but got Unknown //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Expected O, but got Unknown //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Expected O, but got Unknown //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Expected O, but got Unknown //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Expected O, but got Unknown //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Expected O, but got Unknown Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enabled", false, new ConfigDescription("Interruptor general de MEL Performance (experimental). Viene apagado: se enciende en Ajustes → Accesibilidad → \"MEL Performance (más FPS)\", aquí o con vsm_perf on. Apagado, el juego queda exactamente como sin el mod.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 101 } })); OverlayKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. General", "OverlayKey", new KeyboardShortcut((KeyCode)290, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), new ConfigDescription("Muestra u oculta el medidor (FPS, 1 % low, draw calls, sombras, piezas, horizon…). Comando: vsm_perf hud.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); OverlayOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "OverlayOnStart", false, new ConfigDescription("Mostrar el medidor al entrar al juego.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); DeferAssetUnload = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Picos", "DeferAssetUnload", true, new ConfigDescription("Cada hora el juego descarga lo que no usa y recolecta basura (congelón de 0,1–0,5 s). Con esto, si te toca jugando se aplaza a un momento tranquilo (menú, inventario, durmiendo, carga o 30 s sin tocar nada), como mucho una hora más.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); PointShadowBudget = ((BaseUnityPlugin)this).Config.Bind<int>("3. Sombras", "PointShadowBudget", 4, new ConfigDescription("Máximo de luces puntuales (antorchas, fogatas…) con sombra a la vez. Se quedan con sombra las que más se ven (la que te ilumina, siempre); al resto se le quita solo mientras se dibuja el frame (el sigilo no cambia). Solo quita sombras que el juego haya dado: si en Ajustes tienes pocas, esto no cambia nada. -1 = como el juego.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 32), new object[1] { new ConfigurationManagerAttributes { Order = 80 } })); PointShadowResolution = ((BaseUnityPlugin)this).Config.Bind<PointShadowQuality>("3. Sombras", "PointShadowResolution", PointShadowQuality.Vanilla, new ConfigDescription("Resolución de las sombras de luces puntuales. Vanilla = como el juego; Balanced = igual de cerca, 512 a media distancia y 256 lejos; Low = 512 cerca y 256 el resto.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 79 } })); SunSmallShadowCull = ((BaseUnityPlugin)this).Config.Bind<float>("3. Sombras", "SunSmallShadowCull", 0f, new ConfigDescription("Distancia (m) hasta la que proyectan sombra del sol los objetos chicos (objetos tirados, decoración chica, antorchas y alfombras). 0 = como el juego. Probar 30–50.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 150f), new object[1] { new ConfigurationManagerAttributes { Order = 78 } })); SunShadowDistance = ((BaseUnityPlugin)this).Config.Bind<float>("3. Sombras", "SunShadowDistance", 0f, new ConfigDescription("Distancia de las sombras del sol (m). 0 = la de tu calidad de sombras en Ajustes (80/120/150 m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), new object[1] { new ConfigurationManagerAttributes { Order = 77 } })); DepthNormalsOff = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Cámara", "DepthNormalsOff", false, new ConfigDescription("EXPERIMENTAL. El juego pide siempre a la cámara una textura de profundidad + normales (puede costar una pasada extra de toda la escena). Con esto pide solo profundidad. Si algún efecto se ve raro, apágalo (compáralo con: vsm_perf diff depthnormals).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 70 } })); SpawnBudgetMs = ((BaseUnityPlugin)this).Config.Bind<float>("5. Carga de objetos", "SpawnBudgetMs", 4f, new ConfigDescription("Al llegar a una base el juego crea muchos objetos de golpe (tirones). Tiempo máximo (ms) por tanda para crearlos; nunca menos que el mínimo del juego ni en pantallas de carga. 0 = como el juego.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), new object[1] { new ConfigurationManagerAttributes { Order = 60 } })); SpawnMaxExtraDelay = ((BaseUnityPlugin)this).Config.Bind<float>("5. Carga de objetos", "SpawnMaxExtraDelaySeconds", 1.5f, new ConfigDescription("Como mucho cuántos segundos más que el juego puede tardar en aparecer todo. Con MEL Horizons cargado se limita además al 10 % de su MinLoadedSeconds (para que no guarde bases a medio llegar).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 10f), new object[1] { new ConfigurationManagerAttributes { Order = 59 } })); HorizonIntegration = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Integración", "Horizon", true, new ConfigDescription("Si está MEL Horizons (vsm.horizon): mostrar su costo en el medidor y el benchmark, medirlo en el instrumentador, ajustar el plazo de carga de objetos y dejar fijo su modo adaptativo mientras corre un benchmark. No hace falta tenerlo.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 50 } })); ProfilerExtraTargets = ((BaseUnityPlugin)this).Config.Bind<string>("9. Medición", "ProfilerExtraTargets", string.Empty, new ConfigDescription("Métodos extra para el instrumentador (vsm_perf prof on), separados por coma: Tipo.Método (p. ej. Player.Update, ClutterSystem.LateUpdate).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 10, IsAdvanced = true } })); BenchSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("9. Medición", "BenchSeconds", 30, new ConfigDescription("Duración por defecto de la medición de un benchmark (s), sin contar la espera y el calentamiento.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 300), new object[1] { new ConfigurationManagerAttributes { Order = 9 } })); } private static bool IsPatchedByUs(MethodBase method) { if (method == null) { return false; } Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo != null) { return patchInfo.Owners.Contains("vsm.perf"); } return false; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "vsm.perf"; public const string PLUGIN_NAME = "MEL Performance"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace VSM.Perf.Runtime { internal static class AssetUnload { private static readonly DeferPolicy s_policy = new DeferPolicy(); private static bool s_bypass; public static DeferPolicy Policy => s_policy; public static bool OnPeriodic() { if (s_bypass) { return true; } bool num = s_policy.OnPeriodic(PerfPlugin.On && PerfPlugin.DeferAssetUnload.Value, IsSafeMoment(), Time.realtimeSinceStartup); if (!num) { PerfPlugin.Log.LogInfo((object)"vsm.perf: limpieza de assets de cada hora aplazada hasta un momento tranquilo."); } return num; } public static void Tick() { if (!s_policy.Pending) { return; } Game instance = Game.instance; if ((Object)(object)instance == (Object)null || !s_policy.Poll(PerfPlugin.On && PerfPlugin.DeferAssetUnload.Value, IsSafeMoment(), MemoryHigh(), Time.realtimeSinceStartup)) { return; } PerfPlugin.Log.LogInfo((object)"vsm.perf: ejecutando la limpieza de assets aplazada."); s_bypass = true; try { instance.CollectResourcesCheckPeriodic(); } catch (Exception ex) { PerfPlugin.Log.LogWarning((object)("vsm.perf: la limpieza aplazada falló: " + ex.Message)); } finally { s_bypass = false; } } public static bool IsSafeMoment() { Player localPlayer = Player.m_localPlayer; bool loading = (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting(); bool sleeping = (Object)(object)localPlayer != (Object)null && localPlayer.IsSleeping(); double idleSeconds = 0.0; try { if (ZInput.instance != null) { idleSeconds = (DateTime.Now - ZInput.instance.GetLastInputTimer()).TotalSeconds; } } catch (Exception) { idleSeconds = 0.0; } return DeferPolicy.IsSafeMoment(Menu.IsVisible(), InventoryGui.IsVisible(), sleeping, loading, idleSeconds); } private static bool MemoryHigh() { long num = (long)SystemInfo.systemMemorySize * 1024L * 1024; if (num > 0) { return Profiler.GetTotalReservedMemoryLong() > num * 8 / 10; } return false; } } internal struct BenchPoint { public string Name; public Vector3 Position; public float Yaw; } internal sealed class BenchRunner { public const float MaxDistanceFromPoint = 2.5f; public static bool SweepActive; public static float SweepYaw; public static float SweepPitch; private readonly Counters _counters; private readonly Toggles _toggles; private readonly HorizonBridge _horizon; private readonly List<float> _frames = new List<float>(); private double[] _counterSum; private int[] _counterN; private BenchPlan _plan; private BenchPoint _point; private string _label; private StreamWriter _csv; private Action<BenchResult> _onDone; private Action<string> _onCancel; public bool Running => _plan != null; public string Status { get { if (_plan == null) { return string.Empty; } string text = ((_plan.Phase == BenchPhase.Settle) ? "esperando a que todo cargue" : ((_plan.Phase == BenchPhase.Warmup) ? "calentando" : "midiendo")); return PerfLocalization.T("vsm_perf_hud_bench", _point.Name + (string.IsNullOrEmpty(_label) ? string.Empty : (" " + _label)), text, _plan.PhaseTime.ToString("0", CultureInfo.InvariantCulture)); } } public static string PointsFile => Path.Combine(PerfPlugin.DataDir, "bench_puntos.txt"); public BenchRunner(Counters counters, Toggles toggles, HorizonBridge horizon) { _counters = counters; _toggles = toggles; _horizon = horizon; } public static List<BenchPoint> LoadPoints() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) List<BenchPoint> list = new List<BenchPoint>(); if (!File.Exists(PointsFile)) { return list; } string[] array = File.ReadAllLines(PointsFile, Encoding.UTF8); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ';' }); if (array2.Length >= 5 && !text.StartsWith("#", StringComparison.Ordinal)) { try { list.Add(new BenchPoint { Name = array2[0], Position = new Vector3(float.Parse(array2[1], CultureInfo.InvariantCulture), float.Parse(array2[2], CultureInfo.InvariantCulture), float.Parse(array2[3], CultureInfo.InvariantCulture)), Yaw = float.Parse(array2[4], CultureInfo.InvariantCulture) }); } catch (FormatException) { } } } return list; } public static bool TryGetPoint(string name, out BenchPoint point) { foreach (BenchPoint item in LoadPoints()) { if (string.Equals(item.Name, name, StringComparison.OrdinalIgnoreCase)) { point = item; return true; } } point = default(BenchPoint); return false; } public static string MarkPoint(string name) { //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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; Camera mainCamera = RenderOverrides.MainCamera; if ((Object)(object)localPlayer == (Object)null || (Object)(object)mainCamera == (Object)null) { return "hay que estar en el mundo para marcar un punto."; } if (string.IsNullOrEmpty(name) || name.IndexOf(';') >= 0) { return "nombre de punto inválido."; } List<BenchPoint> list = LoadPoints(); list.RemoveAll((BenchPoint p) => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)); Vector3 position = ((Component)localPlayer).transform.position; list.Add(new BenchPoint { Name = name, Position = position, Yaw = ((Component)mainCamera).transform.eulerAngles.y }); Directory.CreateDirectory(PerfPlugin.DataDir); List<string> list2 = new List<string> { "# nombre;x;y;z;giro (vsm_perf bench marcar <nombre>)" }; foreach (BenchPoint item in list) { string[] obj = new string[5] { item.Name, null, null, null, null }; float x = item.Position.x; obj[1] = x.ToString("0.###", CultureInfo.InvariantCulture); x = item.Position.y; obj[2] = x.ToString("0.###", CultureInfo.InvariantCulture); x = item.Position.z; obj[3] = x.ToString("0.###", CultureInfo.InvariantCulture); x = item.Yaw; obj[4] = x.ToString("0.#", CultureInfo.InvariantCulture); list2.Add(string.Join(";", obj)); } File.WriteAllLines(PointsFile, list2.ToArray(), Encoding.UTF8); return "punto «" + name + "» guardado en " + ((Vector3)(ref position)).ToString("F1") + "."; } public string Start(BenchPoint point, float seconds, string label, Action<BenchResult> onDone, Action<string> onCancel) { //IL_0029: 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) if (Running) { return "ya hay un benchmark corriendo (vsm_perf bench parar)."; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return "hay que estar en el mundo."; } float num = Vector3.Distance(((Component)localPlayer).transform.position, point.Position); if (num > 2.5f) { return "acércate al punto «" + point.Name + "» (estás a " + num.ToString("0.0", CultureInfo.InvariantCulture) + " m; máximo " + 2.5f + " m)."; } _point = point; _label = label ?? string.Empty; _onDone = onDone; _onCancel = onCancel; _plan = new BenchPlan(seconds); _frames.Clear(); _counterSum = new double[BenchReport.CounterColumns.Length]; _counterN = new int[BenchReport.CounterColumns.Length]; _toggles.BeginSession(); _horizon.SetTemp("Adaptive", value: false); string text = Path.Combine(PerfPlugin.DataDir, "bench"); Directory.CreateDirectory(text); string path = Safe(point.Name) + (string.IsNullOrEmpty(_label) ? string.Empty : ("_" + Safe(_label))) + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture) + ".csv"; _csv = new StreamWriter(Path.Combine(text, path), append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); _csv.WriteLine(BenchReport.FrameHeader); SetPose(0f); SweepActive = true; return "benchmark «" + point.Name + "» " + _label + ": quieto y sin tocar nada; espera + 5 s de calentamiento + " + _plan.MeasureSeconds.ToString("0", CultureInfo.InvariantCulture) + " s."; } public void Tick(float dt) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_plan == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Cancel("saliste del mundo"); return; } if (Vector3.Distance(((Component)localPlayer).transform.position, _point.Position) > 3.5f) { Cancel("te moviste del punto"); return; } BenchPhase phase = _plan.Phase; BenchPhase benchPhase = _plan.Step(dt, SpawnControl.PendingNear); if (phase == BenchPhase.Measure) { float num = dt * 1000f; _frames.Add(num); double[] array = _counters.Snapshot(); for (int i = 0; i < array.Length && i < _counterSum.Length; i++) { if (!double.IsNaN(array[i])) { _counterSum[i] += array[i]; _counterN[i]++; } } _csv.WriteLine(BenchReport.FrameRow(_frames.Count, (_plan.Phase == BenchPhase.Measure) ? _plan.PhaseTime : _plan.MeasureSeconds, num, array)); } switch (benchPhase) { case BenchPhase.Measure: SetPose(_plan.PhaseTime); break; case BenchPhase.Done: Finish(); break; } } public void Cancel(string reason) { if (_plan != null) { Close(); Action<string> onCancel = _onCancel; _onCancel = null; _onDone = null; onCancel?.Invoke(reason); } } private void Finish() { BenchResult benchResult = new BenchResult { Utc = DateTime.UtcNow, Point = _point.Name, Label = _label, Frames = FrameStats.Summarize(_frames), Toggles = Toggles.Codes(), Graphics = PerfController.GraphicsSummary(), Horizon = _horizon.Describe(), System = PerfController.SystemSummary(), SettleTimedOut = _plan.SettleTimedOut }; for (int i = 0; i < benchResult.Counters.Length; i++) { benchResult.Counters[i] = ((_counterN[i] > 0) ? (_counterSum[i] / (double)_counterN[i]) : double.NaN); } try { string path = Path.Combine(PerfPlugin.DataDir, "bench_resumen.csv"); bool flag = !File.Exists(path); using StreamWriter streamWriter = new StreamWriter(path, append: true, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); if (flag) { streamWriter.WriteLine(BenchReport.SummaryHeader); } streamWriter.WriteLine(BenchReport.SummaryRow(benchResult)); } catch (Exception ex) { PerfPlugin.Log.LogWarning((object)("vsm.perf: no se pudo escribir bench_resumen.csv: " + ex.Message)); } Close(); Action<BenchResult> onDone = _onDone; _onDone = null; _onCancel = null; onDone?.Invoke(benchResult); } private void Close() { SweepActive = false; _plan = null; try { if (_csv != null) { _csv.Dispose(); } } catch (Exception) { } _csv = null; _toggles.EndSession(); } private void SetPose(float t) { BenchPlan.Sweep(t, _plan.MeasureSeconds, out var yaw, out var pitch); SweepYaw = _point.Yaw + yaw; SweepPitch = pitch; } private static string Safe(string s) { StringBuilder stringBuilder = new StringBuilder(); foreach (char c in s) { stringBuilder.Append((char.IsLetterOrDigit(c) || c == '-' || c == '_') ? c : '_'); } return stringBuilder.ToString(); } } internal sealed class Counters : IDisposable { private struct Rec { public ProfilerCategory Category; public string Name; public ProfilerRecorder Recorder; } private readonly Rec[] _recs = new Rec[6] { new Rec { Category = ProfilerCategory.Render, Name = "Draw Calls Count" }, new Rec { Category = ProfilerCategory.Render, Name = "Batches Count" }, new Rec { Category = ProfilerCategory.Render, Name = "SetPass Calls Count" }, new Rec { Category = ProfilerCategory.Render, Name = "Triangles Count" }, new Rec { Category = ProfilerCategory.Render, Name = "Shadow Casters Count" }, new Rec { Category = ProfilerCategory.Memory, Name = "GC Allocated In Frame" } }; private readonly double[] _values; private readonly FrameTiming[] _timings = (FrameTiming[])(object)new FrameTiming[1]; private bool _timingEnabled; private bool _active; public double CpuMainMs { get; private set; } public double CpuRenderMs { get; private set; } public double GpuMs { get; private set; } public double this[int index] => _values[index]; public int Length => _values.Length; public Counters() { //IL_0013: 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_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_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_008b: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) _values = new double[_recs.Length]; Clear(); } public void SetActive(bool active) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (active == _active) { return; } _active = active; if (!active) { Dispose(); Clear(); return; } for (int i = 0; i < _recs.Length; i++) { try { _recs[i].Recorder = ProfilerRecorder.StartNew(_recs[i].Category, _recs[i].Name, 1, (ProfilerRecorderOptions)24); } catch (Exception) { } } try { _timingEnabled = FrameTimingManager.IsFeatureEnabled(); } catch (Exception) { _timingEnabled = false; } } private void Clear() { for (int i = 0; i < _values.Length; i++) { _values[i] = double.NaN; } double num = (GpuMs = double.NaN); double cpuMainMs = (CpuRenderMs = num); CpuMainMs = cpuMainMs; _timingEnabled = false; } public void Sample() { //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) if (!_active) { return; } for (int i = 0; i < _recs.Length; i++) { ProfilerRecorder recorder = _recs[i].Recorder; double num = (((ProfilerRecorder)(ref recorder)).Valid ? ((double)((ProfilerRecorder)(ref recorder)).LastValue) : double.NaN); _values[i] = ((i == 5 && !double.IsNaN(num)) ? (num / 1024.0) : num); } if (_timingEnabled) { FrameTimingManager.CaptureFrameTimings(); if (FrameTimingManager.GetLatestTimings(1u, _timings) != 0) { CpuMainMs = _timings[0].cpuMainThreadFrameTime; CpuRenderMs = _timings[0].cpuRenderThreadFrameTime; GpuMs = _timings[0].gpuFrameTime; } } } public double[] Snapshot() { return (double[])_values.Clone(); } public List<string> Describe() { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); for (int i = 0; i < _recs.Length; i++) { list.Add((((ProfilerRecorder)(ref _recs[i].Recorder)).Valid ? " OK " : " n/d ") + ((ProfilerCategory)(ref _recs[i].Category)).Name + " / " + _recs[i].Name); } list.Add(" FrameTimingManager: " + (_timingEnabled ? "habilitado" : "no habilitado en este build")); try { List<ProfilerRecorderHandle> list2 = new List<ProfilerRecorderHandle>(); ProfilerRecorderHandle.GetAvailable(list2); list.Add(" Disponibles en total: " + list2.Count); List<string> list3 = new List<string>(); foreach (ProfilerRecorderHandle item in list2) { ProfilerRecorderDescription description = ProfilerRecorderHandle.GetDescription(item); ProfilerCategory category = ((ProfilerRecorderDescription)(ref description)).Category; list3.Add(((ProfilerCategory)(ref category)).Name + " / " + ((ProfilerRecorderDescription)(ref description)).Name); } list3.Sort(StringComparer.Ordinal); foreach (string item2 in list3) { list.Add(" " + item2); } } catch (Exception ex) { list.Add(" (no se pudo listar: " + ex.Message + ")"); } return list; } public void Dispose() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _recs.Length; i++) { try { ((ProfilerRecorder)(ref _recs[i].Recorder)).Dispose(); } catch (Exception) { } _recs[i].Recorder = default(ProfilerRecorder); } } } internal static class Dump { public static string Write(HorizonBridge horizon) { string text = Path.Combine(PerfPlugin.DataDir, "dump_" + DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture)); Directory.CreateDirectory(text); int num = WritePieceRender(Path.Combine(text, "piece_render.csv")); WriteBase(Path.Combine(text, "perf_base.txt"), horizon); return text + " (" + num + " prefabs de piezas)"; } private static int WritePieceRender(string path) { //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { File.WriteAllText(path, "sin ZNetScene (entra a un mundo)\n"); return 0; } int num = 0; using StreamWriter streamWriter = new StreamWriter(path, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); streamWriter.WriteLine("prefab,lodgroups,renderer,parte,lod,lod_altura,activo,capa,sombra,recibe,materiales,shaders,cola,instancing,legible,vertices,submallas"); foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<Piece>() == (Object)null) { continue; } num++; WearNTear component = prefab.GetComponent<WearNTear>(); LODGroup[] componentsInChildren = prefab.GetComponentsInChildren<LODGroup>(true); Dictionary<Renderer, KeyValuePair<int, float>> dictionary = new Dictionary<Renderer, KeyValuePair<int, float>>(); LODGroup[] array = componentsInChildren; Renderer[] renderers; for (int i = 0; i < array.Length; i++) { LOD[] lODs = array[i].GetLODs(); for (int j = 0; j < lODs.Length; j++) { renderers = lODs[j].renderers; foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null && !dictionary.ContainsKey(val)) { dictionary[val] = new KeyValuePair<int, float>(j, lODs[j].screenRelativeTransitionHeight); } } } } renderers = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in renderers) { if (ParticleSystemRendererLike(val2)) { continue; } Material[] sharedMaterials = val2.sharedMaterials; Mesh val3 = null; MeshFilter component2 = ((Component)val2).GetComponent<MeshFilter>(); if ((Object)(object)component2 != (Object)null) { val3 = component2.sharedMesh; } else { SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if (val4 != null) { val3 = val4.sharedMesh; } } KeyValuePair<int, float> value; bool flag = dictionary.TryGetValue(val2, out value); streamWriter.WriteLine(string.Join(",", BenchReport.Field(((Object)prefab).name), componentsInChildren.Length.ToString(CultureInfo.InvariantCulture), BenchReport.Field(PathOf(((Component)val2).transform, prefab.transform)), Part(component, ((Component)val2).transform), flag ? value.Key.ToString(CultureInfo.InvariantCulture) : "-1", flag ? BenchReport.Number(value.Value) : string.Empty, (((Component)val2).gameObject.activeSelf && val2.enabled) ? "si" : "no", BenchReport.Field(LayerMask.LayerToName(((Component)val2).gameObject.layer)), ((object)val2.shadowCastingMode/*cast due to .constrained prefix*/).ToString(), val2.receiveShadows ? "si" : "no", BenchReport.Field(string.Join("|", sharedMaterials.Select((Material m) => (!((Object)(object)m != (Object)null)) ? "null" : ((Object)m).name).ToArray())), BenchReport.Field(string.Join("|", sharedMaterials.Select((Material m) => (!((Object)(object)m != (Object)null) || !((Object)(object)m.shader != (Object)null)) ? "null" : ((Object)m.shader).name).ToArray())), (sharedMaterials.Length != 0 && (Object)(object)sharedMaterials[0] != (Object)null) ? sharedMaterials[0].renderQueue.ToString(CultureInfo.InvariantCulture) : string.Empty, (sharedMaterials.Length != 0 && sharedMaterials.All((Material m) => (Object)(object)m != (Object)null && m.enableInstancing)) ? "si" : "no", (!((Object)(object)val3 != (Object)null)) ? string.Empty : (val3.isReadable ? "si" : "no"), ((Object)(object)val3 != (Object)null) ? val3.vertexCount.ToString(CultureInfo.InvariantCulture) : string.Empty, ((Object)(object)val3 != (Object)null) ? val3.subMeshCount.ToString(CultureInfo.InvariantCulture) : string.Empty)); } } return num; } private static bool ParticleSystemRendererLike(Renderer r) { return ((object)r).GetType().Name == "ParticleSystemRenderer"; } private static string Part(WearNTear wnt, Transform t) { if ((Object)(object)wnt == (Object)null) { return "sin_desgaste"; } if (Under(t, wnt.m_new)) { return "nuevo"; } if (Under(t, wnt.m_worn)) { return "gastado"; } if (Under(t, wnt.m_broken)) { return "roto"; } if (Under(t, wnt.m_wet)) { return "mojado"; } if (((Object)(object)wnt.m_snow != (Object)null && (Object)(object)t == (Object)(object)((Component)wnt.m_snow).transform) || ((Object)(object)wnt.m_snowWorn != (Object)null && (Object)(object)t == (Object)(object)((Component)wnt.m_snowWorn).transform) || ((Object)(object)wnt.m_snowBroken != (Object)null && (Object)(object)t == (Object)(object)((Component)wnt.m_snowBroken).transform)) { return "nieve"; } if (wnt.m_fragmentRoots != null) { GameObject[] fragmentRoots = wnt.m_fragmentRoots; foreach (GameObject root in fragmentRoots) { if (Under(t, root)) { return "escombros"; } } } return "otro"; } private static bool Under(Transform t, GameObject root) { if ((Object)(object)root != (Object)null) { if (!((Object)(object)t == (Object)(object)root.transform)) { return t.IsChildOf(root.transform); } return true; } return false; } private static string PathOf(Transform t, Transform root) { List<string> list = new List<string>(); while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root) { list.Add(((Object)t).name); t = t.parent; } list.Reverse(); if (list.Count != 0) { return string.Join("/", list.ToArray()); } return "(raíz)"; } private static void WriteBase(string path, HorizonBridge horizon) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("MEL Performance 0.1.0 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)); stringBuilder.AppendLine("Valheim " + Env.GameVersion + " · Unity " + Application.unityVersion); stringBuilder.AppendLine(); stringBuilder.AppendLine("== Equipo"); stringBuilder.AppendLine(PerfController.SystemSummary()); stringBuilder.AppendLine("Hilos de render: " + PerfController.ThreadingMode()); stringBuilder.AppendLine(); stringBuilder.AppendLine("== Calidad"); stringBuilder.AppendLine(PerfController.GraphicsSummary()); stringBuilder.AppendLine("shadowCascades " + QualitySettings.shadowCascades + " · shadowResolution " + ((object)QualitySettings.shadowResolution/*cast due to .constrained prefix*/).ToString() + " · shadowProjection " + ((object)QualitySettings.shadowProjection/*cast due to .constrained prefix*/).ToString() + " · maximumLODLevel " + QualitySettings.maximumLODLevel + " · softParticles " + QualitySettings.softParticles + " · maxQueuedFrames " + QualitySettings.maxQueuedFrames + " · vSyncCount " + QualitySettings.vSyncCount + " · targetFrameRate " + Application.targetFrameRate); stringBuilder.AppendLine("Mejoras: " + Toggles.Codes()); stringBuilder.AppendLine("Horizon: " + horizon.Describe()); stringBuilder.AppendLine(); Camera mainCamera = RenderOverrides.MainCamera; stringBuilder.AppendLine("== Cámara principal"); if ((Object)(object)mainCamera != (Object)null) { stringBuilder.AppendLine("depthTextureMode " + ((object)mainCamera.depthTextureMode/*cast due to .constrained prefix*/).ToString() + " · renderingPath " + ((object)mainCamera.renderingPath/*cast due to .constrained prefix*/).ToString() + " · actualRenderingPath " + ((object)mainCamera.actualRenderingPath/*cast due to .constrained prefix*/).ToString() + " · HDR " + mainCamera.allowHDR + " · MSAA " + mainCamera.allowMSAA + " · far " + mainCamera.farClipPlane.ToString("0", CultureInfo.InvariantCulture) + " · fov " + mainCamera.fieldOfView.ToString("0", CultureInfo.InvariantCulture) + " · destino " + (((Object)(object)mainCamera.targetTexture != (Object)null) ? (((Texture)mainCamera.targetTexture).width + "x" + ((Texture)mainCamera.targetTexture).height) : "pantalla")); MonoBehaviour[] components = ((Component)mainCamera).GetComponents<MonoBehaviour>(); foreach (MonoBehaviour val in components) { if (!((Object)(object)val == (Object)null)) { stringBuilder.AppendLine(" componente " + ((object)val).GetType().FullName + (((Behaviour)val).enabled ? "" : " (apagado)") + ProfileModels(val)); } } } stringBuilder.AppendLine(); stringBuilder.AppendLine("== Sondas de reflejos"); ReflectionProbe[] array = Object.FindObjectsByType<ReflectionProbe>((FindObjectsSortMode)0); foreach (ReflectionProbe val2 in array) { stringBuilder.AppendLine(" " + ((Object)val2).name + " · modo " + ((object)val2.mode/*cast due to .constrained prefix*/).ToString() + " · refresco " + ((object)val2.refreshMode/*cast due to .constrained prefix*/).ToString() + " · reparto " + ((object)val2.timeSlicingMode/*cast due to .constrained prefix*/).ToString() + " · resolución " + val2.resolution + " · máscara " + val2.cullingMask + " · activa " + ((Behaviour)val2).isActiveAndEnabled); } stringBuilder.AppendLine(); stringBuilder.AppendLine("== Luces (LightLod)"); int num = 0; int num2 = 0; int num3 = 0; foreach (LightLod light in LightLod.m_lights) { if (!((Object)(object)light == (Object)null) && !((Object)(object)light.m_light == (Object)null)) { num++; if (((Behaviour)light.m_light).enabled && light.m_light.range > 0f) { num2++; } if ((int)light.m_light.shadows != 0) { num3++; } } } stringBuilder.AppendLine("total " + num + " · encendidas " + num2 + " · con sombra " + num3 + " · límite luces " + LightLod.m_lightLimit + " · límite sombras " + LightLod.m_shadowLimit); stringBuilder.AppendLine(); Player localPlayer = Player.m_localPlayer; stringBuilder.AppendLine("== Alrededor del jugador (64 m, celdas de 16 m)"); if ((Object)(object)localPlayer != (Object)null) { WriteCells(stringBuilder, ((Component)localPlayer).transform.position, 64f, 16f); } else { stringBuilder.AppendLine("(sin jugador)"); } stringBuilder.AppendLine(); stringBuilder.AppendLine("== Plugins cargados"); foreach (KeyValuePair<string, PluginInfo> item in Chainloader.PluginInfos.OrderBy((KeyValuePair<string, PluginInfo> k) => k.Key)) { stringBuilder.AppendLine(" " + item.Key + " " + item.Value.Metadata.Version); } File.WriteAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } private static void WriteCells(StringBuilder sb, Vector3 center, float radius, float cell) { //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_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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) Dictionary<Vector3Int, int[]> dictionary = new Dictionary<Vector3Int, int[]>(); HashSet<Material> hashSet = new HashSet<Material>(); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; Vector3Int key = default(Vector3Int); foreach (WearNTear allInstance in WearNTear.GetAllInstances()) { if ((Object)(object)allInstance == (Object)null || Vector3.Distance(((Component)allInstance).transform.position, center) > radius) { continue; } num++; Vector3 position = ((Component)allInstance).transform.position; ((Vector3Int)(ref key))..ctor(Mathf.FloorToInt(position.x / cell), Mathf.FloorToInt(position.y / cell), Mathf.FloorToInt(position.z / cell)); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new int[2]); } value[0]++; num5 += ((Component)allInstance).GetComponentsInChildren<LODGroup>(false).Length; Renderer[] componentsInChildren = ((Component)allInstance).GetComponentsInChildren<Renderer>(false); foreach (Renderer val in componentsInChildren) { if (!val.enabled) { continue; } num2++; value[1]++; if (val.HasPropertyBlock()) { num3++; } Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null)) { hashSet.Add(val2); if (((Object)val2).name.IndexOf("(Instance)", StringComparison.Ordinal) >= 0) { num4++; } } } } } sb.AppendLine("piezas " + num + " · renderers activos " + num2 + " · LODGroups " + num5 + " · materiales distintos " + hashSet.Count + " · renderers con property block " + num3 + " · materiales propios \"(Instance)\" " + num4); sb.AppendLine("celdas con piezas: " + dictionary.Count + " (las 15 más cargadas: celda → piezas / renderers)"); foreach (KeyValuePair<Vector3Int, int[]> item in dictionary.OrderByDescending((KeyValuePair<Vector3Int, int[]> k) => k.Value[1]).Take(15)) { sb.AppendLine(" " + ((object)item.Key/*cast due to .constrained prefix*/).ToString() + " → " + item.Value[0] + " / " + item.Value[1]); } } private static string ProfileModels(MonoBehaviour mb) { try { FieldInfo field = ((object)mb).GetType().GetField("profile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object obj = ((field != null) ? field.GetValue(mb) : null); if (obj == null) { return string.Empty; } List<string> list = new List<string>(); FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { object value = fieldInfo.GetValue(obj); if (value != null) { PropertyInfo property = value.GetType().GetProperty("enabled", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.PropertyType == typeof(bool) && (bool)property.GetValue(value, null)) { list.Add(fieldInfo.Name); } } } return " · perfil: " + ((list.Count == 0) ? "nada encendido" : string.Join(", ", list.ToArray())); } catch (Exception) { return string.Empty; } } } internal sealed class HorizonBridge { public const string Guid = "vsm.horizon"; public const string ControllerType = "VSM.Horizon.Runtime.HorizonController"; private bool _resolved; private bool _failed; private ConfigFile _config; private ConfigEntryBase _enabled; private ConfigEntryBase _quality; private ConfigEntryBase _adaptive; private ConfigEntryBase _targetFps; private ConfigEntryBase _minLoaded; private PropertyInfo _instanceProp; private PropertyInfo _scaleProp; private FieldInfo _rendererField; private PropertyInfo _drawnProp; private PropertyInfo _drawCallsProp; private Type _controllerType; private readonly Dictionary<ConfigEntryBase, object> _saved = new Dictionary<ConfigEntryBase, object>(); private bool _savedSaveOnSet; private static bool Wanted { get { if (PerfPlugin.HorizonIntegration != null) { return PerfPlugin.HorizonIntegration.Value; } return true; } } public bool Present { get { Resolve(); if (Wanted && !_failed) { return _config != null; } return false; } } public bool Enabled { get { bool flag = default(bool); int num; if (Present && _enabled != null) { object boxedValue = _enabled.BoxedValue; if (boxedValue is bool) { flag = (bool)boxedValue; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } } public double MinLoadedSeconds { get { if (!Enabled || _minLoaded == null) { return 0.0; } try { return Convert.ToDouble(_minLoaded.BoxedValue, CultureInfo.InvariantCulture); } catch (Exception) { return 0.0; } } } public Type HorizonControllerType { get { Resolve(); if (!Present) { return null; } return _controllerType; } } public string Describe() { if (!Present) { return "no"; } if (!Enabled) { return "apagado"; } string text = "encendido · " + Value(_quality); bool flag = default(bool); int num; if (_adaptive != null) { object boxedValue = _adaptive.BoxedValue; if (boxedValue is bool) { flag = (bool)boxedValue; num = 1; } else { num = 0; } } else { num = 0; } bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0; text += (flag2 ? (" · adaptativo " + Value(_targetFps) + " FPS") : " · fijo"); try { object obj = ((_instanceProp != null) ? _instanceProp.GetValue(null, null) : null); if (obj != null) { if (_scaleProp != null) { text = text + " · escala " + ((float)_scaleProp.GetValue(obj, null)).ToString("0.00", CultureInfo.InvariantCulture); } object obj2 = ((_rendererField != null) ? _rendererField.GetValue(obj) : null); if (obj2 != null && _drawnProp != null && _drawCallsProp != null) { text = text + " · " + _drawnProp.GetValue(obj2, null)?.ToString() + " inst · " + _drawCallsProp.GetValue(obj2, null)?.ToString() + " draws"; } } } catch (Exception ex) { Fail("leer su estado", ex); } return text; } public bool SetTemp(string key, bool value) { if (!Present) { return false; } ConfigEntryBase val = ((key == "Enabled") ? _enabled : ((key == "Adaptive") ? _adaptive : null)); if (val == null) { return false; } if (_saved.Count == 0) { _savedSaveOnSet = _config.SaveOnConfigSet; } if (!_saved.ContainsKey(val)) { _saved[val] = val.BoxedValue; } _config.SaveOnConfigSet = false; try { val.BoxedValue = value; } catch (Exception ex) { Fail("cambiar " + key, ex); return false; } return true; } public void RestoreTemp() { if (_saved.Count == 0 || _config == null) { return; } try { foreach (KeyValuePair<ConfigEntryBase, object> item in _saved) { item.Key.BoxedValue = item.Value; } } catch (Exception ex) { Fail("restaurar su configuración", ex); } finally { _saved.Clear(); _config.SaveOnConfigSet = _savedSaveOnSet; } } private void Resolve() { if (_resolved) { return; } if (!Chainloader.PluginInfos.TryGetValue("vsm.horizon", out var value) || value == null || (Object)(object)value.Instance == (Object)null) { if ((Object)(object)ZNet.instance != (Object)null) { _resolved = true; } return; } _resolved = true; try { _config = value.Instance.Config; foreach (ConfigDefinition key in _config.Keys) { switch (key.Key) { case "Enabled": _enabled = _config[key]; break; case "Quality": _quality = _config[key]; break; case "Adaptive": _adaptive = _config[key]; break; case "TargetFps": _targetFps = _config[key]; break; case "MinLoadedSeconds": _minLoaded = _config[key]; break; } } _controllerType = ((object)value.Instance).GetType().Assembly.GetType("VSM.Horizon.Runtime.HorizonController", throwOnError: false); if (_controllerType != null) { _instanceProp = AccessTools.Property(_controllerType, "Instance"); _scaleProp = AccessTools.Property(_controllerType, "Scale"); _rendererField = AccessTools.Field(_controllerType, "_renderer"); if (_rendererField != null) { _drawnProp = AccessTools.Property(_rendererField.FieldType, "DrawnInstances"); _drawCallsProp = AccessTools.Property(_rendererField.FieldType, "DrawCalls"); } } PerfPlugin.Log.LogInfo((object)("vsm.perf: MEL Horizons " + value.Metadata.Version?.ToString() + " detectado; integración " + (Wanted ? "encendida" : "apagada por config") + ".")); } catch (Exception ex) { Fail("detectarlo", ex); } } private void Fail(string what, Exception ex) { if (!_failed) { _failed = true; PerfPlugin.Log.LogWarning((object)("vsm.perf: integración con MEL Horizons apagada (no se pudo " + what + "): " + ex.Message)); } } private static string Value(ConfigEntryBase e) { if (e != null && e.BoxedValue != null) { return Convert.ToString(e.BoxedValue, CultureInfo.InvariantCulture); } return "?"; } } internal static class PerfCommands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__1_0; public static Action<BenchResult> <>9__4_0; public static Action<string> <>9__4_1; internal void <Register>b__1_0(ConsoleEventArgs args) { PerfController instance = PerfController.Instance; if ((Object)(object)instance == (Object)null) { args.Context.AddString("vsm.perf: no está activo en este proceso."); return; } string sub = ((args.Length > 1) ? args.Args[1].ToLowerInvariant() : string.Empty); try { Run(instance, sub, args); } catch (Exception ex) { args.Context.AddString("vsm.perf: error: " + ex.Message); PerfPlugin.Log.LogWarning((object)("vsm.perf: error en el comando: " + ex)); } } internal void <BenchCmd>b__4_0(BenchResult r) { PerfController.Notify(PerfLocalization.T("vsm_perf_bench_done", r.Point, r.Frames.AvgFps.ToString("0.0", CultureInfo.InvariantCulture), r.Frames.Low1Fps.ToString("0.0", CultureInfo.InvariantCulture)) + (r.SettleTimedOut ? " (ojo: quedaban objetos por crear)" : string.Empty)); } internal void <BenchCmd>b__4_1(string reason) { PerfController.Notify(PerfLocalization.T("vsm_perf_bench_cancel", reason)); } } private static readonly string[] Help = new string[12] { "vsm_perf estado (mejoras, horizon, picos, contadores)", "vsm_perf on|off enciende o apaga el mod (= Ajustes → Accesibilidad)", "vsm_perf hud muestra/oculta el medidor (también Ctrl+F9)", "vsm_perf contadores qué contadores del motor hay en este build (y los guarda en un .txt)", "vsm_perf prof on|off|reporte|reset instrumentador: ms por sistema del juego", "vsm_perf bench marcar <punto> guarda tu posición y hacia dónde miras", "vsm_perf bench puntos lista los puntos guardados", "vsm_perf bench <punto> [s] benchmark reproducible desde ese punto (quieto, sin tocar nada)", "vsm_perf bench parar corta el benchmark o A/B en curso", "vsm_perf ab <mejora> <punto> [s] [rondas] A/B con secuencia ABBA (sin guardar la config)", "vsm_perf diff <mejora> captura A y B en el mismo frame y cuenta píxeles distintos", "vsm_perf dump volcado de cómo se dibujan las piezas y de la base alrededor" }; public static void Register() { //IL_0033: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__1_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { PerfController instance = PerfController.Instance; if ((Object)(object)instance == (Object)null) { args.Context.AddString("vsm.perf: no está activo en este proceso."); return; } string sub = ((args.Length > 1) ? args.Args[1].ToLowerInvariant() : string.Empty); try { Run(instance, sub, args); } catch (Exception ex) { args.Context.AddString("vsm.perf: error: " + ex.Message); PerfPlugin.Log.LogWarning((object)("vsm.perf: error en el comando: " + ex)); } }; <>c.<>9__1_0 = val; obj = (object)val; } new ConsoleCommand("vsm_perf", "MEL Performance: vsm_perf ayuda", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void Run(PerfController ctl, string sub, ConsoleEventArgs args) { Terminal context = args.Context; if (!(sub == "on")) { if (sub == "off") { PerfPlugin.Enabled.Value = false; context.AddString("vsm.perf: apagado: el juego queda como sin el mod."); return; } if (!PerfPlugin.On && sub != string.Empty && sub != "estado" && sub != "status" && sub != "ayuda" && sub != "help") { context.AddString("vsm.perf: MEL Performance está apagado. Enciéndelo en Ajustes → Accesibilidad → \"MEL Performance (más FPS)\" o con vsm_perf on."); return; } switch (sub) { case "estado": case "status": case "": { foreach (string item in Status(ctl)) { context.AddString(item); PerfPlugin.Log.LogInfo((object)item); } break; } case "ayuda": case "help": { string[] help = Help; foreach (string text in help) { context.AddString(text); } context.AddString("mejoras para ab/diff:"); { foreach (string item2 in ctl.Toggles.Help()) { context.AddString(item2); } break; } } case "hud": ctl.ToggleOverlay(); break; case "contadores": case "counters": { List<string> list = ctl.Counters.Describe(); Directory.CreateDirectory(PerfPlugin.DataDir); string text2 = Path.Combine(PerfPlugin.DataDir, "contadores.txt"); File.WriteAllLines(text2, list.ToArray()); foreach (string item3 in list.Take(8)) { context.AddString(item3); } context.AddString("lista completa en " + text2); break; } case "prof": Prof(ctl, context, (args.Length > 2) ? args.Args[2].ToLowerInvariant() : "reporte"); break; case "bench": BenchCmd(ctl, context, args); break; case "ab": { if (args.Length < 4) { context.AddString("uso: vsm_perf ab <mejora> <punto> [segundos] [rondas]. Mejoras:"); { foreach (string item4 in ctl.Toggles.Help()) { context.AddString(item4); } break; } } if (!BenchRunner.TryGetPoint(args.Args[3], out var point)) { context.AddString("no hay un punto «" + args.Args[3] + "» (vsm_perf bench marcar " + args.Args[3] + ")."); } else { float seconds = ((args.Length > 4) ? ParseFloat(args.Args[4], 20f) : 20f); int val = ((args.Length <= 5) ? 1 : ((int)ParseFloat(args.Args[5], 1f))); context.AddString(ctl.StartAb(args.Args[2], point, seconds, Math.Max(1, Math.Min(5, val)))); } break; } case "diff": context.AddString(ctl.StartDiff((args.Length > 2) ? args.Args[2] : string.Empty)); break; case "dump": context.AddString("vsm.perf: volcado en " + Dump.Write(ctl.Horizon)); break; default: context.AddString("vsm.perf: subcomando desconocido. vsm_perf ayuda"); break; } } else { PerfPlugin.Enabled.Value = true; context.AddString("vsm.perf: encendido (queda guardado; también en Ajustes → Accesibilidad)."); } } private static void Prof(PerfController ctl, Terminal t, string op) { switch (op) { case "on": { string text = PerfPlugin.ProfilerExtraTargets.Value ?? string.Empty; t.AddString("vsm.perf: " + ctl.Profiler.Start(text.Split(new char[1] { ',' }), ctl.Horizon.HorizonControllerType)); t.AddString(" (tiempos inclusivos: un sistema incluye lo que llama; mira el medidor con Ctrl+F9)"); return; } case "off": ctl.Profiler.Stop(); t.AddString("vsm.perf: instrumentador apagado."); return; case "reset": ctl.Profiler.Reset(); t.AddString("vsm.perf: instrumentador a cero."); return; } if (!ctl.Profiler.Active && ctl.Profiler.WindowFrames == 0) { t.AddString("vsm.perf: el instrumentador está apagado (vsm_perf prof on)."); return; } foreach (SystemProfiler.Row item in ctl.Profiler.Top(15)) { string[] obj = new string[6] { " ", null, null, null, null, null }; double avgMs = item.AvgMs; obj[1] = avgMs.ToString("0.000", CultureInfo.InvariantCulture); obj[2] = " ms/frame (máx "; avgMs = item.MaxMs; obj[3] = avgMs.ToString("0.0", CultureInfo.InvariantCulture); obj[4] = ") "; obj[5] = item.Key; t.AddString(string.Concat(obj)); } t.AddString("reporte completo: " + ctl.Profiler.WriteReport(PerfPlugin.DataDir)); } private static void BenchCmd(PerfController ctl, Terminal t, ConsoleEventArgs args) { //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) string text = ((args.Length > 2) ? args.Args[2] : string.Empty); switch (text.ToLowerInvariant()) { case "": t.AddString("uso: vsm_perf bench marcar <punto> | puntos | parar | <punto> [segundos]"); return; case "marcar": case "mark": t.AddString("vsm.perf: " + BenchRunner.MarkPoint((args.Length > 3) ? args.Args[3] : string.Empty)); return; case "points": case "puntos": { foreach (BenchPoint item in BenchRunner.LoadPoints()) { string[] obj = new string[6] { " ", item.Name, " ", null, null, null }; Vector3 position = item.Position; obj[3] = ((Vector3)(ref position)).ToString("F1"); obj[4] = " giro "; float yaw = item.Yaw; obj[5] = yaw.ToString("0", CultureInfo.InvariantCulture); t.AddString(string.Concat(obj)); } return; } case "stop": case "parar": ctl.Bench.Cancel("pedido con vsm_perf bench parar"); return; } if (!BenchRunner.TryGetPoint(text, out var point)) { t.AddString("no hay un punto «" + text + "» (vsm_perf bench marcar " + text + ")."); return; } float seconds = ((args.Length > 3) ? ParseFloat(args.Args[3], PerfPlugin.BenchSeconds.Value) : ((float)PerfPlugin.BenchSeconds.Value)); t.AddString("vsm.perf: " + ctl.Bench.Start(point, seconds, string.Empty, delegate(BenchResult r) { PerfController.Notify(PerfLocalization.T("vsm_perf_bench_done", r.Point, r.Frames.AvgFps.ToString("0.0", CultureInfo.InvariantCulture), r.Frames.Low1Fps.ToString("0.0", CultureInfo.InvariantCulture)) + (r.SettleTimedOut ? " (ojo: quedaban objetos por crear)" : string.Empty)); }, delegate(string reason) { PerfController.Notify(PerfLocalization.T("vsm_perf_bench_cancel", reason)); })); } private static IEnumerable<string> Status(PerfController ctl) { CultureInfo inv = CultureInfo.InvariantCulture; yield return "MEL Performance 0.1.0 · " + (PerfPlugin.On ? "ENCENDIDO" : "APAGADO (vsm_perf on o Ajustes → Accesibilidad)") + " · Valheim " + Env.GameVersion + " · " + PerfController.SystemSummary(); yield return " fila en Accesibilidad: " + SettingsRow.LastResult; yield return " mejoras: " + Toggles.Codes(); yield return " render: " + ctl.Tweaks.Describe() + " · luces " + ctl.Shadows.LightsOn + "/" + ctl.Shadows.LightsTotal + " · con sombra " + ctl.Shadows.GameShadowed + " (quitadas " + ctl.Shadows.Suppressed + ")"; yield return " carga de objetos: por crear " + SpawnControl.PendingNear + " · ticks recortados " + SpawnControl.Budget.ThrottledTicks + " · atraso " + SpawnControl.Budget.Deficit.ToString("0", inv) + " obj · " + SpawnControl.Budget.TickRate.ToString("0", inv) + " ticks/s"; yield return " limpieza de assets: " + (AssetUnload.Policy.Pending ? "aplazada (esperando un momento tranquilo)" : "nada pendiente"); yield return " horizon: " + ctl.Horizon.Describe(); yield return " hilos de render: " + PerfController.ThreadingMode() + " · " + PerfController.GraphicsSummary(); if (SafePatch.IsDegraded) { yield return " MODO DEGRADADO, parches que fallaron: " + string.Join("; ", SafePatch.FailedTargets.ToArray()); } yield return " datos en " + PerfPlugin.DataDir + " · vsm_perf ayuda"; } private static float ParseFloat(string s, float fallback) { if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } } internal sealed class PerfController : MonoBehaviour { private sealed class AbRun { private readonly PerfController _ctl; private readonly string _toggle; private readonly BenchPoint _point; private readonly float _seconds; private readonly bool[] _sequence; private readonly List<double> _fpsA = new List<double>(); private readonly List<double> _fpsB = new List<double>(); private readonly List<double> _lowA = new List<double>(); private readonly List<double> _lowB = new List<double>(); private int _index; public bool Started { get; private set; } public AbRun(PerfController ctl, string toggle, BenchPoint point, float seconds, int rounds) { _ctl = ctl; _toggle = toggle; _point = point; _seconds = seconds; _sequence = AbSchedule.Sequence(rounds); } public string Start() { _ctl.Toggles.BeginSession(); string result = Next(); Started = _ctl.Bench.Running; if (!Started) { _ctl.Toggles.EndSession(); } return result; } private string Next() { if (_index >= _sequence.Length) { Finish(); return string.Empty; } bool flag = _sequence[_index]; if (!_ctl.Toggles.Set(_toggle, flag, out var error)) { Abort(error); return "A/B: " + error; } _ctl.Shadows.Invalidate(); _ctl.Tweaks.Apply(); string label = (flag ? "B" : "A") + (_index + 1).ToString(CultureInfo.InvariantCulture) + "-" + _toggle; string text = _ctl.Bench.Start(_point, _seconds, label, OnDone, OnCancel); if (!_ctl.Bench.Running && _index > 0) { Abort(text); } return "A/B «" + _toggle + "» (" + _sequence.Length + " corridas): " + text; } private void OnDone(BenchResult r) { bool flag = _sequence[_index]; (flag ? _fpsB : _fpsA).Add(r.Frames.AvgFps); (flag ? _lowB : _lowA).Add(r.Frames.Low1Fps); Print("vsm.perf A/B: corrida " + (_index + 1) + "/" + _sequence.Length + " (" + (flag ? "B" : "A") + "): " + r.Frames.AvgFps.ToString("0.0", CultureInfo.InvariantCulture) + " FPS, 1% low " + r.Frames.Low1Fps.ToString("0.0", CultureInfo.InvariantCulture)); _index++; Next(); } private void OnCancel(string reason) { Abort(reason); } private void Abort(string reason) { Notify(PerfLocalization.T("vsm_perf_bench_cancel", reason)); _ctl.Toggles.EndSession(); _ctl.AbFinished(); } private void Finish() { AbResult abResult = AbSchedule.Compare(_fpsA, _fpsB); AbResult abResult2 = AbSchedule.Compare(_lowA, _lowB); CultureInfo invariantCulture = CultureInfo.InvariantCulture; Notify("vsm.perf A/B «" + _toggle + "»: A " + abResult.MeanA.ToString("0.0", invariantCulture) + " → B " + abResult.MeanB.ToString("0.0", invariantCulture) + " FPS (" + ((abResult.DeltaPct >= 0.0) ? "+" : string.Empty) + abResult.DeltaPct.ToString("0.0", invariantCulture) + " % ± " + abResult.NoisePct.ToString("0.0", invariantCulture) + ") · 1% low " + ((abResult2.DeltaPct >= 0.0) ? "+" : string.Empty) + abResult2.DeltaPct.ToString("0.0", invariantCulture) + " %"); _ctl.Toggles.EndSession(); _ctl.AbFinished(); } } public readonly FrameWindow Window = new FrameWindow(10.0); public Counters Counters; public ShadowGovernor Shadows; public SceneTweaks Tweaks; public SystemProfiler Profiler; public HorizonBridge Horizon; public Toggles Toggles; public BenchRunner Bench; private RenderOverrides _overrides; private AbRun _ab; private bool _overlay; private string _overlayText = string.Empty; private Vector2 _overlaySize; private GUIStyle _style; private float _nextOverlay; private float _nextSecond; public static PerfController Instance { get; private set; } private void Awake() { Instance = this; Horizon = new HorizonBridge(); SpawnControl.Horizon = Horizon; Counters = new Counters(); Shadows = new ShadowGovernor(); _overrides = new RenderOverrides(Shadows); Tweaks = new SceneTweaks(); Profiler = new SystemProfiler(); Toggles = new Toggles(Horizon); Bench = new BenchRunner(Counters, Toggles, Horizon); _overlay = PerfPlugin.On && PerfPlugin.OverlayOnStart.Value; Counters.SetActive(PerfPlugin.On); PerfPlugin.PointShadowBudget.SettingChanged += delegate { Shadows.Invalidate(); }; PerfPlugin.Enabled.SettingChanged += OnEnabledChanged; ((MonoBehaviour)this).StartCoroutine(EndOfFrameLoop()); } private void OnEnabledChanged(object sender, EventArgs e) { bool flag = PerfPlugin.On; try { Counters.SetActive(flag); if (!flag) { _overlay = false; Profiler.Stop(); Bench.Cancel("MEL Performance apagado"); Window.Clear(); } Shadows.Invalidate(); Tweaks.Apply(); SettingsRow.SyncFromConfig(); } catch (Exception ex) { PerfPlugin.Log.LogWarning((object)("vsm.perf: al " + (flag ? "encender" : "apagar") + ": " + ex.Message)); } PerfPlugin.Log.LogInfo((object)("vsm.perf: " + (flag ? "encendido." : "apagado."))); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)1, PerfLocalization.T(flag ? "vsm_perf_enabled_msg" : "vsm_perf_disabled_msg"), 0, (Sprite)null, false); } } private void Update() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) float unscaledTime = Time.unscaledTime; _overrides.SafetyRestore(); if (!PerfPlugin.On) { if (unscaledTime >= _nextSecond) { _nextSecond = unscaledTime + 1f; try { Tweaks.Apply(); AssetUnload.Tick(); return; } catch (Exception) { return; } } return; } float unscaledDeltaTime = Time.unscaledDeltaTime; Window.Add(unscaledDeltaTime * 1000f); try { Counters.Sample(); } catch (Exception) { } if (Env.Pressed(PerfPlugin.OverlayKey.Value) && !Typing()) { _overlay = !_overlay; } try { Bench.Tick(unscaledDeltaTime); } catch (Exception ex3) { PerfPlugin.Log.LogWarning((object)("vsm.perf: error en el benchmark: " + ex3)); Bench.Cancel("error: " + ex3.Message); } if (unscaledTime >= _nextSecond) { _nextSecond = unscaledTime + 1f; try { Tweaks.Apply(); AssetUnload.Tick(); } catch (Exception ex4) { PerfPlugin.Log.LogWarning((object)("vsm.perf: " + ex4.Message)); } } if (_overlay && unscaledTime >= _nextOverlay) { _nextOverlay = unscaledTime + 0.5f; _overlayText = BuildOverlay(); _overlaySize = Vector2.zero; } } private IEnumerator EndOfFrameLoop() { WaitForEndOfFrame wait = new WaitForEndOfFrame(); while (true) { yield return wait; Profiler.EndFrame(); } } private void OnGUI() { //IL_0058: 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_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_0042: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_011b: 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_0080: 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) if (_overlay && !string.IsNullOrEmpty(_overlayText)) { if (_style == null) { _style = new GUIStyle(GUI.skin.label) { fontSize = 13, wordWrap = false }; _style.normal.textColor = Color.white; } if (_overlaySize == Vector2.zero) { _overlaySize = _style.CalcSize(new GUIContent(_overlayText)); } Rect val = default(Rect); ((Rect)(ref val))..ctor(10f, 10f, _overlaySize.x + 16f, _overlaySize.y + 12f); Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.6f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = color; GUI.Label(new Rect(((Rect)(ref val)).x + 8f, ((Rect)(ref val)).y + 6f, _overlaySize.x, _overlaySize.y), _overlayText, _style); } } private void OnDestroy() { try { PerfPlugin.Enabled.SettingChanged -= OnEnabledChanged; Bench.Cancel("cerrando el juego"); Profiler.Stop(); _overrides.Dispose(); Tweaks.Dispose(); Counters.Dispose(); } catch (Exception) { } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } public void ToggleOverlay() { _overlay = PerfPlugin.On && !_overlay; _nextOverlay = 0f; } private static bool Typing() { Chat instance = Chat.instance; if (!Console.IsVisible() && !TextInput.IsVisible()) { if ((Object)(object)instance != (Object)null) { return instance.HasFocus(); } return false; } return true; } private string BuildOverlay() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) CultureInfo invariantCulture = CultureInfo.InvariantCulture; string text = PerfLocalization.T("vsm_perf_na"); FrameSummary frameSummary = Window.Summarize(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("MEL Performance 0.1.0 · " + ((object)SystemInfo.graphicsDeviceType/*cast due to .constrained prefix*/).ToString() + " · " + ThreadingMode()); stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_fps", frameSummary.AvgFps.ToString("0", invariantCulture), frameSummary.AvgMs.ToString("0.0", invariantCulture), frameSummary.Low1Fps.ToString("0", invariantCulture), frameSummary.Low01Fps.ToString("0", invariantCulture), frameSummary.WorstMs.ToString("0", invariantCulture))); stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_cpu", Ms(Counters.CpuMainMs, text), Ms(Counters.CpuRenderMs, text), Ms(Counters.GpuMs, text))); stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_draw", Num(Counters[0], text), Num(Counters[1], text), Num(Counters[2], text), Big(Counters[3], text), Num(Counters[4], text), double.IsNaN(Counters[5]) ? text : (Counters[5].ToString("0", invariantCulture) + " KB"))); ZNetScene instance = ZNetScene.instance; stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_scene", WearNTear.GetAllInstances().Count, ((Object)(object)instance != (Object)null) ? instance.m_instances.Count : 0, SpawnControl.PendingNear, Shadows.LightsOn, Shadows.LightsTotal, Shadows.GameShadowed - Shadows.Suppressed, Shadows.Suppressed)); if (Horizon.Present) { stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_horizon", Horizon.Describe())); } stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_toggles", Toggles.Codes())); if (Bench.Running) { stringBuilder.AppendLine(Bench.Status); } if (Profiler.Active) { stringBuilder.AppendLine(PerfLocalization.T("vsm_perf_hud_prof")); foreach (SystemProfiler.Row item in Profiler.Top(8)) { string[] obj = new string[6] { " ", null, null, null, null, null }; double avgMs = item.AvgMs; obj[1] = avgMs.ToString("0.00", invariantCulture); obj[2] = " ("; avgMs = item.MaxMs; obj[3] = avgMs.ToString("0.0", invariantCulture); obj[4] = ") "; obj[5] = item.Key; stringBuilder.AppendLine(string.Concat(obj)); } } return stringBuilder.ToString().TrimEnd(Array.Empty<char>()); } private static string Ms(double v, string na) { if (!double.IsNaN(v) && !(v <= 0.0)) { return v.ToString("0.0", CultureInfo.InvariantCulture) + " ms"; } return na; } private static string Num(double v, string na) { if (!double.IsNaN(v)) { return v.ToString("0", CultureInfo.InvariantCulture); } return na; } private static string Big(double v, string na) { if (double.IsNaN(v)) { return na; } if (!(v >= 1000000.0)) { return (v / 1000.0).ToString("0", CultureInfo.InvariantCulture) + "k"; } return (v / 1000000.0).ToString("0.0", CultureInfo.InvariantCulture) + "M"; } public static string ThreadingMode() { try { object obj = ((typeof(SystemInfo).GetProperty("renderingThreadingMode") != null) ? typeof(SystemInfo).GetProperty("renderingThreadingMode").GetValue(null, null) : null); return (obj != null) ? obj.ToString() : (SystemInfo.graphicsMultiThreaded ? "multihilo" : "un hilo"); } catch (Exception) { return "?"; } } public static string GraphicsSummary() { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return Screen.width + "x" + Screen.height + " · sombras " + QualitySettings.shadowDistance.ToString("0", invariantCulture) + " m/" + QualitySettings.shadowCascades + " cascadas · lodBias " + QualitySettings.lodBias.ToString("0.##", invariantCulture) + " · luces px " + QualitySettings.pixelLightCount + " · luces " + LightLod.m_lightLimit + " sombras puntuales " + LightLod.m_shadowLimit + " · vsync " + QualitySettings.vSyncCount + " · límite FPS " + Application.targetFrameRate; } public static string SystemSummary() { //IL_0031: 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) return SystemInfo.graphicsDeviceName + " (" + SystemInfo.graphicsMemorySize + " MB, " + ((object)SystemInfo.graphicsDeviceType/*cast due to .constrained prefix*/).ToString() + ") · " + SystemInfo.processorType + " (" + SystemInfo.processorCount + " hilos) · RAM " + SystemInfo.systemMemorySize + " MB"; } public string StartAb(string toggle, BenchPoint point, float seconds, int rounds) { if (_ab != null || Bench.Running) { return "ya hay un benchmark o A/B corriendo (vsm_perf bench parar)."; } if (!Toggles.Exists(toggle)) { return "no existe la mejora «" + toggle + "»."; } AbRun abRun = (_ab = new AbRun(this, toggle, point, seconds, rounds)); string result = abRun.Start(); if (!abRun.Started && _ab == abRun) { _ab = null; } return result; } internal void AbFinished() { _ab = null; } public static void Print(string msg) { PerfPlugin.Log.LogInfo((object)msg); try { if ((Object)(object)Console.instance != (Object)null) { ((Terminal)Console.instance).AddString(msg); } } catch (Exception) { } } public static void Notify(string msg) { Print(msg); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)1, msg, 0, (Sprite)null, false); } } public string StartDiff(string toggle) { if (!Toggles.Exists(toggle) || string.Equals(toggle, "horizon", StringComparison.OrdinalIgnoreCase)) { return "uso: vsm_perf diff <mejora> (sombras, resolucion, depthnormals, solchicos, soldistancia)."; } if ((Object)(object)RenderOverrides.MainCamera == (Object)null) { return "hay que estar en el mundo."; } ((MonoBehaviour)this).StartCoroutine(DiffRoutine(toggle)); return "capturando A y B en el mismo frame…"; } private IEnumerator DiffRoutine(string toggle) { yield return (object)new WaitForEndOfFrame(); Camera mainCamera = RenderOverrides.MainCamera; if ((Object)(object)mainCamera == (Object)null) { yield break; } Texture2D val = null; Texture2D val2 = null; string error = null; Toggles.BeginSession(); try { if (!Toggles.Set(toggle, b: false, out error)) { yield break; } Shadows.Invalidate(); Tweaks.Apply(); val = Capture(mainCamera); Toggles.Set(toggle, b: true, out error); Shadows.Invalidate(); Tweaks.Apply(); val2 = Capture(mainCamera); } finally { Toggles.EndSession(); Shadows.Invalidate(); Tweaks.Apply(); if (error != null) { Print("vsm.perf diff: " + error); } } if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { byte[] rawTextureData = val.GetRawTextureData(); byte[] rawTextureData2 = val2.GetRawTextureData(); byte[] array = new byte[rawTextureData.Length]; int num = PixelDiff.CountDifferent(rawTextureData, rawTextureData2, 8, array); int num2 = rawTextureData.Length / 4; Texture2D val3 = new Texture2D(((Texture)val).width, ((Texture)val).height, (TextureFormat)4, false); val3.LoadRawTextureData(array); val3.Apply(false); string text = Path.Combine(PerfPlugin.DataDir, "diff"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, toggle + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture)); File.WriteAllBytes(text2 + "_A.png", ImageConversion.EncodeToPNG(val)); File.WriteAllBytes(text2 + "_B.png", ImageConversion.EncodeToPNG(val2)); File.WriteAllBytes(text2 + "_dif.png", ImageConversion.EncodeToPNG(val3)); Object.Destroy((Object)(object)val); Object.Destroy((Object)(object)val2); Object.Destroy((Object)(object)val3); double num3 = ((num2 > 0) ? ((double)num * 100.0 / (double)num2) : 0.0); Notify("vsm.perf diff " + toggle + ": " + num3.ToString("0.00", CultureInfo.InvariantCulture) + " % de píxeles distintos (" + text2 + "_*.png)"); } } private static Texture2D Capture(Camera cam) { //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_005c: 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_007e: Expected O, but got Unknown int pixelWidth = cam.pixelWidth; int pixelHeight = cam.pixelHeight; RenderTexture temporary = RenderTexture.GetTemporary(pixelWidth, pixelHeight, 24, (RenderTextureFormat)0); RenderTexture targetTexture = cam.targetTexture; RenderTexture active = RenderTexture.active; try { cam.targetTexture = temporary; cam.Render(); } finally { cam.targetTexture = targetTexture; } RenderTexture.active = temporary; Texture2D val = new Texture2D(pixelWidth, pixelHeight, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)pixelWidth, (float)pixelHeight), 0, 0, false); val.Apply(false); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); return val; } } internal sealed class RenderOverrides : IDisposable { private readonly ShadowGovernor _shadows; private bool _applied; private bool _failedOnce; public static Camera MainCamera { get { GameCamera instance = GameCamera.instance; if (!((Object)(object)instance != (Object)null)) { return null; } return instance.m_camera; } } public RenderOverrides(ShadowGovernor shadows) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown _shadows = shadows; Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull)); Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnPostRender)); } private void OnPreCull(Camera cam) { if ((Object)(object)cam == (Object)null || (Object)(object)cam != (Object)(object)MainCamera) { return; } try { _shadows.Apply(cam); _applied = true; } catch (Exception ex) { Fail(ex); } } private void OnPostRender(Camera cam) { if (_applied && !((Object)(object)cam == (Object)null) && !((Object)(object)cam != (Object)(object)MainCamera)) { try { _shadows.Restore(); } catch (Exception ex) { Fail(ex); } _applied = false; } } public void SafetyRestore() { if (_applied) { _shadows.Restore(); _applied = false; } } private void Fail(Exception ex) { if (!_failedOnce) { _failedOnce = true; PerfPlugin.Log.LogWarning((object)("vsm.perf: error en los ajustes de render (se sigue intentando sin repetir este aviso): " + ex)); } } public void Dispose() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull)); Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnPostRender)); SafetyRestore(); } } internal sealed class SceneTweaks : IDisposable { private static readonly string[] SmallLayers = new string[3] { "item", "Default_small", "piece_nonsolid" }; private Light _sunApplied; private float[] _sunOriginal; private bool _shadowDistanceOverridden; private float _vanillaShadowDistance; private Camera _depthCam; private bool _depthChanged; private bool _depthHadDepth; public SceneTweaks() { GraphicsSettingsManager.GraphicsSettingsChanged += OnGraphicsSettingsChanged; PerfPlugin.Enabled.SettingChanged += OnConfigChanged; PerfPlugin.SunSmallShadowCull.SettingChanged += OnConfigChanged; PerfPlugin.SunShadowDistance.SettingChanged += OnConfigChanged; PerfPlugin.DepthNormalsOff.SettingChanged += OnConfigChanged; } public void Apply() { ApplySun(); ApplyShadowDistance(); ApplyDepth(); } private void OnGraphicsSettingsChanged() { _shadowDistanceOverridden = false; Apply(); } private void OnConfigChanged(object sender, EventArgs e) { Apply(); } private void ApplySun() { EnvMan instance = EnvMan.instance; Light val = (((Object)(object)instance != (Object)null) ? instance.m_dirLight : null); float num = (PerfPlugin.On ? PerfPlugin.SunSmallShadowCull.Value : 0f); if ((Object)(object)_sunApplied != (Object)null && ((Object)(object)_sunApplied != (Object)(object)val || num <= 0f)) { _sunApplied.layerShadowCullDistances = _sunOriginal ?? new float[32]; _sunApplied = null; _sunOriginal = null; } if ((Object)(object)val == (Object)null || num <= 0f) { return; } if ((Object)(object)_sunApplied == (Object)null) { float[] layerShadowCullDistances = val.layerShadowCullDistances; _sunOriginal = ((layerShadowCullDistances != null && layerShadowCullDistances.Length == 32) ? ((float[])layerShadowCullDistances.Clone()) : null); _sunApplied = val; } float[] array = ((_sunOriginal != null) ? ((float[])_sunOriginal.Clone()) : new float[32]); string[] smallLayers = SmallLayers; for (int i = 0; i < smallLayers.Length; i++) { int num2 = LayerMask.NameToLayer(smallLayers[i]); if (num2 >= 0 && num2 < 32) { array[num2] = ((array[num2] > 0f) ? Mathf.Min(array[num2], num) : num); } } val.layerShadowCullDistances = array; } private void ApplyShadowDistance() { float num = (PerfPlugin.On ? PerfPlugin.SunShadowDistance.Value : 0f); if (num <= 0f) { if (_shadowDistanceOverridden) { QualitySettings.shadowDistance = _vanillaShadowDistance; _shadowDistanceOverridden = false; } return; } if (!_shadowDistanceOverridden) { _vanillaShadowDistance = QualitySettings.shadowDistance; _shadowDistanceOverridden = true; } if (!Mathf.Approximately(QualitySettings.shadowDistance, num)) { QualitySettings.shadowDistance = num; } } private void ApplyDepth() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_004e: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Invalid comparison between Unknown and I4 //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_005e: 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) Camera mainCamera = RenderOverrides.MainCamera; bool flag = PerfPlugin.On && PerfPlugin.DepthNormalsOff.Value; if (_depthChanged && ((Object)(object)_depthCam != (Object)(object)mainCamera || !flag)) { if ((Object)(object)_depthCam != (Object)null) { DepthTextureMode val = (DepthTextureMode)(_depthCam.depthTextureMode | 2); _depthCam.depthTextureMode = (DepthTextureMode)(_depthHadDepth ? val : (val & -2)); } _depthChanged = false; _depthCam = null; } if (flag && !((Object)(object)mainCamera == (Object)null) && (mainCamera.depthTextureMode & 2) != 0) { _depthHadDepth = (mainCamera.depthTextureMode & 1) > 0; mainCamera.depthTextureMode = (DepthTextureMode)((mainCamera.depthTextureMode & -3) | 1); _depthCam = mainCamera; _depthChanged = true; } } public string Describe() { return "sol objetos chicos " + ((PerfPlugin.SunSmallShadowCull.Value > 0f) ? (PerfPlugin.SunSmallShadowCull.Value.ToString("0") + " m") : "como el juego") + " · distancia sombras " + QualitySettings.shadowDistance.ToString("0") + " m · profundidad " + (_depthChanged ? "sin normales" : "con normales (juego)"); } public void Dispose() { GraphicsSettingsManager.GraphicsSettingsChanged -= OnGraphicsSettingsChanged; PerfPlugin.Enabled.SettingChanged -= OnConfigChanged; PerfPlugin.SunSmallShadowCull.SettingChanged -= OnConfigChanged; PerfPlugin.SunShadowDistance.SettingChanged -= OnConfigChanged; PerfPlugin.DepthNormalsOff.SettingChanged -= OnConfigChanged; } } internal static class SettingsRow { private sealed class SelectableNav : INavGraph<Selectable> { internal static readonly SelectableNav Instance = new SelectableNav(); public Selectable Get(Selectable node, Direction direction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Navigation navigation = node.navigation; Selectable val = (Selectable)(direction switch { Direction.Up => ((Navigation)(ref navigation)).selectOnUp, Direction.Down => ((Navigation)(ref navigation)).selectOnDown, Direction.Left => ((Navigation)(ref navigation)).selectOnLeft, _ => ((Navigation)(ref navigation)).selectOnRight, }); if (!((Object)(object)val != (Object)null)) { return null; } return val; } public void Set(Selectable node, Direction direction, Selectable target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Navigation navigation = node.navigation; switch (direction) { case Direction.Up: ((Navigation)(ref navigation)).selectOnUp = target; break; case Direction.Down: ((Navigation)(ref navigation)).selectOnDown = target; break; case Direction.Left: ((Navigation)(ref navigation)).selectOnLeft = target; break; default: ((Navigation)(ref navigation)).selectOnRight = target; break; } node.navigation = navigation; } } internal const string RowName = "vsm_perf_row"; internal static bool SavePatched; private static Toggle s_toggle; private static int s_failedFor; private static bool s_warned; private static bool s_loggedException; private static readonly Vector3[] s_corners = (Vector3[])(object)new Vector3[4]; internal static string LastResult = "la pestaña Accesibilidad aún no se abrió"; internal static void OnTabOpen(AccessibilitySettings tab) { if ((Object)(object)tab == (Object)null) { return; } Toggle val = FindRow(((Component)tab).transform); if ((Object)(object)val == (Object)null && !SavePatched) { LastResult = "no se muestra (no se pudo parchear el OK de la pestaña)"; } else if ((Object)(object)val == (Object)null && ((Object)tab).GetInstanceID() != s_failedFor) { val = Create(tab); if ((Object)(object)val == (Object)null) { s_failedFor = ((Object)tab).GetInstanceID(); } } s_toggle = val; if ((Object)(object)val != (Object)null) { val.SetIsOnWithoutNotify(PerfPlugin.Enabled.Value); Link(tab, val); } } internal static void OnOk(AccessibilitySettings tab) { if ((Object)(object)tab == (Object)null) { return; } Toggle val = s_toggle; if ((Object)(object)val == (Object)null || !((Component)val).transform.IsChildOf(((Component)tab).transform)) { val = FindRow(((Component)tab).transform); } if (!((Object)(object)val == (Object)null)) { bool isOn = val.isOn; if (PerfPlugin.Enabled.Value != isOn) { PerfPlugin.Enabled.Value = isOn; PerfPlugin.Log.LogInfo((object)("vsm.perf: Enabled = " + isOn + " (Ajustes → Accesibilidad).")); } } } internal static void SyncFromConfig() { Toggle val = s_toggle; if ((Object)(object)val != (Object)null && val.isOn != PerfPlugin.Enabled.Value) { val.SetIsOnWithoutNotify(PerfPlugin.Enabled.Value); } } private static Toggle FindRow(Transform root) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == "vsm_perf_row") { Toggle componentInChildren = ((Component)val).GetComponentInChildren<Toggle>(true); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren; } } } return null; } private static Toggle PickTemplate(AccessibilitySettings tab) { Toggle[] obj = new Toggle[9] { tab.m_reduceFlashingLights, tab.m_cameraShake, tab.m_immersiveCamera, tab.m_toggleRun, tab.m_toggleBlockToggle, tab.m_depthOfFieldToggle, tab.m_motionblurToggle, tab.m_soundIndicatorsToggle, tab.m_closedCaptionsToggle }; Toggle val = null; Toggle[] array = (Toggle[])(object)obj; foreach (Toggle val2 in array) { if (!((Object)(object)val2 == (Object)null) && ((Component)val2).transform.IsChildOf(((Component)tab).transform)) { if (((Component)val2).gameObject.activeSelf) { return val2; } if ((Object)(object)val == (Object)null) { val = val2; } } } return val; } private static Transform RowRoot(Transform control, Transform page) { Transform val = control; while ((Object)(object)val.parent != (Object)null && (Object)(object)val.parent != (Object)(object)page && val.parent.IsChildOf(page) && ((Component)val.parent).GetComponentsInChildren<Selectable>(true).Length == 1) { val = val.parent; } return val; } private static Toggle Create(AccessibilitySettings tab) { Toggle val = PickTemplate(tab); if ((Object)(object)val == (Object)null) { return Fail("no hay ningún interruptor vanilla que copiar en la pestaña", null); } Transform val2 = RowRoot(((Component)val).transform, ((Component)tab).transform); Transform parent = val2.parent; if ((Object)(object)parent == (Object)null) { return Fail("la fila plantilla no tiene padre", null); } GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, parent, false); try { ((Object)val3).name = "vsm_perf_row"; val3.SetActive(true); Toggle val4 = MainToggle(val3.transform, val2, ((Component)val).transform); if ((Object)(object)val4 == (Object)null) { return Fail("la copia no tiene el interruptor", val3); } string text = Configure(tab, val3, val4); if (text != null) { return Fail(text, val3); } text = Place(tab, val3, val4, parent, out var where);