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 SoloGFX v1.3.0
SoloGFX.dll
Decompiled 5 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SoloShared; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using UnityEngine.Rendering.PostProcessing; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("HappyTheLegend")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 HappyTheLegend")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+29b14a846b851524562a4c86679436adc8a84165")] [assembly: AssemblyProduct("SoloGFX")] [assembly: AssemblyTitle("SoloGFX")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SoloShared { internal static class Loc { private static Dictionary<string, string> _table = new Dictionary<string, string>(StringComparer.Ordinal); private static string _folder; private static string _mod = "Solo"; private static string _loaded = ""; private static float _nextCheck; private static Action<string> _log = delegate { }; private static Action<string> _warn = delegate { }; private static readonly SortedSet<string> _seen = new SortedSet<string>(StringComparer.Ordinal); private static bool _collect; internal static string Language { get { if (_loaded.Length != 0) { return _loaded; } return "en"; } } internal static void Init(string modName, string dllPath, Action<string> log, Action<string> warn, bool collectStrings = false) { _mod = modName ?? "Solo"; _log = log ?? ((Action<string>)delegate { }); _warn = warn ?? ((Action<string>)delegate { }); _collect = collectStrings; try { _folder = Path.GetDirectoryName(dllPath); } catch { _folder = null; } Reload(CurrentLanguage()); } internal static string T(string english) { if (string.IsNullOrEmpty(english)) { return english; } if (_collect) { lock (_seen) { _seen.Add(english); } } if (!_table.TryGetValue(english, out var value) || value.Length <= 0) { return english; } return value; } internal static string F(string english, params object[] args) { string format = T(english); try { return string.Format(format, args); } catch { try { return string.Format(english, args); } catch { return english; } } } internal static void Tick(float unscaledTime) { if (!(unscaledTime < _nextCheck)) { _nextCheck = unscaledTime + 2f; string text = CurrentLanguage(); if (text != _loaded) { Reload(text); } } } private static string CurrentLanguage() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { Locale selectedLocale = LocalizationSettings.SelectedLocale; object obj; if (!((Object)(object)selectedLocale != (Object)null)) { obj = ""; } else { LocaleIdentifier identifier = selectedLocale.Identifier; obj = ((LocaleIdentifier)(ref identifier)).Code; } string text = (string)obj; return string.IsNullOrEmpty(text) ? "en" : text; } catch { return "en"; } } private static void Reload(string code) { _loaded = code ?? "en"; Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); if (!string.IsNullOrEmpty(_folder) && !_loaded.StartsWith("en", StringComparison.OrdinalIgnoreCase)) { string text = Path.Combine(_folder, "lang"); foreach (string item in Candidates(_loaded, text)) { string path = Path.Combine(text, item + ".txt"); if (File.Exists(path)) { int num = Read(path, dictionary); _log($"[{_mod}] Language {item}: {num} line(s) from {Path.GetFileName(path)}."); break; } } } _table = dictionary; if (dictionary.Count > 0) { _log("[" + _mod + "] Following the game's language: " + _loaded + "."); } if (dictionary.Count == 0 && !_loaded.StartsWith("en", StringComparison.OrdinalIgnoreCase)) { _log("[" + _mod + "] No translation file for '" + _loaded + "' — showing English. Add lang/" + _loaded + ".txt beside the mod to change that."); } } private static IEnumerable<string> Candidates(string code, string dir) { yield return code; string language = code; int num = code.IndexOf('-'); if (num > 0) { language = code.Substring(0, num); yield return language; } string[] array; try { array = (Directory.Exists(dir) ? Directory.GetFiles(dir, "*.txt") : new string[0]); } catch { yield break; } string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(array2[i]); if (fileNameWithoutExtension.StartsWith(language + "-", StringComparison.OrdinalIgnoreCase)) { yield return fileNameWithoutExtension; } } } private static int Read(string path, Dictionary<string, string> into) { int num = 0; try { string text = null; string[] array = File.ReadAllLines(path, Encoding.UTF8); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2[0] == '#') { continue; } if (text2[0] == '=') { text = Unescape(text2.Substring(1).Trim()); } else if (text2[0] == '>' && text != null) { string text3 = Unescape(text2.Substring(1).Trim()); if (text3.Length > 0) { into[text] = text3; num++; } text = null; } } } catch (Exception ex) { _warn("[" + _mod + "] Couldn't read " + Path.GetFileName(path) + ": " + ex.Message); } return num; } private static string Unescape(string s) { return s.Replace("\\n", "\n"); } private static string Escape(string s) { return s.Replace("\n", "\\n"); } internal static void DumpSeen() { if (!_collect || string.IsNullOrEmpty(_folder)) { return; } try { string text = Path.Combine(_folder, "lang"); Directory.CreateDirectory(text); string path = Path.Combine(text, "_english.txt"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Every line " + _mod + " has shown this session."); stringBuilder.AppendLine("# Copy this file to <language code>.txt and fill in the > lines."); stringBuilder.AppendLine("# Leave a > line empty to keep the English."); stringBuilder.AppendLine(); lock (_seen) { foreach (string item in _seen) { stringBuilder.Append("= ").AppendLine(Escape(item)); stringBuilder.AppendLine("> "); } File.WriteAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); _log($"[{_mod}] Wrote {_seen.Count} line(s) to lang/_english.txt."); } } catch (Exception ex) { _warn("[" + _mod + "] Couldn't write the English list: " + ex.Message); } } } } namespace SoloGFX { internal static class GfxApply { private const float ReapplyInterval = 2f; private static bool _postFxInjected; private static PostProcessing _pp; private static bool _pathLogged; private static bool _selfChecked; private static float _reapplyTimer; private static int _traceBudget = 60; private static readonly HashSet<string> _reported = new HashSet<string>(); private static void Trace(string msg) { if (_traceBudget > 0) { _traceBudget--; Plugin.Log.LogInfo((object)("[SoloGFX] " + msg)); } } private static void Fail(string where, Exception e) { if (_reported.Add(where)) { Plugin.Log.LogError((object)$"[SoloGFX] {where} threw {e.GetType().Name}: {e.Message}\n{e}"); } } private static void SelfCheck() { if (!_selfChecked) { _selfChecked = true; bool flag = Plugin.Instance == null; bool flag2 = (Object)(object)Plugin.Instance == (Object)null; Plugin.Log.LogInfo((object)($"[SoloGFX] driver alive. Ready={Plugin.Ready} plugin ref-null={flag} " + string.Format("unity-null={0}{1}", flag2, (!flag && flag2) ? " <- MonoBehaviour was destroyed (expected)" : ""))); } } public static void Pump(PostProcessing pp) { try { SelfCheck(); if (!Plugin.Ready) { return; } if ((Object)(object)pp != (Object)null) { _pp = pp; } if (!_postFxInjected) { try { EnsurePostFx(pp); } catch (Exception e) { Fail("EnsurePostFx", e); _postFxInjected = true; } } _reapplyTimer -= Time.unscaledDeltaTime; if (_reapplyTimer > 0f) { return; } _reapplyTimer = 2f; try { ApplyRenderResolution(); } catch (Exception e2) { Fail("ApplyRenderResolution", e2); } try { ApplyQualityAndLighting(GraphicsManager.instance); } catch (Exception e3) { Fail("ApplyQualityAndLighting", e3); } } catch (Exception e4) { Fail("Pump", e4); } } public static void PumpNow() { if (Plugin.Ready) { try { ApplyRenderResolution(); } catch (Exception e) { Fail("ApplyRenderResolution", e); } try { ApplyQualityAndLighting(GraphicsManager.instance); } catch (Exception e2) { Fail("ApplyQualityAndLighting", e2); } _reapplyTimer = 2f; } } public static void RefreshPostFx() { _postFxInjected = false; if (!Plugin.Ready || (Object)(object)_pp == (Object)null) { return; } try { EnsurePostFx(_pp); } catch (Exception e) { Fail("RefreshPostFx", e); _postFxInjected = true; } } public static void ApplyRenderResolution() { if (!Plugin.RenderEnabled.Value) { return; } RenderTextureMain instance = RenderTextureMain.instance; if ((Object)(object)instance == (Object)null) { Trace("RenderTextureMain.instance is null — cannot set resolution yet."); return; } float num; float num2; if (Plugin.RenderMatchScreen.Value) { num = Screen.width; num2 = Screen.height; } else { float num3 = Mathf.Max(1f, Plugin.RenderScale.Value); num = instance.textureWidthLarge * num3; num2 = instance.textureHeightLarge * num3; } float num4 = Mathf.Clamp(Plugin.Supersampling.Value, 1f, 2f); float num5 = Mathf.Clamp(num * num4, 320f, 7680f); float num6 = Mathf.Clamp(num2 * num4, 240f, 4320f); if ((int)instance.textureWidthOriginal != (int)num5 || (int)instance.textureHeightOriginal != (int)num6) { Trace($"Render buffer {(int)instance.textureWidthOriginal}x{(int)instance.textureHeightOriginal} -> " + $"{(int)num5}x{(int)num6} (screen {Screen.width}x{Screen.height}, ss {num4:0.##}, " + $"vanilla S={(int)instance.textureWidthSmall}x{(int)instance.textureHeightSmall} " + $"M={(int)instance.textureWidthMedium}x{(int)instance.textureHeightMedium} " + $"L={(int)instance.textureWidthLarge}x{(int)instance.textureHeightLarge})"); instance.textureWidthOriginal = num5; instance.textureHeightOriginal = num6; instance.ResetResolution(); } } public static void ApplyQualityAndLighting(GraphicsManager gm) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if (Plugin.LightingEnabled.Value) { if ((Object)(object)gm != (Object)null) { gm.lightDistance = Plugin.LightDistance.Value; gm.shadowDistance = Plugin.ShadowDistance.Value; if ((Object)(object)LightManager.instance != (Object)null) { LightManager.instance.UpdateInstant(); } } QualitySettings.shadowDistance = Plugin.ShadowDistance.Value; QualitySettings.shadowResolution = Plugin.ShadowRes.Value; QualitySettings.shadowCascades = Plugin.ShadowCascades.Value; QualitySettings.pixelLightCount = Plugin.PixelLightCount.Value; } if (Plugin.QualityEnabled.Value) { QualitySettings.anisotropicFiltering = Plugin.Anisotropic.Value; QualitySettings.globalTextureMipmapLimit = Plugin.TextureMipLimit.Value; QualitySettings.lodBias = Plugin.LodBias.Value; QualitySettings.antiAliasing = Plugin.AntiAliasing.Value; } Trace($"Quality applied: gm={(Object)(object)gm != (Object)null} shadowDist={QualitySettings.shadowDistance} " + $"lightDist={(((Object)(object)gm != (Object)null) ? gm.lightDistance : (-1f))} aniso={QualitySettings.anisotropicFiltering} " + $"lod={QualitySettings.lodBias} msaa={QualitySettings.antiAliasing} " + $"pixelLights={QualitySettings.pixelLightCount}"); } public static void EnsurePostFx(PostProcessing pp) { //IL_00a1: 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) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pp == (Object)null || (Object)(object)pp.volume == (Object)null) { return; } PostProcessProfile profile = pp.volume.profile; if ((Object)(object)profile == (Object)null) { return; } Trace($"post-process profile '{((Object)profile).name}' has {profile.settings.Count} effects."); bool value = Plugin.AoEnabled.Value; AmbientOcclusion val = default(AmbientOcclusion); if (!profile.TryGetSettings<AmbientOcclusion>(ref val) && value) { val = profile.AddSettings<AmbientOcclusion>(); } if ((Object)(object)val != (Object)null) { ((PostProcessEffectSettings)val).active = value; ((ParameterOverride<bool>)(object)((PostProcessEffectSettings)val).enabled).Override(value); if (value) { ((ParameterOverride<AmbientOcclusionMode>)(object)val.mode).Override(Plugin.AoMode.Value); ((ParameterOverride<float>)(object)val.intensity).Override(Plugin.AoIntensity.Value); ((ParameterOverride<float>)(object)val.radius).Override(Plugin.AoRadius.Value); ((ParameterOverride<AmbientOcclusionQuality>)(object)val.quality).Override(Plugin.AoQuality.Value); ((ParameterOverride<Color>)(object)val.color).Override(Color.black); } Trace(value ? $"SSAO ON (mode={Plugin.AoMode.Value}, intensity={Plugin.AoIntensity.Value}, quality={Plugin.AoQuality.Value})." : "SSAO OFF."); } bool value2 = Plugin.SsrEnabled.Value; ScreenSpaceReflections val2 = default(ScreenSpaceReflections); if (!profile.TryGetSettings<ScreenSpaceReflections>(ref val2) && value2) { val2 = profile.AddSettings<ScreenSpaceReflections>(); } if ((Object)(object)val2 != (Object)null) { ((PostProcessEffectSettings)val2).active = value2; ((ParameterOverride<bool>)(object)((PostProcessEffectSettings)val2).enabled).Override(value2); if (value2) { ((ParameterOverride<ScreenSpaceReflectionPreset>)(object)val2.preset).Override(Plugin.SsrPreset.Value); WarnIfSsrUnsupported(); } Trace(value2 ? $"SSR ON (preset={Plugin.SsrPreset.Value})." : "SSR OFF."); } _postFxInjected = true; } private static void WarnIfSsrUnsupported() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (_pathLogged) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { _pathLogged = true; RenderingPath actualRenderingPath = main.actualRenderingPath; if ((int)actualRenderingPath == 3) { Trace("Camera is Deferred — SSR will render."); } else { Plugin.Log.LogWarning((object)($"[SoloGFX] Camera path is {actualRenderingPath}, not DeferredShading. PPv2 SSR will NOT render on " + "this path — SSAO still works. Set Reflections/Enabled=false to silence this.")); } } } } [HarmonyPatch(typeof(PostProcessing), "Update")] internal static class PostProcessingUpdatePatch { private static void Postfix(PostProcessing __instance) { GfxApply.Pump(__instance); } } [HarmonyPatch(typeof(GraphicsManager), "UpdateAll")] internal static class GraphicsManagerUpdateAllPatch { private static void Postfix() { GfxApply.PumpNow(); } } [HarmonyPatch(typeof(GraphicsManager), "UpdateRenderSize")] internal static class GraphicsManagerUpdateRenderSizePatch { private static void Postfix() { GfxApply.PumpNow(); } } [BepInPlugin("com.solo.repo.sologfx", "SoloGFX", "1.3.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.solo.repo.sologfx"; public const string Name = "SoloGFX"; public const string Version = "1.3.0"; internal static ManualLogSource Log; internal static ConfigFile Cfg; internal static bool Ready; internal static Plugin Instance; internal static ConfigEntry<bool> ShowInVideoMenu; internal static ConfigEntry<bool> RenderEnabled; internal static ConfigEntry<bool> RenderMatchScreen; internal static ConfigEntry<float> RenderScale; internal static ConfigEntry<float> Supersampling; internal static ConfigEntry<bool> AoEnabled; internal static ConfigEntry<float> AoIntensity; internal static ConfigEntry<float> AoRadius; internal static ConfigEntry<AmbientOcclusionMode> AoMode; internal static ConfigEntry<AmbientOcclusionQuality> AoQuality; internal static ConfigEntry<bool> SsrEnabled; internal static ConfigEntry<ScreenSpaceReflectionPreset> SsrPreset; internal static ConfigEntry<bool> LightingEnabled; internal static ConfigEntry<float> LightDistance; internal static ConfigEntry<float> ShadowDistance; internal static ConfigEntry<ShadowResolution> ShadowRes; internal static ConfigEntry<int> ShadowCascades; internal static ConfigEntry<int> PixelLightCount; internal static ConfigEntry<bool> QualityEnabled; internal static ConfigEntry<AnisotropicFiltering> Anisotropic; internal static ConfigEntry<int> TextureMipLimit; internal static ConfigEntry<float> LodBias; internal static ConfigEntry<int> AntiAliasing; internal static ConfigEntry<bool> DumpTranslationList; private void Awake() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Expected O, but got Unknown //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Expected O, but got Unknown //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Expected O, but got Unknown //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Expected O, but got Unknown //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Expected O, but got Unknown //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; Cfg = ((BaseUnityPlugin)this).Config; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; ShowInVideoMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("0-Menu", "ShowInVideoMenu", true, "Add every setting below to the game's own Video settings page, so they can be changed while playing instead of by editing this file. The rows are copies of the game's own and write only to this file — nothing touches the game's settings, and Reset Settings on that page leaves them alone."); RenderEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1-Resolution", "Enabled", true, "Raise the internal render buffer. This is what removes the blocky/pixelated look."); RenderMatchScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("1-Resolution", "MatchScreenResolution", true, "Render at your monitor's native resolution. Best quality; overrides RenderScale."); RenderScale = ((BaseUnityPlugin)this).Config.Bind<float>("1-Resolution", "RenderScale", 2f, new ConfigDescription("Multiplier over vanilla's buffer when MatchScreenResolution is false.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 6f), Array.Empty<object>())); Supersampling = ((BaseUnityPlugin)this).Config.Bind<float>("1-Resolution", "Supersampling", 1f, new ConfigDescription("Render above the target and let the downscale anti-alias the image. 1 = off. 1.5 is a big sharpness win; 2 costs roughly 4x the pixels, so drop it if you lose frames.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 2f), Array.Empty<object>())); AoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2-AmbientOcclusion", "Enabled", true, "Soft contact shadows in corners and where objects meet. Biggest realism win available."); AoIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("2-AmbientOcclusion", "Intensity", 0.8f, new ConfigDescription("How dark the occlusion is.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 4f), Array.Empty<object>())); AoRadius = ((BaseUnityPlugin)this).Config.Bind<float>("2-AmbientOcclusion", "Radius", 0.35f, new ConfigDescription("How far the effect reaches, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>())); AoMode = ((BaseUnityPlugin)this).Config.Bind<AmbientOcclusionMode>("2-AmbientOcclusion", "Mode", (AmbientOcclusionMode)0, "ScalableAmbientObscurance works on any rendering path. MultiScaleVolumetricObscurance needs compute support."); AoQuality = ((BaseUnityPlugin)this).Config.Bind<AmbientOcclusionQuality>("2-AmbientOcclusion", "Quality", (AmbientOcclusionQuality)3, "Sample count. Lower this first if you lose frames."); SsrEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3-Reflections", "Enabled", true, "Screen-space reflections. NOTE: PPv2 SSR only works on the DEFERRED rendering path; if this game renders forward it will silently do nothing (the log will tell you which)."); SsrPreset = ((BaseUnityPlugin)this).Config.Bind<ScreenSpaceReflectionPreset>("3-Reflections", "Preset", (ScreenSpaceReflectionPreset)3, "Quality preset for reflections."); LightingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4-Lighting", "Enabled", true, "Lift the vanilla light/shadow distance caps."); LightDistance = ((BaseUnityPlugin)this).Config.Bind<float>("4-Lighting", "LightDistance", 80f, new ConfigDescription("Vanilla maxes out at 30. Higher = lights visible from further away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>())); ShadowDistance = ((BaseUnityPlugin)this).Config.Bind<float>("4-Lighting", "ShadowDistance", 80f, new ConfigDescription("Vanilla maxes out at 25.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())); ShadowRes = ((BaseUnityPlugin)this).Config.Bind<ShadowResolution>("4-Lighting", "ShadowResolution", (ShadowResolution)3, "Shadow map resolution."); ShadowCascades = ((BaseUnityPlugin)this).Config.Bind<int>("4-Lighting", "ShadowCascades", 4, new ConfigDescription("Directional shadow cascades. Must be 0, 2 or 4.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[3] { 0, 2, 4 }), Array.Empty<object>())); PixelLightCount = ((BaseUnityPlugin)this).Config.Bind<int>("4-Lighting", "PixelLightCount", 8, new ConfigDescription("Max per-pixel (real-time) lights. Higher = more lights lit properly.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 32), Array.Empty<object>())); QualityEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("5-Quality", "Enabled", true, "Texture filtering and level-of-detail improvements."); Anisotropic = ((BaseUnityPlugin)this).Config.Bind<AnisotropicFiltering>("5-Quality", "AnisotropicFiltering", (AnisotropicFiltering)2, "ForceEnable sharpens textures viewed at an angle (floors/walls). Nearly free performance-wise."); TextureMipLimit = ((BaseUnityPlugin)this).Config.Bind<int>("5-Quality", "TextureMipLimit", 0, new ConfigDescription("0 = full resolution textures. Higher values downscale them.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>())); LodBias = ((BaseUnityPlugin)this).Config.Bind<float>("5-Quality", "LodBias", 2.5f, new ConfigDescription("Higher = detailed models stay detailed further away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>())); AntiAliasing = ((BaseUnityPlugin)this).Config.Bind<int>("5-Quality", "MSAA", 2, new ConfigDescription("Multisample anti-aliasing. Must be 0, 2, 4 or 8. Was 4; dropped to 2 after a session ended in DXGI_ERROR_DEVICE_REMOVED with a matching LiveKernelEvent 0x141 (the display driver hung and Windows reset it). MSAA multiplies the cost of every render target on screen, so it is the first thing to give back when the GPU is what is falling over.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 0, 2, 4, 8 }), Array.Empty<object>())); try { ((BaseUnityPlugin)this).Config.Save(); } catch (Exception ex) { Log.LogWarning((object)("[SoloGFX] Couldn't write the config: " + ex.Message)); } Ready = true; DumpTranslationList = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "WriteTranslationList", false, "Write every line this mod shows to lang/_english.txt as you play, ready to be copied into a new language file. For translating; off otherwise."); Loc.Init("SoloGFX", ((BaseUnityPlugin)this).Info.Location, (Action<string>)Log.LogInfo, (Action<string>)Log.LogWarning, DumpTranslationList.Value); Harmony val = new Harmony("com.solo.repo.sologfx"); val.PatchAll(typeof(Plugin).Assembly); int num = 0; foreach (MethodBase patchedMethod in val.GetPatchedMethods()) { num++; Log.LogInfo((object)("[SoloGFX] patched: " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name)); } Log.LogInfo((object)string.Format("{0} v{1} loaded; Harmony applied {2} patches.", "SoloGFX", "1.3.0", num)); if (num == 0) { Log.LogError((object)"[SoloGFX] PatchAll applied ZERO patches — hooks will never fire!"); } } } internal static class SettingsRows { [HarmonyPatch(typeof(MenuPageSettingsPage), "Start")] internal static class GraphicsPagePatch { private static void Postfix(MenuPageSettingsPage __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if (!Plugin.Ready || (Object)(object)__instance == (Object)null || (int)__instance.settingType != 2 || !Plugin.ShowInVideoMenu.Value) { return; } try { ((MonoBehaviour)__instance).StartCoroutine(AddTo(__instance)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] Video page hook failed: " + ex.Message)); } } } [HarmonyPatch(typeof(MenuPageSettingsPage), "SaveSettings")] internal static class GraphicsPageSavePatch { private static void Postfix() { FlushIfDue(force: true); } } private const string Tag = "SoloGFX Row"; private const string Prefix = "GFX "; private static float _saveAt; private static readonly float[] SuperSteps = new float[5] { 1f, 1.25f, 1.5f, 1.75f, 2f }; private static readonly int[] MsaaSteps = new int[4] { 0, 2, 4, 8 }; private static readonly int[] CascadeSteps = new int[3] { 0, 2, 4 }; private static readonly ShadowResolution[] ShadowResSteps; private static readonly AnisotropicFiltering[] AnisoSteps; private static readonly AmbientOcclusionQuality[] AoQualitySteps; private static readonly ScreenSpaceReflectionPreset[] SsrPresetSteps; internal static void MarkDirty() { _saveAt = Time.unscaledTime + 0.75f; } internal static void FlushIfDue(bool force = false) { if (_saveAt <= 0f || (!force && Time.unscaledTime < _saveAt)) { return; } _saveAt = 0f; try { if (Plugin.Cfg != null) { Plugin.Cfg.Save(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] Couldn't save the config: " + ex.Message)); } } private unsafe static IEnumerator AddTo(MenuPageSettingsPage page) { yield return null; Loc.Tick(Time.unscaledTime); if ((Object)(object)page == (Object)null || ((Component)page).GetComponentsInChildren<Transform>(true).Any((Transform t) => (Object)(object)t != (Object)null && ((Object)t).name == "SoloGFX Row")) { yield break; } MenuSlider[] componentsInChildren = ((Component)page).GetComponentsInChildren<MenuSlider>(true); MenuSlider sliderTemplate = ((IEnumerable<MenuSlider>)componentsInChildren).FirstOrDefault((Func<MenuSlider, bool>)((MenuSlider s) => (Object)(object)s != (Object)null && !s.hasCustomOptions)) ?? componentsInChildren.FirstOrDefault(); MenuTwoOptions toggleTemplate = ((Component)page).GetComponentsInChildren<MenuTwoOptions>(true).FirstOrDefault(); if ((Object)(object)sliderTemplate == (Object)null || (Object)(object)toggleTemplate == (Object)null) { Plugin.Log.LogWarning((object)($"[SoloGFX] Video page has no row to copy (slider={(Object)(object)sliderTemplate != (Object)null}, " + $"toggle={(Object)(object)toggleTemplate != (Object)null}) — leaving it alone.")); yield break; } List<Transform> list = (from t in ((Component)page).GetComponentsInChildren<Transform>(true) where (Object)(object)t != (Object)null && ((Object)(object)((Component)t).GetComponent<MenuSlider>() != (Object)null || (Object)(object)((Component)t).GetComponent<MenuTwoOptions>() != (Object)null) orderby t.localPosition.y descending select t).ToList(); Transform val = list[list.Count - 1]; Transform parent = val.parent; float gap = ((list.Count > 1) ? Mathf.Abs(list[0].localPosition.y - list[1].localPosition.y) : 34f); if (gap < 1f) { gap = 34f; } float y = val.localPosition.y; int added = 0; Action<string, Func<bool>, Action<bool>> action = delegate(string name, Func<bool> read, Action<bool> write) { y -= gap; if (Toggle(toggleTemplate, parent, y, name, read, write)) { added++; } }; Action<string, string[], Func<int>, Action<int>> action2 = delegate(string name, string[] labels, Func<int> read, Action<int> write) { y -= gap; if (Slider(sliderTemplate, parent, y, name, labels, read, write)) { added++; } }; Action<string, bool> action3 = delegate(string text, bool major) { y -= (major ? (gap * 1.5f) : gap); Header((Component)(object)toggleTemplate, TitleOf((Component)(object)toggleTemplate), parent, y, text, major, "SoloGFX Row"); }; action3("SOLOGFX", arg2: true); action3("Resolution", arg2: false); action("Resolution Fix", () => Plugin.RenderEnabled.Value, delegate(bool v) { Plugin.RenderEnabled.Value = v; Applied(); }); action("Native Resolution", () => Plugin.RenderMatchScreen.Value, delegate(bool v) { Plugin.RenderMatchScreen.Value = v; Applied(); }); action2("Supersampling", SuperSteps.Select((float f) => (!(f <= 1f)) ? (f.ToString("0.##") + "x") : "OFF").ToArray(), () => NearestIndex(SuperSteps, Plugin.Supersampling.Value), delegate(int i) { Plugin.Supersampling.Value = SuperSteps[i]; Applied(); }); action2("Render Scale", Steps(1f, 0.5f, 11, "x"), () => Mathf.RoundToInt((Plugin.RenderScale.Value - 1f) / 0.5f), delegate(int i) { Plugin.RenderScale.Value = 1f + (float)i * 0.5f; Applied(); }); action3("Ambient Occlusion", arg2: false); action("Ambient Occlusion", () => Plugin.AoEnabled.Value, delegate(bool v) { Plugin.AoEnabled.Value = v; AppliedPostFx(); }); action2("AO Strength", Steps(0f, 0.25f, 17, ""), () => Mathf.RoundToInt(Plugin.AoIntensity.Value / 0.25f), delegate(int i) { Plugin.AoIntensity.Value = (float)i * 0.25f; AppliedPostFx(); }); action2("AO Radius", Steps(0.05f, 0.05f, 40, "m"), () => Mathf.RoundToInt(Plugin.AoRadius.Value / 0.05f) - 1, delegate(int i) { Plugin.AoRadius.Value = (float)(i + 1) * 0.05f; AppliedPostFx(); }); action2("AO Quality", AoQualitySteps.Select((AmbientOcclusionQuality q) => Readable(((object)(*(AmbientOcclusionQuality*)(&q))/*cast due to .constrained prefix*/).ToString())).ToArray(), () => IndexOf(AoQualitySteps, Plugin.AoQuality.Value, 3), delegate(int i) { Plugin.AoQuality.Value = AoQualitySteps[i]; AppliedPostFx(); }); action3("Reflections", arg2: false); action("Reflections", () => Plugin.SsrEnabled.Value, delegate(bool v) { Plugin.SsrEnabled.Value = v; AppliedPostFx(); }); action2("Reflection Quality", SsrPresetSteps.Select((ScreenSpaceReflectionPreset p) => Readable(((object)(*(ScreenSpaceReflectionPreset*)(&p))/*cast due to .constrained prefix*/).ToString())).ToArray(), () => IndexOf(SsrPresetSteps, Plugin.SsrPreset.Value, 3), delegate(int i) { Plugin.SsrPreset.Value = SsrPresetSteps[i]; AppliedPostFx(); }); action3("Lighting", arg2: false); action("Lighting Boost", () => Plugin.LightingEnabled.Value, delegate(bool v) { Plugin.LightingEnabled.Value = v; Applied(); }); action2("Light Distance", Steps(10f, 10f, 20, "m"), () => Mathf.RoundToInt(Plugin.LightDistance.Value / 10f) - 1, delegate(int i) { Plugin.LightDistance.Value = (float)(i + 1) * 10f; Applied(); }); action2("Shadow Distance", Steps(10f, 10f, 30, "m"), () => Mathf.RoundToInt(Plugin.ShadowDistance.Value / 10f) - 1, delegate(int i) { Plugin.ShadowDistance.Value = (float)(i + 1) * 10f; Applied(); }); action2("Shadow Resolution", ShadowResSteps.Select((ShadowResolution r) => Readable(((object)(*(ShadowResolution*)(&r))/*cast due to .constrained prefix*/).ToString())).ToArray(), () => IndexOf(ShadowResSteps, Plugin.ShadowRes.Value, 3), delegate(int i) { Plugin.ShadowRes.Value = ShadowResSteps[i]; Applied(); }); action2("Shadow Cascades", CascadeSteps.Select((int c) => (c != 0) ? c.ToString() : "OFF").ToArray(), () => IndexOf(CascadeSteps, Plugin.ShadowCascades.Value, 2), delegate(int i) { Plugin.ShadowCascades.Value = CascadeSteps[i]; Applied(); }); action2("Pixel Lights", Steps(1f, 1f, 32, ""), () => Plugin.PixelLightCount.Value - 1, delegate(int i) { Plugin.PixelLightCount.Value = i + 1; Applied(); }); action3("Quality", arg2: false); action("Quality Boost", () => Plugin.QualityEnabled.Value, delegate(bool v) { Plugin.QualityEnabled.Value = v; Applied(); }); action2("Anti-Aliasing", new string[4] { "OFF", "MSAA 2x", "MSAA 4x", "MSAA 8x" }, () => IndexOf(MsaaSteps, Plugin.AntiAliasing.Value, 1), delegate(int i) { Plugin.AntiAliasing.Value = MsaaSteps[i]; Applied(); }); action2("Anisotropic Filter", new string[3] { "OFF", "ON", "FORCED" }, () => IndexOf(AnisoSteps, Plugin.Anisotropic.Value, 2), delegate(int i) { Plugin.Anisotropic.Value = AnisoSteps[i]; Applied(); }); action2("Texture Detail", new string[4] { "FULL", "HIGH", "MEDIUM", "LOW" }, () => Mathf.Clamp(Plugin.TextureMipLimit.Value, 0, 3), delegate(int i) { Plugin.TextureMipLimit.Value = i; Applied(); }); action2("Model Detail", Steps(0.5f, 0.5f, 16, "x"), () => Mathf.RoundToInt(Plugin.LodBias.Value / 0.5f) - 1, delegate(int i) { Plugin.LodBias.Value = (float)(i + 1) * 0.5f; Applied(); }); MenuScrollBox[] componentsInChildren2 = ((Component)page).GetComponentsInChildren<MenuScrollBox>(true); foreach (MenuScrollBox val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { try { val2.RecalculateScrollHeight(); } catch { } } } Plugin.Log.LogInfo((object)$"[SoloGFX] Added {added} row(s) to the game's Video settings."); } private static void Applied() { MarkDirty(); GfxApply.PumpNow(); } private static void AppliedPostFx() { MarkDirty(); GfxApply.RefreshPostFx(); } private static GameObject CloneDormant(Component template, Transform parent, float y) { //IL_003e: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = template.gameObject; bool activeSelf = gameObject.activeSelf; gameObject.SetActive(false); GameObject val; try { val = Object.Instantiate<GameObject>(gameObject, parent); } finally { gameObject.SetActive(activeSelf); } ((Object)val).name = "SoloGFX Row"; val.transform.localPosition = new Vector3(template.transform.localPosition.x, y, template.transform.localPosition.z); val.transform.localScale = template.transform.localScale; val.transform.localRotation = template.transform.localRotation; MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && ((object)val2).GetType().Name.IndexOf("Localize", StringComparison.OrdinalIgnoreCase) >= 0) { Object.DestroyImmediate((Object)(object)val2); } } return val; } private static bool Slider(MenuSlider template, Transform parent, float y, string name, string[] labels, Func<int> read, Action<int> write) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if (labels == null || labels.Length < 2) { return false; } try { GameObject val = CloneDormant((Component)(object)template, parent, y); MenuSlider component = val.GetComponent<MenuSlider>(); if ((Object)(object)component == (Object)null) { Object.DestroyImmediate((Object)(object)val); return false; } Strip<MenuSetting>(val); Strip<MenuInputPercentSetting>(val); Strip<MenuBigSettingText>(val); component.onChange = new UnityEvent(); component.customOptions = new List<CustomOption>(); component.hasCustomOptions = false; component.hasCustomValues = false; component.hasBar = true; component.wrapAround = false; component.buttonSegmentJump = 1; component.pointerSegmentJump = 1; component.startValue = 0; component.endValue = labels.Length - 1; component.stringAtStartOfValue = ""; component.stringAtEndOfValue = ""; component.elementName = "GFX " + Loc.T(name); int num = Mathf.Clamp(read(), 0, labels.Length - 1); component.settingsValue = (float)num / (float)(labels.Length - 1); PruneClicks(val, (Component)(object)component, "OnIncrease", "OnDecrease"); val.AddComponent<GfxSliderRow>().Bind(component, "GFX " + Loc.T(name), labels, read, write); val.SetActive(true); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] Couldn't add the '" + name + "' row: " + ex.Message)); return false; } } private static bool Toggle(MenuTwoOptions template, Transform parent, float y, string name, Func<bool> read, Action<bool> write) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown try { GameObject val = CloneDormant((Component)(object)template, parent, y); MenuTwoOptions two = val.GetComponent<MenuTwoOptions>(); if ((Object)(object)two == (Object)null) { Object.DestroyImmediate((Object)(object)val); return false; } two.onOption1 = new UnityEvent(); two.onOption2 = new UnityEvent(); two.fetchSetting = new UnityEvent(); two.customEvents = true; two.customFetch = true; two.settingSet = false; two.settingName = "GFX " + Loc.T(name); two.fetchSetting.AddListener((UnityAction)delegate { try { two.startSettingFetch = read(); } catch { } }); two.onOption1.AddListener((UnityAction)delegate { try { write(obj: true); } catch { } }); two.onOption2.AddListener((UnityAction)delegate { try { write(obj: false); } catch { } }); PruneClicks(val, (Component)(object)two, "OnOption1", "OnOption2"); val.AddComponent<GfxToggleRow>().Bind(two, "GFX " + Loc.T(name)); val.SetActive(true); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] Couldn't add the '" + name + "' row: " + ex.Message)); return false; } } internal static TextMeshProUGUI TitleOf(Component row) { HashSet<TextMeshProUGUI> exclude = new HashSet<TextMeshProUGUI>(); MenuTwoOptions val = (MenuTwoOptions)(object)((row is MenuTwoOptions) ? row : null); if (val != null) { exclude.Add(val.option1TextMesh); exclude.Add(val.option2TextMesh); } MenuBigButton component = row.GetComponent<MenuBigButton>(); if ((Object)(object)component != (Object)null && (Object)(object)component.menuButton != (Object)null) { exclude.Add(component.menuButton.buttonText); } return ((IEnumerable<TextMeshProUGUI>)row.GetComponentsInChildren<TextMeshProUGUI>(true)).FirstOrDefault((Func<TextMeshProUGUI, bool>)((TextMeshProUGUI t) => (Object)(object)t != (Object)null && !exclude.Contains(t))); } internal static void Header(Component row, TextMeshProUGUI title, Transform parent, float y, string text, bool major, string tag) { //IL_0024: 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_002f: 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: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)row == (Object)null || (Object)(object)title == (Object)null || (Object)(object)parent == (Object)null) { return; } try { Vector3 val = parent.InverseTransformPoint(((TMP_Text)title).transform.position); float x = val.x; float num = val.y - row.transform.localPosition.y; GameObject val2 = Object.Instantiate<GameObject>(((Component)title).gameObject, parent); ((Object)val2).name = tag; foreach (Transform item in ((IEnumerable)val2.transform).Cast<Transform>().ToList()) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } Component[] components = val2.GetComponents<Component>(); foreach (Component val3 in components) { if (!((Object)(object)val3 == (Object)null) && !(val3 is Transform) && !(val3 is TextMeshProUGUI) && !(val3 is CanvasRenderer)) { Object.DestroyImmediate((Object)(object)val3); } } val2.transform.localPosition = new Vector3(x, y + num, val.z); val2.transform.localRotation = ((((TMP_Text)title).transform.rotation == Quaternion.identity) ? Quaternion.identity : (Quaternion.Inverse(parent.rotation) * ((TMP_Text)title).transform.rotation)); val2.transform.localScale = (Vector3)((((TMP_Text)title).transform.lossyScale.x > 0f && parent.lossyScale.x > 0f) ? new Vector3(((TMP_Text)title).transform.lossyScale.x / parent.lossyScale.x, ((TMP_Text)title).transform.lossyScale.y / parent.lossyScale.y, 1f) : Vector3.one); TextMeshProUGUI component = val2.GetComponent<TextMeshProUGUI>(); text = Loc.T(text); ((TMP_Text)component).text = (major ? text : ("— " + text + " —")); ((TMP_Text)component).fontStyle = (FontStyles)1; ((TMP_Text)component).enableWordWrapping = false; ((TMP_Text)component).overflowMode = (TextOverflowModes)0; if (major) { ((TMP_Text)component).fontSize = ((TMP_Text)title).fontSize * 1.25f; ((Graphic)component).color = new Color(0.67f, 0.55f, 1f, 1f); } else { ((Graphic)component).color = new Color(((Graphic)component).color.r, ((Graphic)component).color.g, ((Graphic)component).color.b, ((Graphic)component).color.a * 0.75f); } val2.SetActive(true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] Couldn't add the '" + text + "' heading: " + ex.Message)); } } private static void PruneClicks(GameObject clone, Component keep, params string[] keepMethods) { MenuButton[] componentsInChildren = clone.GetComponentsInChildren<MenuButton>(true); foreach (MenuButton val in componentsInChildren) { ButtonClickedEvent val2 = (((Object)(object)val != (Object)null && (Object)(object)val.button != (Object)null) ? val.button.onClick : null); if (val2 == null) { continue; } for (int j = 0; j < ((UnityEventBase)val2).GetPersistentEventCount(); j++) { Object persistentTarget = ((UnityEventBase)val2).GetPersistentTarget(j); string persistentMethodName = ((UnityEventBase)val2).GetPersistentMethodName(j); if ((object)persistentTarget != keep || Array.IndexOf(keepMethods, persistentMethodName) < 0) { ((UnityEventBase)val2).SetPersistentListenerState(j, (UnityEventCallState)0); } } } } private static void Strip<T>(GameObject go) where T : Component { T[] componentsInChildren = go.GetComponentsInChildren<T>(true); foreach (T val in componentsInChildren) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } } private static string[] Steps(float first, float step, int count, string suffix) { string[] array = new string[count]; for (int i = 0; i < count; i++) { float num = first + (float)i * step; array[i] = ((step >= 1f) ? num.ToString("0") : num.ToString("0.##")) + suffix; } return array; } private static string Readable(string enumName) { StringBuilder stringBuilder = new StringBuilder(enumName.Length + 4); for (int i = 0; i < enumName.Length; i++) { if (i > 0 && char.IsUpper(enumName[i]) && !char.IsUpper(enumName[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(char.ToUpperInvariant(enumName[i])); } return stringBuilder.ToString(); } private static int IndexOf<T>(T[] steps, T value, int fallback) { int num = Array.IndexOf(steps, value); if (num < 0) { return Mathf.Clamp(fallback, 0, steps.Length - 1); } return num; } private static int NearestIndex(float[] steps, float value) { int result = 0; float num = float.MaxValue; for (int i = 0; i < steps.Length; i++) { float num2 = Mathf.Abs(steps[i] - value); if (num2 < num) { num = num2; result = i; } } return result; } static SettingsRows() { ShadowResolution[] array = new ShadowResolution[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); ShadowResSteps = (ShadowResolution[])(object)array; AnisoSteps = (AnisotropicFiltering[])(object)new AnisotropicFiltering[3] { default(AnisotropicFiltering), (AnisotropicFiltering)1, (AnisotropicFiltering)2 }; AmbientOcclusionQuality[] array2 = new AmbientOcclusionQuality[5]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); AoQualitySteps = (AmbientOcclusionQuality[])(object)array2; ScreenSpaceReflectionPreset[] array3 = new ScreenSpaceReflectionPreset[7]; RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); SsrPresetSteps = (ScreenSpaceReflectionPreset[])(object)array3; } } internal sealed class GfxSliderRow : MonoBehaviour { private MenuSlider _slider; private string _name; private string[] _labels; private Func<int> _read; private Action<int> _write; private int _shown = -1; private bool _sized; public void Bind(MenuSlider slider, string name, string[] labels, Func<int> read, Action<int> write) { _slider = slider; _name = name; _labels = labels; _read = read; _write = write; } private void LateUpdate() { if ((Object)(object)_slider == (Object)null || _labels == null) { return; } if ((Object)(object)_slider.elementNameText != (Object)null && ((TMP_Text)_slider.elementNameText).text != _name) { ((TMP_Text)_slider.elementNameText).text = _name; } int num = Mathf.Clamp(_slider.currentValue, 0, _labels.Length - 1); if (_shown < 0) { _shown = num; if (!_sized) { _sized = true; try { _slider.SetBarScaleInstant(); } catch { } } } else if (num != _shown) { _shown = num; try { _write(num); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SoloGFX] '" + _name + "' failed to apply: " + ex.Message)); } } string text = _labels[num]; if ((Object)(object)_slider.segmentText != (Object)null && ((TMP_Text)_slider.segmentText).text != text) { ((TMP_Text)_slider.segmentText).text = text; } if ((Object)(object)_slider.segmentMaskText != (Object)null && ((TMP_Text)_slider.segmentMaskText).text != text) { ((TMP_Text)_slider.segmentMaskText).text = text; } SettingsRows.FlushIfDue(); } } internal sealed class GfxToggleRow : MonoBehaviour { private MenuTwoOptions _two; private string _name; private TextMeshProUGUI[] _titles = (TextMeshProUGUI[])(object)new TextMeshProUGUI[0]; public void Bind(MenuTwoOptions two, string name) { _two = two; _name = name; _titles = (from t in ((Component)two).GetComponentsInChildren<TextMeshProUGUI>(true) where (Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)two.option1TextMesh && (Object)(object)t != (Object)(object)two.option2TextMesh select t).ToArray(); Apply(); } private void LateUpdate() { Apply(); } private void Apply() { TextMeshProUGUI[] titles = _titles; foreach (TextMeshProUGUI val in titles) { if ((Object)(object)val != (Object)null && ((TMP_Text)val).text != _name) { ((TMP_Text)val).text = _name; } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }