Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of LittleLooneys LocalPerformance v0.3.1
Mods\ScheduleI.LocalPerformance.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.UI.MainMenu; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using ScheduleILocalPerformance; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Mod), "LittleLooney's Local Performance", "0.3.1", "LittleLooney", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ScheduleI.LocalPerformance")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.1.0")] [assembly: AssemblyInformationalVersion("0.3.1")] [assembly: AssemblyProduct("ScheduleI.LocalPerformance")] [assembly: AssemblyTitle("ScheduleI.LocalPerformance")] [assembly: AssemblyVersion("0.3.1.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ScheduleILocalPerformance { internal static class GraphicsTuning { private static UniversalRenderPipelineAsset? asset; private static readonly OwnedFloat scale = new OwnedFloat(); private static readonly OwnedFloat shadows = new OwnedFloat(); private static readonly OwnedFloat lod = new OwnedFloat(); private static float nextPoll; private static bool hasOverrides; internal static string Status { get; private set; } = "Original graphics"; internal static void Tick(bool active) { Mod instance = Mod.Instance; if (!active || !instance.graphics.Value) { Restore(); } else { if (Time.unscaledTime < nextPoll) { return; } nextPoll = Time.unscaledTime + 0.5f; RenderPipelineAsset currentRenderPipeline = GraphicsSettings.currentRenderPipeline; UniversalRenderPipelineAsset val = ((currentRenderPipeline != null) ? ((Il2CppObjectBase)currentRenderPipeline).TryCast<UniversalRenderPipelineAsset>() : null); if ((Object)(object)val != (Object)(object)asset) { Restore(); asset = val; } if ((Object)(object)asset == (Object)null) { Status = "URP not detected; graphics overrides skipped"; return; } hasOverrides = true; float num = scale.Apply(asset.renderScale, RenderPolicy.Scale(instance.scale.Value)); float num2 = shadows.Apply(asset.shadowDistance, RenderPolicy.ShadowDistance(instance.shadows.Value)); float num3 = lod.Apply(QualitySettings.lodBias, RenderPolicy.Lod(instance.lod.Value)); bool num4 = asset.renderScale != num || asset.shadowDistance != num2 || QualitySettings.lodBias != num3; asset.renderScale = num; asset.shadowDistance = num2; QualitySettings.lodBias = num3; Status = $"Applied: scale {num * 100f:F0}%, shadows {num2:F0} m, LOD {num3:F2}"; if (num4) { instance.Log(Status + ". Local rendering only."); } } } internal static void Refresh() { nextPoll = 0f; } internal static void Restore() { if (hasOverrides) { if ((Object)(object)asset != (Object)null) { asset.renderScale = scale.Restore(asset.renderScale); asset.shadowDistance = shadows.Restore(asset.shadowDistance); } else { scale.Restore(0f); shadows.Restore(0f); } QualitySettings.lodBias = lod.Restore(QualitySettings.lodBias); asset = null; hasOverrides = false; Status = "Original graphics"; } } } internal static class MenuLayout { public static float TabWidth(float left, float right, int count, float gap) { if (count <= 0) { return 0f; } return Math.Max(0f, (right - left - gap * (float)(count - 1)) / (float)count); } public static float TabCenter(float left, float width, int index, float gap) { return left + width / 2f + (float)index * (width + gap); } } public sealed class Mod : MelonMod { internal MelonPreferences_Entry<bool> enabled; internal MelonPreferences_Entry<bool> logging; internal MelonPreferences_Entry<bool> statistics; internal MelonPreferences_Entry<float> distance; internal MelonPreferences_Entry<float> padding; internal MelonPreferences_Entry<string> toggle; internal MelonPreferences_Entry<string> excluded; internal MelonPreferences_Entry<bool> graphics; internal MelonPreferences_Entry<float> scale; internal MelonPreferences_Entry<float> shadows; internal MelonPreferences_Entry<float> lod; private MelonPreferences_Category category; private Camera? camera; private readonly float[] original = new float[32]; private readonly float[] applied = new float[32]; private readonly float[] samples = new float[1800]; private bool hasDistances; private bool ownsMatrix; private bool originalAutomatic; private bool originalSpherical; private Matrix4x4 originalMatrix; private Matrix4x4 lastMatrix; private int sampleCount; private int sampleIndex; private float nextPoll; private float nextReport; private float nextError; internal static Mod Instance { get; private set; } public override void OnInitializeMelon() { Instance = this; category = MelonPreferences.CreateCategory("LittleLooneysLocalPerformance"); enabled = category.CreateEntry<bool>("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); distance = category.CreateEntry<float>("RenderDistanceMeters", 200f, "World render distance", "50–1000 m. Shorter existing layer limits are preserved. Does not change simulation distance.", false, false, (ValueValidator)null, (string)null); padding = category.CreateEntry<float>("VisibilityPaddingDegrees", 0f, "Extra culling FOV", "0–30 degrees. Set 10 for a 100-degree culling view at FOV 90. Does not change visible FOV; widening can cost performance.", false, false, (ValueValidator)null, (string)null); excluded = category.CreateEntry<string>("ExcludedLayers", "UI,ViewModel,Viewmodel,FirstPerson,Overlay", "Layers without a distance limit", "Comma-separated Unity layer names. The separate overlay camera is always untouched.", false, false, (ValueValidator)null, (string)null); toggle = category.CreateEntry<string>("ToggleKey", "F6", "Comparison toggle", "Unity Input System key name. Changes Enabled for this session.", false, false, (ValueValidator)null, (string)null); logging = category.CreateEntry<bool>("EnableLogging", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); statistics = category.CreateEntry<bool>("LogFrameStatistics", false, "Frame-time reports", "Reports the most recent 1800 frames every 30 seconds. Resets when toggled or settings change.", false, false, (ValueValidator)null, (string)null); graphics = category.CreateEntry<bool>("EnableGraphicsOverrides", false, "Additional graphics optimization", "Opt-in local URP render-scale, shadow-distance and LOD limits. F6 restores these along with camera limits.", false, false, (ValueValidator)null, (string)null); scale = category.CreateEntry<float>("RenderScale", 1f, "Rendering resolution scale", "0.5–1.0. Lower values render fewer pixels and soften the image; existing lower scales are preserved.", false, false, (ValueValidator)null, (string)null); shadows = category.CreateEntry<float>("ShadowDistanceMeters", 75f, "Maximum shadow distance", "0–300 m. Zero removes distance-based realtime shadows; existing shorter limits are preserved.", false, false, (ValueValidator)null, (string)null); lod = category.CreateEntry<float>("LODBias", 1f, "Maximum LOD bias", "0.25–1.0. Smaller values select simpler existing LOD meshes earlier. Only affects objects with LOD groups.", false, false, (ValueValidator)null, (string)null); if (logging.Value) { MelonLogger.Msg(ConsoleColor.Magenta, "+----------------------------------------+"); MelonLogger.Msg(ConsoleColor.Cyan, "| LittleLooney's Mods |"); MelonLogger.Msg(ConsoleColor.Magenta, "| LOCAL PERFORMANCE |"); MelonLogger.Msg(ConsoleColor.Cyan, "+----------------------------------------+"); } Log("Experimental 0.3.1: Settings > Performance includes General and Graphics pages with hover help. F6 toggles by default."); } public override void OnUpdate() { //IL_001d: 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) try { PerformanceMenu.Tick(); if (Enum.TryParse<Key>(toggle.Value, ignoreCase: true, out Key result) && (int)result != 0 && Keyboard.current != null && ((ButtonControl)Keyboard.current[result]).wasPressedThisFrame) { enabled.Value = !enabled.Value; nextPoll = 0f; ResetStatistics(); Log($"Comparison toggle: enabled={enabled.Value}."); } } catch (Exception error) { Fail(error); } } public override void OnLateUpdate() { try { LoadManager instance = Singleton<LoadManager>.Instance; object obj; if (!enabled.Value || !((Object)(object)instance != (Object)null) || !instance.IsGameLoaded || instance.IsLoading) { obj = null; } else { PlayerCamera instance2 = PlayerSingleton<PlayerCamera>.Instance; obj = ((instance2 != null) ? instance2.Camera : null); } Camera val = (Camera)obj; if ((Object)(object)camera != (Object)(object)val) { Restore(); camera = val; nextPoll = 0f; ResetStatistics(); } if ((Object)(object)camera != (Object)null && Time.unscaledTime >= nextPoll) { nextPoll = Time.unscaledTime + 0.5f; ApplyDistances(); } if ((Object)(object)camera != (Object)null) { ApplyPadding(); } GraphicsTuning.Tick((Object)(object)camera != (Object)null); if (!statistics.Value || !((Object)(object)instance != (Object)null) || !instance.IsGameLoaded || instance.IsLoading) { return; } samples[sampleIndex] = Time.unscaledDeltaTime * 1000f; sampleIndex = (sampleIndex + 1) % samples.Length; sampleCount = Math.Min(sampleCount + 1, samples.Length); if (Time.unscaledTime >= nextReport) { nextReport = Time.unscaledTime + 30f; float num = 0f; for (int i = 0; i < sampleCount; i++) { num += samples[i]; } Log($"Frame window: enabled={enabled.Value}, frames={sampleCount}, meanFPS={((num > 0f) ? ((float)(sampleCount * 1000) / num) : 0f):F1}, p95FrameMs={RenderPolicy.Percentile95(samples, sampleCount):F2}, radius={RenderPolicy.Distance(distance.Value):F0}m, padding={RenderPolicy.Padding(padding.Value):F0}deg. Includes CPU/GPU stalls, not a GPU-only measurement."); } } catch (Exception error) { Fail(error); Restore(); GraphicsTuning.Restore(); } } private void ApplyDistances() { Il2CppStructArray<float> layerCullDistances = camera.layerCullDistances; if (!hasDistances) { originalSpherical = camera.layerCullSpherical; } string[] source = excluded.Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); float[] array = new float[32]; bool flag = !hasDistances; for (int i = 0; i < 32; i++) { if (!hasDistances || ((Il2CppArrayBase<float>)(object)layerCullDistances)[i] != applied[i]) { original[i] = ((Il2CppArrayBase<float>)(object)layerCullDistances)[i]; } string name = LayerMask.LayerToName(i); bool flag2 = (camera.cullingMask & (1 << i)) == 0 || source.Any((string item) => item.Equals(name, StringComparison.OrdinalIgnoreCase)); array[i] = (flag2 ? original[i] : RenderPolicy.CullDistance(original[i], distance.Value)); flag |= array[i] != applied[i]; applied[i] = array[i]; } if (flag) { camera.layerCullDistances = Il2CppStructArray<float>.op_Implicit(array); camera.layerCullSpherical = true; ResetStatistics(); Log($"Camera '{((Object)camera).name}': distance={RenderPolicy.Distance(distance.Value):F0}m, culling mask=0x{camera.cullingMask:X8}, excluded='{excluded.Value}', spherical={camera.layerCullSpherical}. Overlay camera unchanged."); } hasDistances = true; } private void ApplyPadding() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) float num = RenderPolicy.Padding(padding.Value); if (num == 0f || camera.orthographic) { RestoreMatrix(); return; } if (!ownsMatrix) { originalMatrix = camera.cullingMatrix; originalAutomatic = Approximately(originalMatrix, camera.projectionMatrix * camera.worldToCameraMatrix); if (!originalAutomatic) { return; } } else if (!Approximately(camera.cullingMatrix, lastMatrix)) { ownsMatrix = false; return; } Matrix4x4 projectionMatrix = camera.projectionMatrix; float num2 = Mathf.Tan(camera.fieldOfView * ((float)Math.PI / 180f) * 0.5f) / Mathf.Tan(RenderPolicy.PaddedFov(camera.fieldOfView, num) * ((float)Math.PI / 180f) * 0.5f); projectionMatrix.m00 *= num2; projectionMatrix.m11 *= num2; lastMatrix = projectionMatrix * camera.worldToCameraMatrix; camera.cullingMatrix = lastMatrix; ownsMatrix = true; } private void RestoreMatrix() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)camera != (Object)null && ownsMatrix && Approximately(camera.cullingMatrix, lastMatrix)) { if (originalAutomatic) { camera.ResetCullingMatrix(); } else { camera.cullingMatrix = originalMatrix; } } ownsMatrix = false; } private void Restore() { if ((Object)(object)camera != (Object)null) { RestoreMatrix(); if (hasDistances) { Il2CppStructArray<float> layerCullDistances = camera.layerCullDistances; float[] array = new float[32]; for (int i = 0; i < 32; i++) { array[i] = RenderPolicy.Restore(((Il2CppArrayBase<float>)(object)layerCullDistances)[i], applied[i], original[i]); } camera.layerCullDistances = Il2CppStructArray<float>.op_Implicit(array); if (camera.layerCullSpherical) { camera.layerCullSpherical = originalSpherical; } Log("Restored owned world-camera distance settings."); } } camera = null; hasDistances = false; ownsMatrix = false; } private static bool Approximately(Matrix4x4 a, Matrix4x4 b) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (Mathf.Abs(((Matrix4x4)(ref a))[i, j] - ((Matrix4x4)(ref b))[i, j]) > 0.0001f) { return false; } } } return true; } internal void SettingsChanged() { nextPoll = 0f; GraphicsTuning.Refresh(); ResetStatistics(); } internal void BalancedPreset() { MelonPreferences_Entry<bool> obj = enabled; bool value = (graphics.Value = true); obj.Value = value; distance.Value = 200f; padding.Value = 0f; scale.Value = 0.85f; shadows.Value = 50f; lod.Value = 0.75f; SettingsChanged(); } internal void SaveSettings() { category.SaveToFile(true); Log("Performance settings saved."); } internal void ResetDefaults() { enabled.Value = true; distance.Value = 200f; padding.Value = 0f; logging.Value = true; statistics.Value = false; toggle.Value = "F6"; excluded.Value = "UI,ViewModel,Viewmodel,FirstPerson,Overlay"; graphics.Value = false; scale.Value = 1f; shadows.Value = 75f; lod.Value = 1f; SettingsChanged(); } private void ResetStatistics() { sampleCount = (sampleIndex = 0); nextReport = Time.unscaledTime + 30f; } internal void Log(string message) { if (logging.Value) { MelonLogger.Msg("[LocalPerformance] " + message); } } private void Fail(Exception error) { if (logging.Value && Time.unscaledTime >= nextError) { nextError = Time.unscaledTime + 10f; MelonLogger.Error("[LocalPerformance] " + error); } } public override void OnApplicationQuit() { Restore(); GraphicsTuning.Restore(); } public override void OnDeinitializeMelon() { PerformanceMenu.Cleanup(); Restore(); GraphicsTuning.Restore(); } } [HarmonyPatch(typeof(SettingsScreen), "OnEnable")] internal static class AddPerformanceCategory { private static void Postfix(SettingsScreen __instance) { PerformanceMenu.Ensure(__instance); } } internal static class PerformanceMenu { private sealed class State { internal SettingsScreen Screen; internal Toggle Tab; internal GameObject Panel; internal readonly List<Action> Refreshers = new List<Action>(); internal TMP_FontAsset Font; internal TextMeshProUGUI Status; internal bool GraphicsPage; internal TextMeshProUGUI Help; internal string Hint = ""; internal string DefaultHint = ""; internal RectTransform? Hovered; internal float HoverStart; internal readonly List<TabRect> OriginalTabs = new List<TabRect>(); internal Behaviour? Layout; internal bool LayoutEnabled; internal float Left; internal float Right; internal RectTransform TabParent; } private sealed class TabRect { internal RectTransform Rect; internal Vector2 Min; internal Vector2 Max; internal Vector2 Pivot; internal Vector2 Position; internal Vector2 Size; internal TextMeshProUGUI? Text; internal bool AutoSize; internal float FontMin; internal float FontMax; internal float FontSize; internal Vector2 TextMin; internal Vector2 TextMax; internal Vector2 TextOffsetsMin; internal Vector2 TextOffsetsMax; internal Vector2 TextPivot; internal TabRect(RectTransform rect) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) Rect = rect; Min = rect.anchorMin; Max = rect.anchorMax; Pivot = rect.pivot; Position = rect.anchoredPosition; Size = rect.sizeDelta; Text = ((Component)rect).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)Text != (Object)null) { AutoSize = ((TMP_Text)Text).enableAutoSizing; FontMin = ((TMP_Text)Text).fontSizeMin; FontMax = ((TMP_Text)Text).fontSizeMax; FontSize = ((TMP_Text)Text).fontSize; RectTransform rectTransform = ((TMP_Text)Text).rectTransform; TextMin = rectTransform.anchorMin; TextMax = rectTransform.anchorMax; TextOffsetsMin = rectTransform.offsetMin; TextOffsetsMax = rectTransform.offsetMax; TextPivot = rectTransform.pivot; } } internal void Restore() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Rect == (Object)null)) { Rect.anchorMin = Min; Rect.anchorMax = Max; Rect.pivot = Pivot; Rect.sizeDelta = Size; Rect.anchoredPosition = Position; if ((Object)(object)Text != (Object)null) { ((TMP_Text)Text).enableAutoSizing = AutoSize; ((TMP_Text)Text).fontSizeMin = FontMin; ((TMP_Text)Text).fontSizeMax = FontMax; ((TMP_Text)Text).fontSize = FontSize; RectTransform rectTransform = ((TMP_Text)Text).rectTransform; rectTransform.anchorMin = TextMin; rectTransform.anchorMax = TextMax; rectTransform.pivot = TextPivot; rectTransform.offsetMin = TextOffsetsMin; rectTransform.offsetMax = TextOffsetsMax; } } } } private static readonly Dictionary<IntPtr, State> states = new Dictionary<IntPtr, State>(); private static float nextRefresh; private static float nextDiscovery; internal static void Tick() { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < nextRefresh) { return; } nextRefresh = Time.unscaledTime + 0.25f; KeyValuePair<IntPtr, State>[] array = states.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<IntPtr, State> keyValuePair = array[i]; if ((Object)(object)keyValuePair.Value.Screen == (Object)null || (Object)(object)keyValuePair.Value.Panel == (Object)null) { states.Remove(keyValuePair.Key); continue; } if (((Behaviour)keyValuePair.Value.Screen).isActiveAndEnabled) { FitTabs(keyValuePair.Value); } if (keyValuePair.Value.Panel.activeInHierarchy) { Refresh(keyValuePair.Value); } else { keyValuePair.Value.Hovered = null; } } if (Time.unscaledTime < nextDiscovery) { return; } nextDiscovery = Time.unscaledTime + 2f; foreach (SettingsScreen item in Resources.FindObjectsOfTypeAll<SettingsScreen>()) { if ((Object)(object)item != (Object)null) { Scene scene = ((Component)item).gameObject.scene; if (((Scene)(ref scene)).IsValid() && ((Behaviour)item).isActiveAndEnabled) { Ensure(item); } } } } internal static void Ensure(SettingsScreen screen) { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Expected O, but got Unknown //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Expected O, but got Unknown //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Expected O, but got Unknown if (states.ContainsKey(((Il2CppObjectBase)screen).Pointer)) { return; } State state = null; try { Il2CppReferenceArray<SettingsCategory> categories = screen.Categories; if (categories == null || ((Il2CppArrayBase<SettingsCategory>)(object)categories).Length == 0) { return; } SettingsCategory val = ((Il2CppArrayBase<SettingsCategory>)(object)categories)[((Il2CppArrayBase<SettingsCategory>)(object)categories).Length - 1]; if ((Object)(object)((val != null) ? val.Toggle : null) == (Object)null || (Object)(object)val.Panel == (Object)null) { return; } TextMeshProUGUI componentInChildren = ((Component)val.Toggle).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren == (Object)null) { throw new InvalidOperationException("Settings category has no TMP label to reuse."); } state = new State { Screen = screen, Font = ((TMP_Text)componentInChildren).font }; state.TabParent = ((Il2CppObjectBase)((Component)val.Toggle).transform.parent).TryCast<RectTransform>() ?? throw new InvalidOperationException("Settings tabs need a RectTransform parent."); LayoutRebuilder.ForceRebuildLayoutImmediate(state.TabParent); Il2CppStructArray<Vector3> val2 = new Il2CppStructArray<Vector3>(4L); state.Left = float.PositiveInfinity; state.Right = float.NegativeInfinity; foreach (SettingsCategory item in (Il2CppArrayBase<SettingsCategory>)(object)categories) { RectTransform component = ((Component)item.Toggle).GetComponent<RectTransform>(); state.OriginalTabs.Add(new TabRect(component)); component.GetWorldCorners(val2); foreach (Vector3 item2 in (Il2CppArrayBase<Vector3>)(object)val2) { float x = ((Transform)state.TabParent).InverseTransformPoint(item2).x; state.Left = Math.Min(state.Left, x); state.Right = Math.Max(state.Right, x); } } State state2 = state; HorizontalLayoutGroup component2 = ((Component)state.TabParent).GetComponent<HorizontalLayoutGroup>(); object obj = ((component2 != null) ? ((Il2CppObjectBase)component2).TryCast<Behaviour>() : null); if (obj == null) { GridLayoutGroup component3 = ((Component)state.TabParent).GetComponent<GridLayoutGroup>(); obj = ((component3 != null) ? ((Il2CppObjectBase)component3).TryCast<Behaviour>() : null); } state2.Layout = (Behaviour?)obj; if ((Object)(object)state.Layout != (Object)null) { state.LayoutEnabled = state.Layout.enabled; state.Layout.enabled = false; } GameObject val3 = new GameObject("LocalPerformanceStaging"); val3.SetActive(false); val3.transform.SetParent(((Component)val.Toggle).transform.parent, false); try { GameObject val4 = Object.Instantiate<GameObject>(((Component)val.Toggle).gameObject, val3.transform, false); ((Object)val4).name = "LittleLooneyPerformanceTab"; val4.SetActive(false); val4.transform.SetParent(((Component)val.Toggle).transform.parent, false); state.Tab = val4.GetComponent<Toggle>(); state.Tab.onValueChanged = new ToggleEvent(); state.Tab.SetIsOnWithoutNotify(false); ((Selectable)state.Tab).interactable = true; TextMeshProUGUI componentInChildren2 = val4.GetComponentInChildren<TextMeshProUGUI>(true); ((TMP_Text)componentInChildren2).text = "Performance"; ((TMP_Text)componentInChildren2).enableAutoSizing = true; ((TMP_Text)componentInChildren2).fontSizeMin = 12f; ((TMP_Text)componentInChildren2).fontSizeMax = ((TMP_Text)componentInChildren).fontSize; } finally { Object.Destroy((Object)(object)val3); } state.Panel = new GameObject("LittleLooneyPerformancePanel"); state.Panel.SetActive(false); RectTransform obj2 = state.Panel.AddComponent<RectTransform>(); RectTransform component4 = val.Panel.GetComponent<RectTransform>(); ((Transform)obj2).SetParent(((Transform)component4).parent, false); obj2.anchorMin = component4.anchorMin; obj2.anchorMax = component4.anchorMax; obj2.pivot = component4.pivot; obj2.sizeDelta = component4.sizeDelta; obj2.anchoredPosition = component4.anchoredPosition; Build(state); Il2CppReferenceArray<SettingsCategory> val5 = new Il2CppReferenceArray<SettingsCategory>((long)(((Il2CppArrayBase<SettingsCategory>)(object)categories).Length + 1)); for (int i = 0; i < ((Il2CppArrayBase<SettingsCategory>)(object)categories).Length; i++) { ((Il2CppArrayBase<SettingsCategory>)(object)val5)[i] = ((Il2CppArrayBase<SettingsCategory>)(object)categories)[i]; } ((Il2CppArrayBase<SettingsCategory>)(object)val5)[((Il2CppArrayBase<SettingsCategory>)(object)categories).Length] = new SettingsCategory { Toggle = state.Tab, Panel = state.Panel }; screen.Categories = val5; State captured = state; ((UnityEvent<bool>)(object)state.Tab.onValueChanged).AddListener(UnityAction<bool>.op_Implicit((Action<bool>)delegate(bool value) { if (value && !((Object)(object)captured.Screen == (Object)null)) { Il2CppReferenceArray<SettingsCategory> categories2 = captured.Screen.Categories; for (int j = 0; j < ((Il2CppArrayBase<SettingsCategory>)(object)categories2).Length; j++) { bool flag = (Object)(object)((Il2CppArrayBase<SettingsCategory>)(object)categories2)[j].Panel == (Object)(object)captured.Panel; ((Selectable)((Il2CppArrayBase<SettingsCategory>)(object)categories2)[j].Toggle).interactable = !flag; ((Il2CppArrayBase<SettingsCategory>)(object)categories2)[j].Toggle.SetIsOnWithoutNotify(flag); ((Il2CppArrayBase<SettingsCategory>)(object)categories2)[j].Panel.SetActive(flag); } ((TMP_Text)captured.Status).text = "Changes apply now. Save to keep them after restarting."; Refresh(captured); } })); ((Component)state.Tab).gameObject.SetActive(true); states.Add(((Il2CppObjectBase)screen).Pointer, state); FitTabs(state); Mod.Instance.Log($"Registered Performance category in settings '{((Object)screen).name}', category count={((Il2CppArrayBase<SettingsCategory>)(object)val5).Length}."); } catch (Exception ex) { if (state != null) { RestoreTabs(state); } if ((Object)(object)state?.Panel != (Object)null && screen.Categories != null) { SettingsCategory[] array = ((IEnumerable<SettingsCategory>)screen.Categories).Where((SettingsCategory category) => (Object)(object)category.Panel != (Object)(object)state.Panel).ToArray(); screen.Categories = new Il2CppReferenceArray<SettingsCategory>(array); } if ((Object)(object)state?.Tab != (Object)null) { Object.Destroy((Object)(object)((Component)state.Tab).gameObject); } if ((Object)(object)state?.Panel != (Object)null) { Object.Destroy((Object)(object)state.Panel); } Mod.Instance.Log("Settings category creation failed: " + ex); } } private static void Build(State state) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_05e1: Unknown result type (might be due to invalid IL or missing references) //IL_0647: Unknown result type (might be due to invalid IL or missing references) Transform transform = state.Panel.transform; state.Refreshers.Clear(); state.Hovered = null; for (int num = transform.childCount - 1; num >= 0; num--) { GameObject gameObject = ((Component)transform.GetChild(num)).gameObject; gameObject.SetActive(false); Object.Destroy((Object)(object)gameObject); } Label(state, transform, "Performance", 0.04f, 0.7f, 0.89f, 0.99f, 27f); TextMeshProUGUI obj = Label(state, transform, "LittleLooney", 0.72f, 0.96f, 0.89f, 0.99f, 16f); ((TMP_Text)obj).alignment = (TextAlignmentOptions)516; ((Graphic)obj).color = new Color(0.65f, 0.68f, 0.72f); TextMeshProUGUI val = Button(state, transform, "General", 0.04f, 0.49f, 0.78f, 0.86f, delegate { state.GraphicsPage = false; Build(state); }); TextMeshProUGUI val2 = Button(state, transform, "Graphics", 0.51f, 0.96f, 0.78f, 0.86f, delegate { state.GraphicsPage = true; Build(state); }); ((Graphic)(state.GraphicsPage ? val2 : val)).color = new Color(0.65f, 0.86f, 0.89f); Mod mod = Mod.Instance; if (state.GraphicsPage) { BooleanRow(state, "Use graphics tuning", 0.67f, () => mod.graphics.Value, delegate(bool value) { mod.graphics.Value = value; }, "Turns on the three settings below. The main Performance switch must also be on. Turn this off to restore your game's original graphics."); NumberRow(state, "Render resolution", 0.58f, () => RenderPolicy.Scale(mod.scale.Value) * 100f, delegate(float value) { mod.scale.Value = RenderPolicy.Scale(value / 100f); }, 5f, "%", "Lower values draw fewer pixels. This can improve FPS, but the picture looks softer. 100% keeps full resolution."); NumberRow(state, "Shadow range", 0.49f, () => RenderPolicy.ShadowDistance(mod.shadows.Value), delegate(float value) { mod.shadows.Value = RenderPolicy.ShadowDistance(value); }, 10f, "m", "How far away real-time shadows are drawn. Lower values can improve FPS. 0 turns these shadows off; baked shadows may remain."); NumberRow(state, "Distant detail", 0.4f, () => RenderPolicy.Lod(mod.lod.Value) * 100f, delegate(float value) { mod.lod.Value = RenderPolicy.Lod(value / 100f); }, 5f, "%", "Lower values show simpler models sooner. This can help FPS, but details may change as you move. Only models with simpler versions are affected."); TextMeshProUGUI val3 = Button(state, transform, "Balanced preset", 0.04f, 0.49f, 0.29f, 0.37f, delegate { mod.BalancedPreset(); ((TMP_Text)state.Status).text = "Balanced preset applied. Save to keep it."; Refresh(state); }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val3).rectTransform).parent).TryCast<RectTransform>(), "A starting point: 200 m draw distance, 85% resolution, 50 m shadows and 75% distant detail. Turns Performance and graphics tuning on."); TextMeshProUGUI val4 = Button(state, transform, "Restore graphics", 0.51f, 0.96f, 0.29f, 0.37f, delegate { mod.graphics.Value = false; mod.SettingsChanged(); ((TMP_Text)state.Status).text = "Graphics tuning off. Draw distance unchanged."; Refresh(state); }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val4).rectTransform).parent).TryCast<RectTransform>(), "Turns off graphics tuning and restores the original values. Draw distance is separate; turn Performance off to restore everything."); state.DefaultHint = "Start with Balanced. Lower settings trade picture quality for FPS."; } else { BooleanRow(state, "Performance", 0.67f, () => mod.enabled.Value, delegate(bool value) { mod.enabled.Value = value; }, "The main switch for this mod. Off restores draw distance and graphics tuning. This only changes your graphics, not other players' games."); NumberRow(state, "Draw distance", 0.58f, () => RenderPolicy.Distance(mod.distance.Value), delegate(float value) { mod.distance.Value = RenderPolicy.Distance(value); }, 25f, "m", "How far away objects are drawn. A shorter distance can help FPS, but distant scenery may disappear. People, deals and saves keep working."); NumberRow(state, "View buffer", 0.49f, () => RenderPolicy.Padding(mod.padding.Value), delegate(float value) { mod.padding.Value = RenderPolicy.Padding(value); }, 5f, "°", "Keeps extra objects near the edge of your view eligible to draw. Your visible field of view does not change. Leave at 0 for best performance."); BooleanRow(state, "Diagnostic logs", 0.4f, () => mod.logging.Value, delegate(bool value) { mod.logging.Value = value; }, "Writes settings changes and errors to the MelonLoader log. Enable this when reporting a problem."); BooleanRow(state, "FPS reports", 0.31f, () => mod.statistics.Value, delegate(bool value) { mod.statistics.Value = value; }, "Writes average FPS and slow-frame times to the log every 30 seconds. Diagnostic logs must be on. Walk the same route with Performance on and off to compare."); TextMeshProUGUI val5 = Label(state, transform, "Comparison key", 0.06f, 0.61f, 0.22f, 0.295f, 20f); TextMeshProUGUI key = Button(state, transform, "", 0.65f, 0.94f, 0.22f, 0.295f, delegate { string[] array = new string[5] { "F6", "F7", "F8", "F9", "None" }; int num2 = Array.FindIndex(array, (string value) => value.Equals(mod.toggle.Value, StringComparison.OrdinalIgnoreCase)); mod.toggle.Value = array[(num2 + 1) % array.Length]; mod.SettingsChanged(); Refresh(state); }); state.Refreshers.Add(delegate { ((TMP_Text)key).text = ((mod.toggle.Value == "None") ? "Disabled" : mod.toggle.Value); }); string text = "Press this key to switch Performance on or off without opening Settings. Click to choose another key."; Tip(state, ((TMP_Text)val5).rectTransform, text); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)key).rectTransform).parent).TryCast<RectTransform>(), text); state.DefaultHint = "Changes apply right away. Hover over a setting to learn what it does."; } RectTransform val6 = Rect("Help", transform, 0.04f, 0.96f, 0.105f, 0.2f); Image obj2 = ((Component)val6).gameObject.AddComponent<Image>(); ((Graphic)obj2).color = new Color(1f, 1f, 1f, 0.035f); ((Graphic)obj2).raycastTarget = false; state.Help = Label(state, (Transform)(object)val6, state.DefaultHint, 0.025f, 0.975f, 0.07f, 0.93f, 16f); ((Graphic)state.Help).color = new Color(0.78f, 0.81f, 0.84f); state.Status = Label(state, transform, "Changes apply now. Save to keep them after restarting.", 0.04f, 0.96f, 0.065f, 0.1f, 13f); TextMeshProUGUI val7 = Button(state, transform, "Reset defaults", 0.04f, 0.49f, 0f, 0.06f, delegate { mod.ResetDefaults(); ((TMP_Text)state.Status).text = "Defaults applied. Save to keep them."; Refresh(state); }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val7).rectTransform).parent).TryCast<RectTransform>(), "Resets this mod to its defaults. Graphics tuning is turned off. Your saved preferences change only when you click Save."); TextMeshProUGUI val8 = Button(state, transform, "Save settings", 0.51f, 0.96f, 0f, 0.06f, delegate { try { mod.SaveSettings(); ((TMP_Text)state.Status).text = "Settings saved."; } catch (Exception ex) { ((TMP_Text)state.Status).text = "Could not save settings. Check the MelonLoader log."; mod.Log("Preference save failed: " + ex); } }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val8).rectTransform).parent).TryCast<RectTransform>(), "Keeps your current Performance settings for the next time you start the game."); Refresh(state); } private static void Row(State state, string title, float y, string hint) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Rect("SettingRow", state.Panel.transform, 0.04f, 0.96f, y, y + 0.075f); ((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(1f, 1f, 1f, 0.025f); Tip(state, val, hint); TextMeshProUGUI val2 = Label(state, state.Panel.transform, title, 0.06f, 0.53f, y, y + 0.075f, 20f); Tip(state, ((TMP_Text)val2).rectTransform, hint); } private static void BooleanRow(State state, string title, float y, Func<bool> read, Action<bool> write, string hint) { Row(state, title, y, hint); TextMeshProUGUI value = Button(state, state.Panel.transform, "", 0.65f, 0.94f, y + 0.007f, y + 0.068f, delegate { write(!read()); Mod.Instance.SettingsChanged(); Refresh(state); }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)value).rectTransform).parent).TryCast<RectTransform>(), hint); state.Refreshers.Add(delegate { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)value).text = (read() ? "On" : "Off"); ((Graphic)value).color = (read() ? new Color(0.65f, 0.86f, 0.89f) : new Color(0.72f, 0.74f, 0.77f)); }); } private static void NumberRow(State state, string title, float y, Func<float> read, Action<float> write, float step, string unit, string hint) { Row(state, title, y, hint); TextMeshProUGUI value = Label(state, state.Panel.transform, "", 0.64f, 0.86f, y, y + 0.075f, 19f); ((TMP_Text)value).alignment = (TextAlignmentOptions)514; TextMeshProUGUI val = Button(state, state.Panel.transform, "−", 0.56f, 0.64f, y + 0.007f, y + 0.068f, delegate { Change(-1f); }); TextMeshProUGUI val2 = Button(state, state.Panel.transform, "+", 0.86f, 0.94f, y + 0.007f, y + 0.068f, delegate { Change(1f); }); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val).rectTransform).parent).TryCast<RectTransform>(), hint); Tip(state, ((Il2CppObjectBase)((Transform)((TMP_Text)val2).rectTransform).parent).TryCast<RectTransform>(), hint); Tip(state, ((TMP_Text)value).rectTransform, hint); state.Refreshers.Add(delegate { ((TMP_Text)value).text = $"{read():F0}{((unit == "%" || unit == "°") ? "" : " ")}{unit}"; }); void Change(float direction) { write(read() + direction * step); Mod.Instance.SettingsChanged(); Refresh(state); } } private static void Tip(State state, RectTransform? rect, string text) { if ((Object)(object)rect == (Object)null) { return; } Graphic component = ((Component)rect).GetComponent<Graphic>(); if ((Object)(object)component != (Object)null) { component.raycastTarget = true; } EventTrigger trigger = ((Component)rect).gameObject.AddComponent<EventTrigger>(); Bind((EventTriggerType)0, delegate { state.Hovered = rect; state.Hint = text; state.HoverStart = Time.unscaledTime; }); Bind((EventTriggerType)1, delegate { if ((Object)(object)state.Hovered == (Object)(object)rect) { state.Hovered = null; } }); void Bind(EventTriggerType type, Action action) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown Entry val = new Entry { eventID = type }; ((UnityEvent<BaseEventData>)(object)val.callback).AddListener(UnityAction<BaseEventData>.op_Implicit((Action<BaseEventData>)delegate { action(); })); trigger.triggers.Add(val); } } private static void FitTabs(State state) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)state.Tab == (Object)null || (Object)(object)state.TabParent == (Object)null || state.OriginalTabs.Count == 0) { return; } RectTransform[] array = (from val3 in state.OriginalTabs.Select((TabRect saved) => saved.Rect).Append(((Component)state.Tab).GetComponent<RectTransform>()) where (Object)(object)val3 != (Object)null select val3).ToArray(); float left = state.Left; Rect rect = state.TabParent.rect; float num = Math.Max(left, ((Rect)(ref rect)).xMin + 4f); float right = state.Right; rect = state.TabParent.rect; float num2 = Math.Min(right, ((Rect)(ref rect)).xMax - 4f); if (num2 - num < 100f) { rect = state.TabParent.rect; num = ((Rect)(ref rect)).xMin + 4f; rect = state.TabParent.rect; num2 = ((Rect)(ref rect)).xMax - 4f; } if (num2 - num < 100f) { return; } float gap = 4f; float num3 = MenuLayout.TabWidth(num, num2, array.Length, gap); Vector2 val2 = default(Vector2); for (int num4 = 0; num4 < array.Length; num4++) { RectTransform val = array[num4]; float y = ((Transform)val).localPosition.y; rect = val.rect; float height = ((Rect)(ref rect)).height; ((Vector2)(ref val2))..ctor(0.5f, 0.5f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0.5f, 0.5f); val.sizeDelta = new Vector2(num3, height); float num5 = MenuLayout.TabCenter(num, num3, num4, gap); rect = state.TabParent.rect; float num6 = num5 - ((Rect)(ref rect)).center.x; rect = state.TabParent.rect; val.anchoredPosition = new Vector2(num6, y - ((Rect)(ref rect)).center.y); TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).enableAutoSizing = true; ((TMP_Text)componentInChildren).fontSizeMin = 10f; ((TMP_Text)componentInChildren).fontSizeMax = 22f; RectTransform rectTransform = ((TMP_Text)componentInChildren).rectTransform; if ((Object)(object)rectTransform != (Object)(object)val) { rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(5f, 2f); rectTransform.offsetMax = new Vector2(-5f, -2f); } } } } private static void RestoreTabs(State state) { foreach (TabRect originalTab in state.OriginalTabs) { originalTab.Restore(); } if ((Object)(object)state.Layout != (Object)null) { state.Layout.enabled = state.LayoutEnabled; } } private static RectTransform Rect(string name, Transform parent, float left, float right, float bottom, float top) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = new GameObject(name).AddComponent<RectTransform>(); ((Transform)obj).SetParent(parent, false); obj.anchorMin = new Vector2(left, bottom); obj.anchorMax = new Vector2(right, top); Vector2 offsetMin = (obj.offsetMax = Vector2.zero); obj.offsetMin = offsetMin; return obj; } private static TextMeshProUGUI Label(State state, Transform parent, string text, float left, float right, float bottom, float top, float size) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = ((Component)Rect("Label", parent, left, right, bottom, top)).gameObject.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = state.Font; ((TMP_Text)obj).text = text; ((Graphic)obj).color = Color.white; ((TMP_Text)obj).fontSize = size; ((TMP_Text)obj).enableAutoSizing = true; ((TMP_Text)obj).fontSizeMin = 10f; ((TMP_Text)obj).fontSizeMax = size; ((TMP_Text)obj).alignment = (TextAlignmentOptions)4097; ((Graphic)obj).raycastTarget = false; return obj; } private static TextMeshProUGUI Button(State state, Transform parent, string text, float left, float right, float bottom, float top, Action action) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Rect("Control", parent, left, right, bottom, top); Image val2 = ((Component)val).gameObject.AddComponent<Image>(); ((Graphic)val2).color = new Color(0.18f, 0.19f, 0.21f, 0.95f); Button obj = ((Component)val).gameObject.AddComponent<Button>(); ((Selectable)obj).targetGraphic = (Graphic)(object)val2; ((UnityEvent)obj.onClick).AddListener(UnityAction.op_Implicit((Action)delegate { try { action(); } catch (Exception ex) { Mod.Instance.Log("Settings control failed: " + ex); } })); TextMeshProUGUI obj2 = Label(state, (Transform)(object)val, text, 0.04f, 0.96f, 0.02f, 0.98f, 20f); ((TMP_Text)obj2).alignment = (TextAlignmentOptions)514; return obj2; } private static void Refresh(State state) { foreach (Action refresher in state.Refreshers) { refresher(); } if ((Object)(object)state.Help != (Object)null) { ((TMP_Text)state.Help).text = (((Object)(object)state.Hovered != (Object)null && Time.unscaledTime - state.HoverStart >= 0.35f) ? state.Hint : state.DefaultHint); } } internal static void Cleanup() { foreach (State state in states.Values) { RestoreTabs(state); if ((Object)(object)state.Screen != (Object)null && state.Screen.Categories != null) { SettingsCategory[] array = ((IEnumerable<SettingsCategory>)state.Screen.Categories).Where((SettingsCategory category) => (Object)(object)category.Panel != (Object)(object)state.Panel).ToArray(); state.Screen.Categories = new Il2CppReferenceArray<SettingsCategory>(array); if (array.Length != 0) { state.Screen.ShowCategory(0); } } if ((Object)(object)state.Tab != (Object)null) { Object.Destroy((Object)(object)((Component)state.Tab).gameObject); } if ((Object)(object)state.Panel != (Object)null) { Object.Destroy((Object)(object)state.Panel); } } states.Clear(); } } internal static class RenderPolicy { public static float Scale(float value) { if (!float.IsFinite(value)) { return 1f; } return Math.Clamp(value, 0.5f, 1f); } public static float ShadowDistance(float value) { if (!float.IsFinite(value)) { return 75f; } return Math.Clamp(value, 0f, 300f); } public static float Lod(float value) { if (!float.IsFinite(value)) { return 1f; } return Math.Clamp(value, 0.25f, 1f); } public static float Distance(float value) { if (!float.IsFinite(value)) { return 200f; } return Math.Clamp(value, 50f, 1000f); } public static float Padding(float value) { if (!float.IsFinite(value)) { return 0f; } return Math.Clamp(value, 0f, 30f); } public static float CullDistance(float original, float distance) { if (!(original > 0f)) { return Distance(distance); } return Math.Min(original, Distance(distance)); } public static float PaddedFov(float fov, float padding) { return Math.Clamp(fov + Padding(padding), 1f, 170f); } public static float Restore(float current, float applied, float original) { if (current != applied) { return current; } return original; } public static float Percentile95(float[] samples, int count) { if (count == 0) { return 0f; } float[] array = new float[count]; Array.Copy(samples, array, count); Array.Sort(array); return array[(int)Math.Ceiling((double)count * 0.95) - 1]; } } internal sealed class OwnedFloat { private bool owned; private float original; private float applied; public float Apply(float current, float desired) { if (!owned || current != applied) { original = current; } applied = Math.Min(original, desired); owned = true; return applied; } public float Restore(float current) { float result = (owned ? RenderPolicy.Restore(current, applied, original) : current); owned = false; return result; } } }