Decompiled source of BetterLab v1.0.0
Mods/BetterLab.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BetterLab; using BoneLib; using BoneLib.BoneMenu; using BoneLib.Notifications; using Il2CppHorizonBasedAmbientOcclusion.Universal; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppMK.Glow; using Il2CppMK.Glow.URP; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.XR; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "BetterLab", "1.0.0", "RUcreator", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BetterLab")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetterLab")] [assembly: AssemblyTitle("BetterLab")] [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 BetterLab { public static class Assets { private static AssetBundle bundle; private static bool tried; public static bool Loaded => (Object)(object)bundle != (Object)null; public static void Load() { if (tried) { return; } tried = true; try { using Stream stream = typeof(Assets).Assembly.GetManifestResourceStream("BetterLab.betterlab.bundle") ?? throw new Exception("embedded bundle missing"); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); byte[] array = memoryStream.ToArray(); string text = Path.Combine(MelonEnvironment.UserDataDirectory, "BetterLab"); Directory.CreateDirectory(text); string text2 = Convert.ToHexString(SHA1.HashData(array)).Substring(0, 12); string text3 = Path.Combine(text, "betterlab_" + text2 + ".bundle"); if (!File.Exists(text3)) { string[] files = Directory.GetFiles(text, "betterlab_*.bundle"); foreach (string path in files) { try { File.Delete(path); } catch { } } File.WriteAllBytes(text3, array); } bundle = AssetBundle.LoadFromFile(text3); if ((Object)(object)bundle == (Object)null) { throw new Exception("AssetBundle.LoadFromFile returned null for " + text3); } ((Object)bundle).hideFlags = (HideFlags)32; MelonLogger.Msg($"BetterLab assets loaded ({array.Length / 1024} KB): " + string.Join(", ", Il2CppArrayBase<string>.op_Implicit((Il2CppArrayBase<string>)(object)bundle.GetAllAssetNames()))); } catch (Exception ex) { MelonLogger.Warning("BetterLab: weather assets not loaded, sky/rain/snow/sounds disabled: " + ex.Message); } } public static T Get<T>(string name) where T : Object { if ((Object)(object)bundle == (Object)null) { return default(T); } try { Object val = bundle.LoadAsset(name, Il2CppType.Of<T>()); if (val == (Object)null) { MelonLogger.Warning("BetterLab: asset not in bundle: " + name); return default(T); } val.hideFlags = (HideFlags)32; return ((Il2CppObjectBase)val).Cast<T>(); } catch (Exception ex) { MelonLogger.Warning("BetterLab: could not load " + name + ": " + ex.Message); return default(T); } } } public sealed class Core : MelonMod { private static float warnedAt = -10f; private static bool started; private static bool dirty = true; private static bool texDirty; private static float slowTick; private static TexMode lastTex; private static UniversalAdditionalCameraData camData; private static bool camPostOrig; private static EnumElement presetEl; private static EnumElement resModeEl; private static EnumElement msaaEl; private static EnumElement shadowsEl; private static EnumElement aoEl; private static EnumElement ssrEl; private static EnumElement texEl; private static EnumElement detailEl; private static EnumElement bloomEl; private static EnumElement bloomQEl; private static EnumElement toneEl; private static EnumElement godEl; private static FloatElement resEl; private static FloatElement minResEl; private static FloatElement sharpEl; private static FloatElement expEl; private static FloatElement conEl; private static FloatElement satEl; private static FloatElement tempEl; private static FloatElement vigEl; private static FloatElement chromaEl; private static FloatElement grainEl; private static BoolElement flareEl; private static BoolElement glareEl; private static BoolElement dirtEl; public static Camera Camera { get; private set; } public override void OnInitializeMelon() { try { Settings.Init(); Settings.Changed += delegate { dirty = true; }; lastTex = Settings.Textures; Assets.Load(); BuildMenu(); Hooking.OnLevelLoaded += delegate { MelonCoroutines.Start(AfterLevelLoad()); }; started = true; ((MelonBase)this).LoggerInstance.Msg($"BetterLab ready: {(Settings.Enabled ? "ON" : "OFF")}, preset {Settings.Preset}, weather {Settings.Weather}"); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("BetterLab could not start: " + ex); } } private static IEnumerator AfterLevelLoad() { yield return null; yield return null; try { RefreshCamera(log: true); Pipeline.Refresh(); Pipeline.Apply(); DynamicResolution.Reset(); Weather.OnLevelLoaded(); dirty = true; } catch (Exception ex) { Warn("level load: " + ex); } float until = Time.realtimeSinceStartup + 3f; while (Time.realtimeSinceStartup < until) { yield return null; } try { Pipeline.ApplyTextures(force: true); MelonLogger.Msg("BetterLab status: " + Status(full: true)); } catch (Exception ex2) { Warn("level load (late): " + ex2); } } public override void OnUpdate() { if (!started) { return; } try { if (Time.unscaledTime > slowTick) { slowTick = Time.unscaledTime + 1f; RefreshCamera(log: false); if (Pipeline.Refresh()) { MelonLogger.Msg("BetterLab: the game switched its pipeline asset (graphics quality changed)"); DynamicResolution.Reset(); dirty = true; } else if (Settings.Enabled) { Pipeline.Apply(restoreGame: false); } } if (dirty) { dirty = false; if (!Settings.Enabled) { Pipeline.RestoreAll(); Weather.Disable(); } else { Pipeline.Apply(); } if (Settings.Textures != lastTex || texDirty) { lastTex = Settings.Textures; texDirty = false; Pipeline.ApplyTextures(force: true); } Weather.SettingsChanged(); ApplyCameraPost(); PostFx.Apply(); } DynamicResolution.Update(); Weather.Update(); if (Weather.Animating) { PostFx.Apply(); } } catch (Exception ex) { Warn(ex.ToString()); } } public override void OnLateUpdate() { if (!started) { return; } try { Weather.LateUpdate(); } catch (Exception ex) { Warn(ex.ToString()); } } private static void RefreshCamera(bool log) { //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) Camera val = Camera.main; if ((Object)(object)val == (Object)null && (Object)(object)Player.Head != (Object)null) { val = ((Component)Player.Head).GetComponentInChildren<Camera>(); } if ((Object)(object)val == (Object)null) { return; } bool flag = (Object)(object)Camera == (Object)null || ((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)Camera).Pointer; Camera = val; if (flag || log) { if (flag) { camData = ((Component)val).GetComponent<UniversalAdditionalCameraData>(); camPostOrig = (Object)(object)camData != (Object)null && camData.renderPostProcessing; } LayerMask volumeLayerMask; if (PostFx.Ensure() && (Object)(object)camData != (Object)null) { volumeLayerMask = camData.volumeLayerMask; PostFx.FitLayer(((LayerMask)(ref volumeLayerMask)).value); } ApplyCameraPost(); string obj = $"BetterLab: camera '{Path(((Component)val).transform)}' far {val.farClipPlane:0} m, stereo {val.stereoEnabled}, "; object obj2; if (!((Object)(object)camData != (Object)null)) { obj2 = "no URP camera data"; } else { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(45, 5); defaultInterpolatedStringHandler.AppendLiteral("post "); defaultInterpolatedStringHandler.AppendFormatted(camPostOrig); defaultInterpolatedStringHandler.AppendLiteral(" (now "); defaultInterpolatedStringHandler.AppendFormatted(camData.renderPostProcessing); defaultInterpolatedStringHandler.AppendLiteral("), volume mask 0x"); volumeLayerMask = camData.volumeLayerMask; defaultInterpolatedStringHandler.AppendFormatted(((LayerMask)(ref volumeLayerMask)).value, "X"); defaultInterpolatedStringHandler.AppendLiteral(", AA "); defaultInterpolatedStringHandler.AppendFormatted<AntialiasingMode>(camData.antialiasing); defaultInterpolatedStringHandler.AppendLiteral(", renderer #"); defaultInterpolatedStringHandler.AppendFormatted(camData.m_RendererIndex); obj2 = defaultInterpolatedStringHandler.ToStringAndClear(); } MelonLogger.Msg(obj + (string?)obj2); } } private static void ApplyCameraPost() { if (!((Object)(object)camData == (Object)null)) { bool flag = Settings.Enabled || camPostOrig; if (camData.renderPostProcessing != flag) { camData.renderPostProcessing = flag; } } } private static string Path(Transform t) { string text = ((Object)t).name; Transform parent = t.parent; while ((Object)(object)parent != (Object)null && text.Length < 120) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private static void BuildMenu() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_00bc: 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_0149: 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_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: 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_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_055b: Unknown result type (might be due to invalid IL or missing references) //IL_0599: 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_0629: Unknown result type (might be due to invalid IL or missing references) //IL_0671: Unknown result type (might be due to invalid IL or missing references) //IL_06b9: Unknown result type (might be due to invalid IL or missing references) //IL_0701: Unknown result type (might be due to invalid IL or missing references) //IL_0748: Unknown result type (might be due to invalid IL or missing references) //IL_079f: Unknown result type (might be due to invalid IL or missing references) //IL_07b1: Unknown result type (might be due to invalid IL or missing references) //IL_07e6: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_085e: Unknown result type (might be due to invalid IL or missing references) //IL_088d: Unknown result type (might be due to invalid IL or missing references) Page obj = Page.Root.CreatePage("BetterLab", new Color(0.3f, 0.85f, 1f), 0, true); obj.CreateBool("BetterLab On/Off", Color.green, Settings.Enabled, (Action<bool>)delegate(bool v) { Settings.Enabled = v; Notify("BetterLab " + (v ? "ON" : "OFF (game graphics)")); }); presetEl = obj.CreateEnum("Preset", new Color(1f, 0.8f, 0.2f), (Enum)Settings.Preset, (Action<Enum>)delegate(Enum v) { Preset preset = (Preset)(object)v; if (preset != Preset.Custom) { Presets.Apply(preset); SyncMenu(); texDirty = true; Notify($"Preset {preset}: {Presets.Describe(preset)}", 5f); } }); obj.CreateEnum("Weather", new Color(0.6f, 0.8f, 1f), (Enum)Settings.Weather, (Action<Enum>)delegate(Enum v) { Settings.Weather = (WeatherType)(object)v; Notify("Weather: " + v); }); obj.CreateFloat("Weather intensity", new Color(0.6f, 0.8f, 1f), Settings.WeatherIntensity, 0.25f, 0.25f, 1.5f, (Action<float>)delegate(float v) { Settings.WeatherIntensity = v; }); Page obj2 = obj.CreatePage("Graphics", Color.white, 0, true); resModeEl = obj2.CreateEnum("Resolution mode", Color.white, (Enum)Settings.ResMode, (Action<Enum>)delegate(Enum v) { Settings.ResMode = (ResMode)(object)v; }); resEl = obj2.CreateFloat("Resolution (max)", Color.white, Settings.Resolution, 0.05f, 0.5f, 2f, (Action<float>)delegate(float v) { Settings.Resolution = v; }); minResEl = obj2.CreateFloat("Auto: min resolution", Color.white, Settings.MinResolution, 0.05f, 0.5f, 2f, (Action<float>)delegate(float v) { Settings.MinResolution = v; }); msaaEl = obj2.CreateEnum("Anti-aliasing (MSAA)", Color.white, (Enum)Settings.Msaa, (Action<Enum>)delegate(Enum v) { Settings.Msaa = (Msaa)(object)v; }); shadowsEl = obj2.CreateEnum("Shadows", Color.white, (Enum)Settings.Shadows, (Action<Enum>)delegate(Enum v) { Settings.Shadows = (Quality4)(object)v; }); aoEl = obj2.CreateEnum("Ambient occlusion", Color.white, (Enum)Settings.Ao, (Action<Enum>)delegate(Enum v) { Settings.Ao = (AoMode)(object)v; }); ssrEl = obj2.CreateEnum("Reflections (SSR)", Color.white, (Enum)Settings.Ssr, (Action<Enum>)delegate(Enum v) { Settings.Ssr = (Reflections)(object)v; }); texEl = obj2.CreateEnum("Textures", Color.white, (Enum)Settings.Textures, (Action<Enum>)delegate(Enum v) { Settings.Textures = (TexMode)(object)v; }); detailEl = obj2.CreateEnum("Detail distance", Color.white, (Enum)Settings.Detail, (Action<Enum>)delegate(Enum v) { Settings.Detail = (Detail)(object)v; }); sharpEl = obj2.CreateFloat("Sharpen (FSR, test)", Color.yellow, Settings.Sharpen, 0.1f, 0f, 1f, (Action<float>)delegate(float v) { Settings.Sharpen = v; }); Page obj3 = obj.CreatePage("Effects", Color.white, 0, true); bloomEl = obj3.CreateEnum("Bloom", Color.white, (Enum)Settings.Bloom, (Action<Enum>)delegate(Enum v) { Settings.Bloom = (BloomMode)(object)v; }); bloomQEl = obj3.CreateEnum("Bloom quality", Color.white, (Enum)Settings.BloomQuality, (Action<Enum>)delegate(Enum v) { Settings.BloomQuality = (Quality4)(object)v; }); flareEl = obj3.CreateBool("Lens flare", Color.white, Settings.LensFlare, (Action<bool>)delegate(bool v) { Settings.LensFlare = v; }); glareEl = obj3.CreateBool("Glare streaks", Color.white, Settings.Glare, (Action<bool>)delegate(bool v) { Settings.Glare = v; }); dirtEl = obj3.CreateBool("Lens dirt", Color.white, Settings.LensDirt, (Action<bool>)delegate(bool v) { Settings.LensDirt = v; }); godEl = obj3.CreateEnum("God rays", Color.white, (Enum)Settings.GodRays, (Action<Enum>)delegate(Enum v) { Settings.GodRays = (GodRays)(object)v; }); toneEl = obj3.CreateEnum("Tonemapping", Color.white, (Enum)Settings.Tonemap, (Action<Enum>)delegate(Enum v) { Settings.Tonemap = (ToneMap)(object)v; }); expEl = obj3.CreateFloat("Exposure", Color.white, Settings.Exposure, 0.1f, -2f, 2f, (Action<float>)delegate(float v) { Settings.Exposure = v; }); conEl = obj3.CreateFloat("Contrast", Color.white, Settings.Contrast, 2f, -50f, 50f, (Action<float>)delegate(float v) { Settings.Contrast = v; }); satEl = obj3.CreateFloat("Saturation", Color.white, Settings.Saturation, 2f, -50f, 50f, (Action<float>)delegate(float v) { Settings.Saturation = v; }); tempEl = obj3.CreateFloat("Temperature", Color.white, Settings.Temperature, 2f, -50f, 50f, (Action<float>)delegate(float v) { Settings.Temperature = v; }); vigEl = obj3.CreateFloat("Vignette", Color.white, Settings.Vignette, 0.02f, 0f, 0.6f, (Action<float>)delegate(float v) { Settings.Vignette = v; }); chromaEl = obj3.CreateFloat("Chromatic aberration", Color.white, Settings.Chroma, 0.02f, 0f, 1f, (Action<float>)delegate(float v) { Settings.Chroma = v; }); grainEl = obj3.CreateFloat("Film grain", Color.white, Settings.Grain, 0.05f, 0f, 1f, (Action<float>)delegate(float v) { Settings.Grain = v; }); Page obj4 = obj.CreatePage("Weather options", new Color(0.6f, 0.8f, 1f), 0, true); obj4.CreateBool("Weather sounds", Color.white, Settings.WeatherSound, (Action<bool>)delegate(bool v) { Settings.WeatherSound = v; }); obj4.CreateFloat("Weather volume", Color.white, Settings.WeatherVolume, 0.1f, 0f, 1f, (Action<float>)delegate(float v) { Settings.WeatherVolume = v; }); obj4.CreateBool("Lightning (storm)", Color.white, Settings.Lightning, (Action<bool>)delegate(bool v) { Settings.Lightning = v; }); obj.CreateFunction("Show stats", Color.white, (Action)delegate { Notify(Status(full: false), 8f); }); obj.CreateFunction("Reapply preset", Color.yellow, (Action)delegate { Preset p = ((Settings.Preset == Preset.Custom) ? Preset.Balanced : Settings.Preset); Presets.Apply(p); SyncMenu(); texDirty = true; Notify("Preset " + p.ToString() + " restored"); }); } private static void SyncMenu() { try { presetEl.Value = Settings.Preset; resModeEl.Value = Settings.ResMode; resEl.Value = Settings.Resolution; minResEl.Value = Settings.MinResolution; msaaEl.Value = Settings.Msaa; shadowsEl.Value = Settings.Shadows; aoEl.Value = Settings.Ao; ssrEl.Value = Settings.Ssr; texEl.Value = Settings.Textures; detailEl.Value = Settings.Detail; sharpEl.Value = Settings.Sharpen; bloomEl.Value = Settings.Bloom; bloomQEl.Value = Settings.BloomQuality; flareEl.Value = Settings.LensFlare; glareEl.Value = Settings.Glare; dirtEl.Value = Settings.LensDirt; godEl.Value = Settings.GodRays; toneEl.Value = Settings.Tonemap; expEl.Value = Settings.Exposure; conEl.Value = Settings.Contrast; satEl.Value = Settings.Saturation; tempEl.Value = Settings.Temperature; vigEl.Value = Settings.Vignette; chromaEl.Value = Settings.Chroma; grainEl.Value = Settings.Grain; } catch (Exception ex) { Warn("menu sync: " + ex.Message); } } private static string Status(bool full) { float value = ((Time.unscaledDeltaTime > 0f) ? (1f / Time.unscaledDeltaTime) : 0f); string text = $"{(Settings.Enabled ? "ON" : "OFF")}, preset {Settings.Preset}; {value:0} FPS (headset {DynamicResolution.RefreshRate:0} Hz), render scale {(((Object)(object)Pipeline.Asset != (Object)null) ? Pipeline.Asset.renderScale : 0f):0.00}" + (DynamicResolution.Active ? $" auto [{Settings.MinResolution:0.00}..{Settings.Resolution:0.00}], frame {DynamicResolution.LastMedianMs:0.0} ms, late {DynamicResolution.LateShare:P0}" : "") + "; " + Weather.Describe(); if (full) { text = text + "\n pipeline: " + Pipeline.Describe() + "\n post: " + PostFx.Describe(); } return text; } public static void Notify(string text, float seconds = 2.5f) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown MelonLogger.Msg(text); try { Notifier.Send(new Notification { Title = NotificationText.op_Implicit("BetterLab"), Message = NotificationText.op_Implicit(text), Type = (NotificationType)0, PopupLength = seconds, ShowTitleOnPopup = true }); } catch (Exception) { } } public static void Debug(string text) { MelonLogger.Msg("BetterLab: " + text); } public static void Warn(string text) { if (Time.realtimeSinceStartup - warnedAt > 3f) { warnedAt = Time.realtimeSinceStartup; MelonLogger.Warning("BetterLab: " + text); } } } public static class DynamicResolution { private const float Window = 1f; private const float StepUp = 0.05f; private const float StepDown = 0.1f; private const float UpQuiet = 6f; private const float CeilingMemory = 60f; private static readonly List<float> frames = new List<float>(256); private static float windowStart; private static float lastChange; private static float lastDrop = -999f; private static float ceiling = 9f; private static float graceUntil; private static float scale = -1f; private static float refresh; private static float estimate; private static readonly Queue<float> medians = new Queue<float>(); private static bool triedXr; public static float Scale => scale; public static float RefreshRate { get { if (!(refresh > 0f)) { return estimate; } return refresh; } } public static float LastMedianMs { get; private set; } public static float LateShare { get; private set; } public static bool Active { get { if (Settings.Enabled && Settings.ResMode == ResMode.Auto) { return (Object)(object)Pipeline.Asset != (Object)null; } return false; } } public static void Reset() { frames.Clear(); windowStart = Time.unscaledTime; graceUntil = Time.unscaledTime + 4f; scale = -1f; ceiling = 9f; } private static void FindRefresh() { if (triedXr) { return; } triedXr = true; try { List<XRDisplaySubsystem> val = new List<XRDisplaySubsystem>(); SubsystemManager.GetInstances<XRDisplaySubsystem>(val); float num = default(float); for (int i = 0; i < val.Count; i++) { if (val[i] != null && ((IntegratedSubsystem)val[i]).running && val[i].TryGetDisplayRefreshRate(ref num) && num > 30f) { refresh = num; break; } } MelonLogger.Msg($"BetterLab: headset refresh rate {((refresh > 0f) ? (refresh.ToString("0") + " Hz") : "unknown (will measure)")}, eye texture {XRSettings.eyeTextureWidth}x{XRSettings.eyeTextureHeight}, eye scale {XRSettings.eyeTextureResolutionScale:0.00}"); } catch (Exception ex) { MelonLogger.Msg("BetterLab: refresh rate query failed (" + ex.Message + "), will measure it"); } } public static void Update() { if (!Active) { if (scale > 0f) { Reset(); } return; } FindRefresh(); float num = Mathf.Min(Settings.MinResolution, Settings.Resolution); float resolution = Settings.Resolution; if (scale < 0f) { scale = resolution; lastChange = Time.unscaledTime; Pipeline.SetRenderScale(scale); } if (Mathf.Abs(Mathf.Clamp(scale, num, resolution) - scale) > 0.001f) { scale = Mathf.Clamp(scale, num, resolution); Pipeline.SetRenderScale(scale); } if (Time.unscaledTime < graceUntil || (Object)(object)Player.RigManager == (Object)null) { frames.Clear(); windowStart = Time.unscaledTime; return; } frames.Add(Time.unscaledDeltaTime); if (Time.unscaledTime - windowStart < 1f) { return; } windowStart = Time.unscaledTime; frames.Sort(); float num2 = frames[frames.Count / 2]; LastMedianMs = num2 * 1000f; medians.Enqueue(num2); while (medians.Count > 30) { medians.Dequeue(); } float num3 = float.MaxValue; foreach (float median in medians) { num3 = Mathf.Min(num3, median); } estimate = Snap(1f / num3); float num4 = 1f / Mathf.Max(30f, RefreshRate); int num5 = 0; foreach (float frame in frames) { if (frame > num4 * 1.35f) { num5++; } } LateShare = (float)num5 / (float)frames.Count; frames.Clear(); float unscaledTime = Time.unscaledTime; if (unscaledTime - lastChange < 1.5f || Time.timeScale < 0.01f) { return; } if (LateShare > 0.08f || num2 > num4 * 1.15f) { if (scale > num + 0.001f) { ceiling = scale; lastDrop = unscaledTime; Set(Mathf.Max(num, scale - 0.1f), $"late frames {LateShare:P0}, median {num2 * 1000f:0.0} ms vs {num4 * 1000f:0.0}"); } } else if (LateShare < 0.01f && unscaledTime - lastChange > 6f && scale < resolution - 0.001f) { float num6 = Mathf.Min(resolution, scale + 0.05f); if (unscaledTime - lastDrop > 60f || num6 < ceiling - 0.001f) { Set(num6, "headroom"); } } } private static float Snap(float hz) { float[] obj = new float[6] { 60f, 72f, 80f, 90f, 120f, 144f }; float result = hz; float num = float.MaxValue; float[] array = obj; foreach (float num2 in array) { if (Mathf.Abs(num2 - hz) < num) { num = Mathf.Abs(num2 - hz); result = num2; } } if (!(num < 6f)) { return hz; } return result; } private static void Set(float s, string why) { scale = s; lastChange = Time.unscaledTime; Pipeline.SetRenderScale(s); Core.Debug($"auto resolution -> {s:0.00} ({why})"); } } public static class Pipeline { private sealed class Orig { public UniversalRenderPipelineAsset asset; public float renderScale; public float shadowDistance; public float cascadeBorder; public float ssrHit; public float fsrSharp; public int msaa; public int cascades; public int lightsPerObject; public int ssrSteps; public int ssrMinMip; public int upscaling; public ShadowResolution mainShadowRes; public ShadowResolution addShadowRes; public bool soft; public bool ssr; public bool fsrOverride; } private static readonly Dictionary<IntPtr, Orig> origs = new Dictionary<IntPtr, Orig>(); private static UniversalRenderPipelineAsset asset; private static float origLodBias = -1f; private static float appliedLod = -1f; private static int appliedAniso = -1; private static AnisotropicFiltering origAniso; private static bool qualityCaptured; private static readonly Dictionary<IntPtr, (Texture2D tex, float bias, int aniso)> texOrig = new Dictionary<IntPtr, (Texture2D, float, int)>(); private static TexMode texApplied = TexMode.Game; public static UniversalRenderPipelineAsset Asset => asset; public static string AssetName { get { if (!((Object)(object)asset != (Object)null)) { return "none"; } return ((Object)asset).name; } } private static Orig O { get { if (!((Object)(object)asset != (Object)null) || !origs.TryGetValue(((Il2CppObjectBase)asset).Pointer, out var value)) { return null; } return value; } } public static float GameRenderScale => O?.renderScale ?? 1f; public static bool Refresh() { //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected I4, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: 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_0100: 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_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) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected I4, but got Unknown RenderPipelineAsset val = null; try { val = GraphicsSettings.currentRenderPipeline; } catch { } UniversalRenderPipelineAsset val2 = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).TryCast<UniversalRenderPipelineAsset>() : null); bool result = (((Object)(object)val2 == (Object)null) ? ((Object)(object)asset != (Object)null) : ((Object)(object)asset == (Object)null || ((Il2CppObjectBase)val2).Pointer != ((Il2CppObjectBase)asset).Pointer)); asset = val2; if ((Object)(object)asset != (Object)null && !origs.ContainsKey(((Il2CppObjectBase)asset).Pointer)) { origs[((Il2CppObjectBase)asset).Pointer] = new Orig { asset = asset, renderScale = asset.renderScale, msaa = asset.msaaSampleCount, shadowDistance = asset.shadowDistance, cascades = asset.m_ShadowCascadeCount, cascadeBorder = asset.m_CascadeBorder, mainShadowRes = asset.m_MainLightShadowmapResolution, addShadowRes = asset.m_AdditionalLightsShadowmapResolution, lightsPerObject = asset.m_AdditionalLightsPerObjectLimit, soft = asset.m_SoftShadowsSupported, ssr = asset.m_EnableSSR, ssrSteps = asset.m_MaxSsrSteps, ssrMinMip = asset.m_SsrMinMip, ssrHit = asset.m_SsrHitRadius, upscaling = (int)asset.m_UpscalingFilter, fsrOverride = asset.m_FsrOverrideSharpness, fsrSharp = asset.m_FsrSharpness }; MelonLogger.Msg("BetterLab: pipeline asset " + Describe()); } if (!qualityCaptured) { qualityCaptured = true; try { origLodBias = QualitySettings.lodBias; } catch { origLodBias = 2f; } try { origAniso = QualitySettings.anisotropicFiltering; } catch { origAniso = (AnisotropicFiltering)2; } appliedLod = origLodBias; appliedAniso = (int)origAniso; MelonLogger.Msg($"BetterLab: game LOD bias {origLodBias}, anisotropic {origAniso}"); } return result; } public static void SetRenderScale(float s) { if ((Object)(object)asset != (Object)null && Mathf.Abs(asset.renderScale - s) > 0.004f) { asset.renderScale = s; } } public static void Apply(bool restoreGame = true) { //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Invalid comparison between I4 and Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Expected I4, but got Unknown Refresh(); Orig o = O; if ((Object)(object)asset == (Object)null || o == null) { return; } bool enabled = Settings.Enabled; try { if (!enabled || Settings.ResMode == ResMode.Game) { if (restoreGame) { SetRenderScale(o.renderScale); } } else if (Settings.ResMode == ResMode.Fixed) { SetRenderScale(Settings.Resolution); } int num = (enabled ? (Settings.Msaa switch { Msaa.Off => 1, Msaa.X2 => 2, Msaa.X4 => 4, Msaa.X8 => 8, _ => o.msaa, }) : o.msaa); int num2 = num; if (asset.msaaSampleCount != num2 && (restoreGame || (enabled && Settings.Msaa != Msaa.Game))) { asset.msaaSampleCount = num2; } switch (enabled ? Settings.Shadows : Quality4.Game) { case Quality4.Low: SetShadows(30f, 2, 0.1f, (ShadowResolution)1024, (ShadowResolution)1024, 4, soft: true); break; case Quality4.Medium: SetShadows(50f, 3, 0.1f, (ShadowResolution)2048, (ShadowResolution)2048, 6, soft: true); break; case Quality4.High: SetShadows(100f, 4, 0.0667f, (ShadowResolution)4096, (ShadowResolution)4096, 8, soft: true); break; case Quality4.Ultra: SetShadows(150f, 4, 0.05f, (ShadowResolution)4096, (ShadowResolution)4096, 8, soft: true); break; default: if (restoreGame) { SetShadows(o.shadowDistance, o.cascades, o.cascadeBorder, o.mainShadowRes, o.addShadowRes, o.lightsPerObject, o.soft); } break; } switch (enabled ? Settings.Ssr : Reflections.Game) { case Reflections.Off: asset.m_EnableSSR = false; break; case Reflections.On: asset.m_EnableSSR = true; asset.m_MaxSsrSteps = 35; asset.m_SsrMinMip = 0; asset.m_SsrHitRadius = 0.025f; break; case Reflections.High: asset.m_EnableSSR = true; asset.m_MaxSsrSteps = 64; asset.m_SsrMinMip = 0; asset.m_SsrHitRadius = 0.02f; break; default: if (restoreGame) { asset.m_EnableSSR = o.ssr; asset.m_MaxSsrSteps = o.ssrSteps; asset.m_SsrMinMip = o.ssrMinMip; asset.m_SsrHitRadius = o.ssrHit; } break; } float num3 = (enabled ? Settings.Sharpen : 0f); if (num3 > 0.01f) { asset.m_UpscalingFilter = (UpscalingFilterSelection)3; asset.m_FsrOverrideSharpness = true; asset.m_FsrSharpness = num3; } else if (restoreGame) { asset.m_UpscalingFilter = (UpscalingFilterSelection)o.upscaling; asset.m_FsrOverrideSharpness = o.fsrOverride; asset.m_FsrSharpness = o.fsrSharp; } } catch (Exception ex) { Core.Warn("pipeline: " + ex.Message); } try { float num4 = (enabled ? (Settings.Detail switch { Detail.Near => 1.2f, Detail.Normal => 2f, Detail.Far => 3f, Detail.Ultra => 4.5f, _ => origLodBias, }) : origLodBias); float num5 = num4; bool flag = !enabled || Settings.Detail == Detail.Game; if (num5 > 0f && Mathf.Abs(appliedLod - num5) > 0.001f && (restoreGame || !flag)) { QualitySettings.lodBias = num5; appliedLod = num5; } TexMode texMode = (enabled ? Settings.Textures : TexMode.Game); AnisotropicFiltering val = (AnisotropicFiltering)((texMode != TexMode.Game) ? 2 : ((int)origAniso)); if (appliedAniso != (int)val && (restoreGame || texMode != TexMode.Game)) { QualitySettings.anisotropicFiltering = val; appliedAniso = (int)val; } } catch (Exception ex2) { Core.Warn("quality: " + ex2.Message); } } private static void SetShadows(float dist, int cascades, float border, ShadowResolution main, ShadowResolution add, int lights, bool soft) { //IL_003e: 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) if (Mathf.Abs(asset.shadowDistance - dist) > 0.01f) { asset.shadowDistance = dist; } asset.m_ShadowCascadeCount = cascades; asset.m_CascadeBorder = border; asset.m_MainLightShadowmapResolution = main; asset.m_AdditionalLightsShadowmapResolution = add; asset.m_AdditionalLightsPerObjectLimit = lights; asset.m_SoftShadowsSupported = soft; } public static void ApplyTextures(bool force = false) { TexMode texMode = (Settings.Enabled ? Settings.Textures : TexMode.Game); if (!force && texMode == texApplied && texMode == TexMode.Game) { return; } texApplied = texMode; float num = texMode switch { TexMode.Sharp => -0.3f, TexMode.UltraSharp => -0.6f, _ => 0f, }; int num2 = 0; int num3 = 0; try { if (texMode == TexMode.Game) { foreach (KeyValuePair<IntPtr, (Texture2D, float, int)> item2 in texOrig) { Texture2D item = item2.Value.Item1; if (!((Object)(object)item == (Object)null)) { ((Texture)item).mipMapBias = 0f; ((Texture)item).anisoLevel = item2.Value.Item3; num3++; } } texOrig.Clear(); } else { foreach (Object item3 in (Il2CppArrayBase<Object>)(object)Resources.FindObjectsOfTypeAll(Il2CppType.Of<Texture2D>())) { Texture2D val = ((Il2CppObjectBase)item3).TryCast<Texture2D>(); if ((Object)(object)val == (Object)null || ((Texture)val).mipmapCount <= 1) { continue; } string name = ((Object)val).name; if (!name.StartsWith("Lightmap", StringComparison.OrdinalIgnoreCase) && !name.Contains("_lightmap", StringComparison.OrdinalIgnoreCase)) { if (!texOrig.ContainsKey(((Il2CppObjectBase)val).Pointer)) { texOrig[((Il2CppObjectBase)val).Pointer] = (val, 0f, ((Texture)val).anisoLevel); } ((Texture)val).mipMapBias = num; if (((Texture)val).anisoLevel < 16) { ((Texture)val).anisoLevel = 16; } num2++; } } } } catch (Exception ex) { Core.Warn("textures: " + ex.Message); } MelonLogger.Msg($"BetterLab: textures {texMode}: {num2} set (mip bias {num}), {num3} restored"); } public static void RestoreAll() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) foreach (Orig value in origs.Values) { UniversalRenderPipelineAsset val = value.asset; if ((Object)(object)val == (Object)null) { continue; } try { if (Mathf.Abs(val.renderScale - value.renderScale) > 0.004f) { val.renderScale = value.renderScale; } if (val.msaaSampleCount != value.msaa) { val.msaaSampleCount = value.msaa; } val.shadowDistance = value.shadowDistance; val.m_ShadowCascadeCount = value.cascades; val.m_CascadeBorder = value.cascadeBorder; val.m_MainLightShadowmapResolution = value.mainShadowRes; val.m_AdditionalLightsShadowmapResolution = value.addShadowRes; val.m_AdditionalLightsPerObjectLimit = value.lightsPerObject; val.m_SoftShadowsSupported = value.soft; val.m_EnableSSR = value.ssr; val.m_MaxSsrSteps = value.ssrSteps; val.m_SsrMinMip = value.ssrMinMip; val.m_SsrHitRadius = value.ssrHit; val.m_UpscalingFilter = (UpscalingFilterSelection)value.upscaling; val.m_FsrOverrideSharpness = value.fsrOverride; val.m_FsrSharpness = value.fsrSharp; } catch (Exception ex) { Core.Warn("restore: " + ex.Message); } } Apply(); ApplyTextures(force: true); } public static string Describe() { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)asset == (Object)null) { return "no URP asset"; } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(25, 4, stringBuilder2); handler.AppendLiteral("'"); handler.AppendFormatted(((Object)asset).name); handler.AppendLiteral("': scale "); handler.AppendFormatted(asset.renderScale, "0.00"); handler.AppendLiteral(", MSAA "); handler.AppendFormatted(asset.msaaSampleCount); handler.AppendLiteral(", HDR "); handler.AppendFormatted(asset.supportsHDR); handler.AppendLiteral(", "); stringBuilder3.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(22, 4, stringBuilder2); handler.AppendLiteral("shadows "); handler.AppendFormatted(asset.shadowDistance, "0"); handler.AppendLiteral(" m x"); handler.AppendFormatted(asset.m_ShadowCascadeCount); handler.AppendLiteral(" "); handler.AppendFormatted<ShadowResolution>(asset.m_MainLightShadowmapResolution); handler.AppendLiteral(", soft "); handler.AppendFormatted(asset.m_SoftShadowsSupported); handler.AppendLiteral(", "); stringBuilder4.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(31, 3, stringBuilder2); handler.AppendLiteral("lights/object "); handler.AppendFormatted(asset.m_AdditionalLightsPerObjectLimit); handler.AppendLiteral(", SSR "); handler.AppendFormatted(asset.m_EnableSSR); handler.AppendLiteral(" ("); handler.AppendFormatted(asset.m_MaxSsrSteps); handler.AppendLiteral(" steps), "); stringBuilder5.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(28, 3, stringBuilder2); handler.AppendLiteral("opaque tex "); handler.AppendFormatted(asset.m_RequireOpaqueTexture); handler.AppendLiteral(" ("); handler.AppendFormatted<Downsampling>(asset.m_OpaqueDownsampling); handler.AppendLiteral("), depth tex "); handler.AppendFormatted(asset.m_RequireDepthTexture); handler.AppendLiteral(", "); stringBuilder6.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder7 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(36, 3, stringBuilder2); handler.AppendLiteral("upscaling "); handler.AppendFormatted<UpscalingFilterSelection>(asset.m_UpscalingFilter); handler.AppendLiteral(", grading "); handler.AppendFormatted<ColorGradingMode>(asset.m_ColorGradingMode); handler.AppendLiteral(", volume update "); handler.AppendFormatted<VolumeFrameworkUpdateMode>(asset.m_VolumeFrameworkUpdateMode); stringBuilder7.Append(ref handler); try { Il2CppReferenceArray<ScriptableRendererData> rendererDataList = asset.m_RendererDataList; int num = 0; while (rendererDataList != null && num < ((Il2CppArrayBase<ScriptableRendererData>)(object)rendererDataList).Length) { ScriptableRendererData val = ((Il2CppArrayBase<ScriptableRendererData>)(object)rendererDataList)[num]; if (!((Object)(object)val == (Object)null)) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder8 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(24, 2, stringBuilder2); handler.AppendLiteral("; renderer "); handler.AppendFormatted(num); handler.AppendLiteral(" '"); handler.AppendFormatted(((Object)val).name); handler.AppendLiteral("' features:"); stringBuilder8.Append(ref handler); List<ScriptableRendererFeature> rendererFeatures = val.rendererFeatures; int num2 = 0; while (rendererFeatures != null && num2 < rendererFeatures.Count) { ScriptableRendererFeature val2 = rendererFeatures[num2]; stringBuilder.Append(((Object)(object)val2 == (Object)null) ? " (null)" : (" " + ((Object)val2).name + (val2.isActive ? "" : "(off)"))); num2++; } UniversalRendererData val3 = ((Il2CppObjectBase)val).TryCast<UniversalRendererData>(); if ((Object)(object)val3 != (Object)null) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder9 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2); handler.AppendLiteral(", post data "); handler.AppendFormatted(((Object)(object)val3.postProcessData != (Object)null) ? "yes" : "NO"); stringBuilder9.Append(ref handler); } } num++; } } catch (Exception ex) { stringBuilder.Append("; renderers: " + ex.Message); } try { stringBuilder2 = stringBuilder; StringBuilder stringBuilder10 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(18, 2, stringBuilder2); handler.AppendLiteral("; lodBias "); handler.AppendFormatted(appliedLod); handler.AppendLiteral(", aniso "); handler.AppendFormatted<AnisotropicFiltering>((AnisotropicFiltering)appliedAniso); stringBuilder10.Append(ref handler); } catch (Exception ex2) { stringBuilder.Append("; quality: " + ex2.Message); } return stringBuilder.ToString(); } } public struct Grade { public float exposure; public float contrast; public float saturation; public float temperature; public float tint; public float bloom; public float vignette; public Color filter; public static Grade Lerp(Grade a, Grade b, float t) { //IL_00ba: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) return new Grade { exposure = Mathf.Lerp(a.exposure, b.exposure, t), contrast = Mathf.Lerp(a.contrast, b.contrast, t), saturation = Mathf.Lerp(a.saturation, b.saturation, t), temperature = Mathf.Lerp(a.temperature, b.temperature, t), tint = Mathf.Lerp(a.tint, b.tint, t), bloom = Mathf.Lerp(a.bloom, b.bloom, t), vignette = Mathf.Lerp(a.vignette, b.vignette, t), filter = Color.Lerp(a.filter, b.filter, t) }; } } public static class PostFx { private static GameObject go; private static Volume volume; private static VolumeProfile profile; private static MKGlow mk; private static HBAO hbao; private static Tonemapping tone; private static ColorAdjustments color; private static WhiteBalance white; private static Vignette vig; private static ChromaticAberration chroma; private static FilmGrain grain; private static Volumetrics volumetrics; private static Texture2D lensDirt; private static bool failed; public static bool Ready => (Object)(object)volume != (Object)null; public static string Layer { get { if (!((Object)(object)go != (Object)null)) { return "-"; } return LayerMask.LayerToName(go.layer) + " (" + go.layer + ")"; } } private static T Add<T>() where T : VolumeComponent { try { T val = ((Il2CppObjectBase)profile.Add(Il2CppType.Of<T>(), false)).Cast<T>(); ((VolumeComponent)val).active = true; ((Object)(object)val).hideFlags = (HideFlags)32; return val; } catch (Exception ex) { MelonLogger.Warning($"BetterLab: no {typeof(T).Name} effect ({ex.Message})"); return default(T); } } public static bool Ensure() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if ((Object)(object)volume != (Object)null) { return true; } if (failed) { return false; } try { go = new GameObject("BetterLab Volume"); Object.DontDestroyOnLoad((Object)(object)go); volume = go.AddComponent<Volume>(); volume.isGlobal = true; volume.priority = 100f; volume.weight = 1f; profile = ScriptableObject.CreateInstance<VolumeProfile>(); ((Object)profile).name = "BetterLab"; ((Object)profile).hideFlags = (HideFlags)32; mk = Add<MKGlow>(); hbao = Add<HBAO>(); tone = Add<Tonemapping>(); color = Add<ColorAdjustments>(); white = Add<WhiteBalance>(); vig = Add<Vignette>(); chroma = Add<ChromaticAberration>(); grain = Add<FilmGrain>(); volumetrics = Add<Volumetrics>(); volume.sharedProfile = profile; lensDirt = Assets.Get<Texture2D>("LensDirt"); MelonLogger.Msg($"BetterLab: volume ready ({profile.components.Count} effects)"); return true; } catch (Exception ex) { failed = true; MelonLogger.Error("BetterLab: could not create the post-processing volume: " + ex); return false; } } public static void FitLayer(int mask) { if ((Object)(object)go == (Object)null || mask == 0 || (mask & (1 << go.layer)) != 0) { return; } for (int i = 0; i < 32; i++) { if ((mask & (1 << i)) != 0) { go.layer = i; MelonLogger.Msg($"BetterLab: volume moved to layer {i} ({LayerMask.LayerToName(i)})"); break; } } } private static void P<T>(VolumeParameter<T> p, T v) { ((VolumeParameter)p).overrideState = true; p.value = v; } private static void Off(VolumeParameter p) { if (p != null) { p.overrideState = false; } } private static void Grading(bool set, VolumeParameter<float> p, float v, float min, float max) { if (set) { P(p, Mathf.Clamp(v, min, max)); } else { Off((VolumeParameter)(object)p); } } private static T BaseValue<T, TC>(Func<TC, VolumeParameter<T>> sel, T def) where TC : VolumeComponent { try { List<Volume> volumes = VolumeManager.instance.m_Volumes; float num = float.MinValue; T result = def; int num2 = 0; while (volumes != null && num2 < volumes.Count) { Volume val = volumes[num2]; if (!((Object)(object)val == (Object)null) && !(((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)volume).Pointer) && ((Behaviour)val).isActiveAndEnabled && val.isGlobal && !(val.weight <= 0f) && !(val.priority < num)) { VolumeProfile val2 = (val.HasInstantiatedProfile() ? val.profile : val.sharedProfile); if (!((Object)(object)val2 == (Object)null)) { List<VolumeComponent> components = val2.components; for (int i = 0; i < components.Count; i++) { VolumeComponent obj = components[i]; TC val3 = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast<TC>() : default(TC)); if (!((Object)(object)val3 == (Object)null) && ((VolumeComponent)val3).active) { VolumeParameter<T> val4 = sel(val3); if (val4 != null && ((VolumeParameter)val4).overrideState) { result = val4.value; num = val.priority; } } } } } num2++; } return result; } catch { return def; } } private static float Base<TC>(Func<TC, VolumeParameter<float>> sel, float def) where TC : VolumeComponent { return BaseValue(sel, def); } private static Color BaseColor<TC>(Func<TC, VolumeParameter<Color>> sel, Color def) where TC : VolumeComponent { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) return BaseValue(sel, def); } public static void Apply() { if (!Ensure()) { return; } bool enabled = Settings.Enabled; Grade grade = Weather.Grade; float flash = Weather.Flash; try { ApplyBloom(enabled, grade); } catch (Exception ex) { Core.Warn("bloom: " + ex.Message); } try { ApplyAo(enabled); } catch (Exception ex2) { Core.Warn("ao: " + ex2.Message); } try { ApplyGrading(enabled, grade, flash); } catch (Exception ex3) { Core.Warn("grading: " + ex3.Message); } try { ApplyVolumetrics(enabled); } catch (Exception ex4) { Core.Warn("volumetrics: " + ex4.Message); } } private static void ApplyBloom(bool on, Grade w) { //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mk == (Object)null) { return; } BloomMode bloomMode = (on ? Settings.Bloom : BloomMode.Game); float num = 1f + w.bloom; switch (bloomMode) { case BloomMode.Off: P((VolumeParameter<float>)(object)mk.bloomIntensity, 0f); Off((VolumeParameter)(object)mk.bloomScattering); break; case BloomMode.Soft: P((VolumeParameter<float>)(object)mk.bloomIntensity, 1.8f * num); P((VolumeParameter<float>)(object)mk.bloomScattering, 6f); break; case BloomMode.Normal: P((VolumeParameter<float>)(object)mk.bloomIntensity, 3f * num); P((VolumeParameter<float>)(object)mk.bloomScattering, 7f); break; case BloomMode.Strong: P((VolumeParameter<float>)(object)mk.bloomIntensity, 4.5f * num); P((VolumeParameter<float>)(object)mk.bloomScattering, 8f); break; default: if (on && Mathf.Abs(w.bloom) > 0.01f) { P((VolumeParameter<float>)(object)mk.bloomIntensity, BaseValue<float, MKGlow>((Func<MKGlow, VolumeParameter<float>>)((MKGlow c) => (VolumeParameter<float>)(object)c.bloomIntensity), 3f) * num); } else { Off((VolumeParameter)(object)mk.bloomIntensity); } Off((VolumeParameter)(object)mk.bloomScattering); break; } Quality4 quality = (on ? Settings.BloomQuality : Quality4.Game); if (quality == Quality4.Game) { Off((VolumeParameter)(object)mk.quality); } else { VolumeParameter<Quality> quality2 = (VolumeParameter<Quality>)(object)mk.quality; P<Quality>(quality2, (Quality)(quality switch { Quality4.Low => 8, Quality4.Medium => 4, Quality4.High => 2, _ => 1, })); } if (on && Settings.LensFlare) { P((VolumeParameter<bool>)(object)mk.allowLensFlare, v: true); P<LensFlareStyle>((VolumeParameter<LensFlareStyle>)(object)mk.lensFlareStyle, (LensFlareStyle)1); P((VolumeParameter<float>)(object)mk.lensFlareGhostIntensity, 0.7f); P((VolumeParameter<float>)(object)mk.lensFlareHaloIntensity, 0.6f); } else { Off((VolumeParameter)(object)mk.allowLensFlare); Off((VolumeParameter)(object)mk.lensFlareStyle); Off((VolumeParameter)(object)mk.lensFlareGhostIntensity); Off((VolumeParameter)(object)mk.lensFlareHaloIntensity); } if (on && Settings.Glare) { P((VolumeParameter<bool>)(object)mk.allowGlare, v: true); P<GlareStyle>((VolumeParameter<GlareStyle>)(object)mk.glareStyle, (GlareStyle)1); P((VolumeParameter<float>)(object)mk.glareIntensity, 0.8f); P((VolumeParameter<float>)(object)mk.glareBlend, 0.33f); P((VolumeParameter<float>)(object)mk.glareScattering, 2f); P<MinMaxRange>((VolumeParameter<MinMaxRange>)(object)mk.glareThreshold, new MinMaxRange { minValue = 1.4f, maxValue = 10f }); } else { Off((VolumeParameter)(object)mk.allowGlare); Off((VolumeParameter)(object)mk.glareStyle); Off((VolumeParameter)(object)mk.glareIntensity); Off((VolumeParameter)(object)mk.glareBlend); Off((VolumeParameter)(object)mk.glareScattering); Off((VolumeParameter)(object)mk.glareThreshold); } if (on && Settings.LensDirt && (Object)(object)lensDirt != (Object)null) { P((VolumeParameter<bool>)(object)mk.allowLensSurface, v: true); P<Texture2D>((VolumeParameter<Texture2D>)(object)mk.lensSurfaceDirtTexture, lensDirt); P((VolumeParameter<float>)(object)mk.lensSurfaceDirtIntensity, 2.5f); } else { Off((VolumeParameter)(object)mk.allowLensSurface); Off((VolumeParameter)(object)mk.lensSurfaceDirtTexture); Off((VolumeParameter)(object)mk.lensSurfaceDirtIntensity); } } private static void ApplyAo(bool on) { if ((Object)(object)hbao == (Object)null) { return; } AoMode aoMode = (on ? Settings.Ao : AoMode.Game); switch (aoMode) { case AoMode.Game: { VolumeParameter[] array = (VolumeParameter[])(object)new VolumeParameter[12] { (VolumeParameter)hbao.intensity, (VolumeParameter)hbao.quality, (VolumeParameter)hbao.resolution, (VolumeParameter)hbao.radius, (VolumeParameter)hbao.mode, (VolumeParameter)hbao.blurType, (VolumeParameter)hbao.useMultiBounce, (VolumeParameter)hbao.colorBleedingEnabled, (VolumeParameter)hbao.saturation, (VolumeParameter)hbao.perPixelNormals, (VolumeParameter)hbao.noiseType, (VolumeParameter)hbao.bias }; for (int i = 0; i < array.Length; i++) { Off(array[i]); } return; } case AoMode.Off: P((VolumeParameter<float>)(object)hbao.intensity, 0f); return; } P<Mode>((VolumeParameter<Mode>)(object)hbao.mode, (Mode)1); P<PerPixelNormals>((VolumeParameter<PerPixelNormals>)(object)hbao.perPixelNormals, (PerPixelNormals)2); P<NoiseType>((VolumeParameter<NoiseType>)(object)hbao.noiseType, (NoiseType)1); P((VolumeParameter<float>)(object)hbao.bias, 0.172f); switch (aoMode) { case AoMode.Low: P<Quality>((VolumeParameter<Quality>)(object)hbao.quality, (Quality)1); P<Resolution>((VolumeParameter<Resolution>)(object)hbao.resolution, (Resolution)1); P((VolumeParameter<float>)(object)hbao.intensity, 1.5f); P((VolumeParameter<float>)(object)hbao.radius, 0.3f); P<BlurType>((VolumeParameter<BlurType>)(object)hbao.blurType, (BlurType)1); P((VolumeParameter<bool>)(object)hbao.useMultiBounce, v: true); P((VolumeParameter<bool>)(object)hbao.colorBleedingEnabled, v: false); break; case AoMode.Medium: P<Quality>((VolumeParameter<Quality>)(object)hbao.quality, (Quality)2); P<Resolution>((VolumeParameter<Resolution>)(object)hbao.resolution, (Resolution)0); P((VolumeParameter<float>)(object)hbao.intensity, 1.8f); P((VolumeParameter<float>)(object)hbao.radius, 0.3f); P<BlurType>((VolumeParameter<BlurType>)(object)hbao.blurType, (BlurType)1); P((VolumeParameter<bool>)(object)hbao.useMultiBounce, v: true); P((VolumeParameter<bool>)(object)hbao.colorBleedingEnabled, v: false); break; case AoMode.High: P<Quality>((VolumeParameter<Quality>)(object)hbao.quality, (Quality)4); P<Resolution>((VolumeParameter<Resolution>)(object)hbao.resolution, (Resolution)0); P((VolumeParameter<float>)(object)hbao.intensity, 2.1f); P((VolumeParameter<float>)(object)hbao.radius, 0.35f); P<BlurType>((VolumeParameter<BlurType>)(object)hbao.blurType, (BlurType)1); P((VolumeParameter<bool>)(object)hbao.useMultiBounce, v: true); P((VolumeParameter<bool>)(object)hbao.colorBleedingEnabled, v: false); break; case AoMode.UltraGI: P<Quality>((VolumeParameter<Quality>)(object)hbao.quality, (Quality)4); P<Resolution>((VolumeParameter<Resolution>)(object)hbao.resolution, (Resolution)0); P((VolumeParameter<float>)(object)hbao.intensity, 2.2f); P((VolumeParameter<float>)(object)hbao.radius, 0.45f); P<BlurType>((VolumeParameter<BlurType>)(object)hbao.blurType, (BlurType)2); P((VolumeParameter<bool>)(object)hbao.useMultiBounce, v: true); P((VolumeParameter<bool>)(object)hbao.colorBleedingEnabled, v: true); P((VolumeParameter<float>)(object)hbao.saturation, 1.6f); break; } } private static void ApplyGrading(bool on, Grade w, float flash) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) ToneMap toneMap = (on ? Settings.Tonemap : ToneMap.Game); if ((Object)(object)tone != (Object)null) { if (toneMap == ToneMap.Game) { Off((VolumeParameter)(object)tone.mode); } else { VolumeParameter<TonemappingMode> mode = (VolumeParameter<TonemappingMode>)(object)tone.mode; P<TonemappingMode>(mode, (TonemappingMode)(toneMap switch { ToneMap.Neutral => 1, ToneMap.ACES => 2, _ => 0, })); } } float num = (on ? Settings.Exposure : 0f) + w.exposure + flash * 1.6f; float num2 = (on ? Settings.Contrast : 0f) + w.contrast; float num3 = (on ? Settings.Saturation : 0f) + w.saturation; bool active = Weather.Active; if ((Object)(object)color != (Object)null) { Grading(on && Mathf.Abs(num) > 0.001f, (VolumeParameter<float>)(object)color.postExposure, Base<ColorAdjustments>((Func<ColorAdjustments, VolumeParameter<float>>)((ColorAdjustments c) => (VolumeParameter<float>)(object)c.postExposure), 0f) + num, -10f, 10f); Grading(on && Mathf.Abs(num2) > 0.01f, (VolumeParameter<float>)(object)color.contrast, Base<ColorAdjustments>((Func<ColorAdjustments, VolumeParameter<float>>)((ColorAdjustments c) => (VolumeParameter<float>)(object)c.contrast), 0f) + num2, -100f, 100f); Grading(on && Mathf.Abs(num3) > 0.01f, (VolumeParameter<float>)(object)color.saturation, Base<ColorAdjustments>((Func<ColorAdjustments, VolumeParameter<float>>)((ColorAdjustments c) => (VolumeParameter<float>)(object)c.saturation), 0f) + num3, -100f, 100f); if (on && active) { P<Color>((VolumeParameter<Color>)(object)color.colorFilter, BaseColor<ColorAdjustments>((Func<ColorAdjustments, VolumeParameter<Color>>)((ColorAdjustments c) => (VolumeParameter<Color>)(object)c.colorFilter), Color.white) * w.filter); } else { Off((VolumeParameter)(object)color.colorFilter); } } float num4 = (on ? Settings.Temperature : 0f) + w.temperature; if ((Object)(object)white != (Object)null) { Grading(on && Mathf.Abs(num4) > 0.01f, (VolumeParameter<float>)(object)white.temperature, Base<WhiteBalance>((Func<WhiteBalance, VolumeParameter<float>>)((WhiteBalance c) => (VolumeParameter<float>)(object)c.temperature), 0f) + num4, -100f, 100f); Grading(on && Mathf.Abs(w.tint) > 0.01f, (VolumeParameter<float>)(object)white.tint, Base<WhiteBalance>((Func<WhiteBalance, VolumeParameter<float>>)((WhiteBalance c) => (VolumeParameter<float>)(object)c.tint), 0f) + w.tint, -100f, 100f); } float num5 = (on ? Settings.Vignette : 0f) + w.vignette; if ((Object)(object)vig != (Object)null) { if (on && num5 > 0.001f) { num5 = Mathf.Max(num5, Base<Vignette>((Func<Vignette, VolumeParameter<float>>)((Vignette c) => (VolumeParameter<float>)(object)c.intensity), 0f) + w.vignette); P((VolumeParameter<float>)(object)vig.intensity, Mathf.Clamp01(num5)); P((VolumeParameter<float>)(object)vig.smoothness, 0.45f); P<Color>((VolumeParameter<Color>)(object)vig.color, Color.black); } else { Off((VolumeParameter)(object)vig.intensity); Off((VolumeParameter)(object)vig.smoothness); Off((VolumeParameter)(object)vig.color); } } if ((Object)(object)chroma != (Object)null) { if (on && Settings.Chroma > 0.001f) { P((VolumeParameter<float>)(object)chroma.intensity, Settings.Chroma); } else { Off((VolumeParameter)(object)chroma.intensity); } } if ((Object)(object)grain != (Object)null) { if (on && Settings.Grain > 0.001f) { P<FilmGrainLookup>((VolumeParameter<FilmGrainLookup>)(object)grain.type, (FilmGrainLookup)1); P((VolumeParameter<float>)(object)grain.intensity, Settings.Grain); P((VolumeParameter<float>)(object)grain.response, 0.8f); } else { Off((VolumeParameter)(object)grain.type); Off((VolumeParameter)(object)grain.intensity); Off((VolumeParameter)(object)grain.response); } } } private static void ApplyVolumetrics(bool on) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)volumetrics == (Object)null)) { GodRays godRays = (on ? Settings.GodRays : GodRays.Game); bool flag = (uint)(godRays - 2) <= 1u; float num = (flag ? BaseValue<float, Volumetrics>((Func<Volumetrics, VolumeParameter<float>>)((Volumetrics c) => (VolumeParameter<float>)(object)c.FogViewDistance), 50f) : 50f); float num2 = godRays switch { GodRays.Off => 3000f, GodRays.Normal => Mathf.Clamp(num * 0.6f, 40f, 150f), GodRays.Strong => Mathf.Clamp(num * 0.4f, 30f, 100f), _ => 0f, }; float num3 = (on ? Weather.VolumetricFog : 0f); if (num3 > 0f) { num2 = ((num2 > 0f) ? Mathf.Min(num2, num3) : num3); } if (num2 > 0f) { P((VolumeParameter<float>)(object)volumetrics.FogViewDistance, num2); } else { Off((VolumeParameter)(object)volumetrics.FogViewDistance); } flag = on; if (flag) { bool flag2 = (uint)(godRays - 2) <= 1u; flag = flag2; } if (flag) { P((VolumeParameter<float>)(object)volumetrics.GlobalStaticLightMultiplier, (godRays == GodRays.Strong) ? 1.5f : 1.25f); } else { Off((VolumeParameter)(object)volumetrics.GlobalStaticLightMultiplier); } if (num3 > 0f) { P((VolumeParameter<float>)(object)volumetrics.FogBaseHeight, -10000f); P((VolumeParameter<float>)(object)volumetrics.FogMaxHeight, 10000f); P<Color>((VolumeParameter<Color>)(object)volumetrics.VolumetricAlbedo, Weather.FogAlbedo); } else { Off((VolumeParameter)(object)volumetrics.FogBaseHeight); Off((VolumeParameter)(object)volumetrics.FogMaxHeight); Off((VolumeParameter)(object)volumetrics.VolumetricAlbedo); } Cubemap val = (on ? Weather.SkyCube : null); if ((Object)(object)val != (Object)null) { P<Texture>((VolumeParameter<Texture>)(object)volumetrics.SkyTexture, (Texture)(object)val); P((VolumeParameter<bool>)(object)volumetrics.isNullSky, v: false); } else { Off((VolumeParameter)(object)volumetrics.SkyTexture); Off((VolumeParameter)(object)volumetrics.isNullSky); } } } public static string Describe() { //IL_012e: 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_01fc: 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) if ((Object)(object)volume == (Object)null) { return "volume not created"; } try { VolumeStack stack = VolumeManager.instance.stack; VolumeComponent component = stack.GetComponent(Il2CppType.Of<MKGlow>()); MKGlow val = ((component != null) ? ((Il2CppObjectBase)component).TryCast<MKGlow>() : null); VolumeComponent component2 = stack.GetComponent(Il2CppType.Of<HBAO>()); HBAO val2 = ((component2 != null) ? ((Il2CppObjectBase)component2).TryCast<HBAO>() : null); VolumeComponent component3 = stack.GetComponent(Il2CppType.Of<Tonemapping>()); Tonemapping val3 = ((component3 != null) ? ((Il2CppObjectBase)component3).TryCast<Tonemapping>() : null); VolumeComponent component4 = stack.GetComponent(Il2CppType.Of<Volumetrics>()); Volumetrics val4 = ((component4 != null) ? ((Il2CppObjectBase)component4).TryCast<Volumetrics>() : null); return $"volume layer {Layer}, priority {volume.priority}; stack: " + (((Object)(object)val != (Object)null) ? $"MKGlow {((VolumeParameter<float>)(object)val.bloomIntensity).value:0.0} q{((VolumeParameter<Quality>)(object)val.quality).value} flare {((VolumeParameter<bool>)(object)val.allowLensFlare).value} glare {((VolumeParameter<bool>)(object)val.allowGlare).value}; " : "no MKGlow; ") + (((Object)(object)val2 != (Object)null) ? $"HBAO {((VolumeParameter<float>)(object)val2.intensity).value:0.0} {((VolumeParameter<Quality>)(object)val2.quality).value} {((VolumeParameter<Mode>)(object)val2.mode).value} bleed {((VolumeParameter<bool>)(object)val2.colorBleedingEnabled).value}; " : "no HBAO; ") + (((Object)(object)val3 != (Object)null) ? $"tonemap {((VolumeParameter<TonemappingMode>)(object)val3.mode).value}; " : "") + (((Object)(object)val4 != (Object)null) ? $"volumetric fog {((VolumeParameter<float>)(object)val4.FogViewDistance).value:0} m, light x{((VolumeParameter<float>)(object)val4.GlobalStaticLightMultiplier).value:0.00}" : ""); } catch (Exception ex) { return "stack: " + ex.Message; } } } public static class Presets { public static bool Applying { get; private set; } public static string Describe(Preset p) { return p switch { Preset.Vanilla => "the game as it is (weather still works)", Preset.Performance => "more FPS: lower resolution with auto scaling, no AO and reflections, short shadows", Preset.Balanced => "better picture at the same FPS: auto resolution, AF16, finer bloom, light color grading", Preset.Quality => "sharper and richer: higher resolution, ACES, better shadows, AO and reflections", Preset.Ultra => "max quality: supersampling, ultra shadows, long detail distance, lens flares", Preset.RTX => "fake ray tracing: supersampling, GI-like AO color bleeding, high reflections, glare, lens dirt", _ => "your own settings", }; } public static void Apply(Preset p) { if (p == Preset.Custom) { return; } Applying = true; try { Settings.ResMode = ResMode.Game; Settings.Resolution = 1.1f; Settings.MinResolution = 0.8f; Settings.Msaa = Msaa.Game; Settings.Shadows = Quality4.Game; Settings.Ao = AoMode.Game; Settings.Ssr = Reflections.Game; Settings.Textures = TexMode.Game; Settings.Detail = Detail.Game; Settings.Sharpen = 0f; Settings.Bloom = BloomMode.Game; Settings.BloomQuality = Quality4.Game; Settings.LensFlare = false; Settings.Glare = false; Settings.LensDirt = false; Settings.Tonemap = ToneMap.Game; Settings.Exposure = 0f; Settings.Contrast = 0f; Settings.Saturation = 0f; Settings.Temperature = 0f; Settings.Vignette = 0f; Settings.Chroma = 0f; Settings.Grain = 0f; Settings.GodRays = GodRays.Game; switch (p) { case Preset.Performance: Settings.ResMode = ResMode.Auto; Settings.Resolution = 1f; Settings.MinResolution = 0.7f; Settings.Msaa = Msaa.X2; Settings.Shadows = Quality4.Low; Settings.Ao = AoMode.Off; Settings.Ssr = Reflections.Off; Settings.Detail = Detail.Near; Settings.Bloom = BloomMode.Soft; Settings.BloomQuality = Quality4.Low; Settings.GodRays = GodRays.Off; break; case Preset.Balanced: Settings.ResMode = ResMode.Auto; Settings.Resolution = 1.1f; Settings.MinResolution = 0.8f; Settings.Textures = TexMode.AF16; Settings.Detail = Detail.Normal; Settings.Bloom = BloomMode.Normal; Settings.BloomQuality = Quality4.Medium; Settings.Contrast = 5f; Settings.Saturation = 5f; Settings.Vignette = 0.12f; break; case Preset.Quality: Settings.ResMode = ResMode.Auto; Settings.Resolution = 1.25f; Settings.MinResolution = 0.9f; Settings.Msaa = Msaa.X4; Settings.Shadows = Quality4.High; Settings.Ao = AoMode.High; Settings.Ssr = Reflections.On; Settings.Textures = TexMode.Sharp; Settings.Detail = Detail.Far; Settings.Bloom = BloomMode.Normal; Settings.BloomQuality = Quality4.High; Settings.Tonemap = ToneMap.ACES; Settings.Exposure = 0.15f; Settings.Contrast = 8f; Settings.Saturation = 8f; Settings.Vignette = 0.15f; Settings.GodRays = GodRays.Normal; break; case Preset.Ultra: Settings.ResMode = ResMode.Auto; Settings.Resolution = 1.4f; Settings.MinResolution = 1f; Settings.Msaa = Msaa.X4; Settings.Shadows = Quality4.Ultra; Settings.Ao = AoMode.High; Settings.Ssr = Reflections.High; Settings.Textures = TexMode.UltraSharp; Settings.Detail = Detail.Ultra; Settings.Bloom = BloomMode.Normal; Settings.BloomQuality = Quality4.Ultra; Settings.LensFlare = true; Settings.Tonemap = ToneMap.ACES; Settings.Exposure = 0.15f; Settings.Contrast = 10f; Settings.Saturation = 10f; Settings.Vignette = 0.15f; Settings.GodRays = GodRays.Normal; break; case Preset.RTX: Settings.ResMode = ResMode.Auto; Settings.Resolution = 1.5f; Settings.MinResolution = 1f; Settings.Msaa = Msaa.X4; Settings.Shadows = Quality4.Ultra; Settings.Ao = AoMode.UltraGI; Settings.Ssr = Reflections.High; Settings.Textures = TexMode.UltraSharp; Settings.Detail = Detail.Ultra; Settings.Bloom = BloomMode.Strong; Settings.BloomQuality = Quality4.Ultra; Settings.LensFlare = true; Settings.Glare = true; Settings.LensDirt = true; Settings.Tonemap = ToneMap.ACES; Settings.Exposure = 0.2f; Settings.Contrast = 12f; Settings.Saturation = 12f; Settings.Vignette = 0.2f; Settings.Chroma = 0.06f; Settings.GodRays = GodRays.Strong; break; } } finally { Applying = false; } Settings.Preset = p; } } public enum Preset { Vanilla, Performance, Balanced, Quality, Ultra, RTX, Custom } public enum ResMode { Game, Fixed, Auto } public enum Msaa { Game, Off, X2, X4, X8 } public enum Quality4 { Game, Low, Medium, High, Ultra } public enum AoMode { Game, Off, Low, Medium, High, UltraGI } public enum Reflections { Game, Off, On, High } public enum TexMode { Game, AF16, Sharp, UltraSharp } public enum Detail { Game, Near, Normal, Far, Ultra } public enum BloomMode { Game, Off, Soft, Normal, Strong } public enum ToneMap { Game, Neutral, ACES, Off } public enum GodRays { Game, Off, Normal, Strong } public enum WeatherType { Level, Sunny, Clear, Cloudy, Overcast, Fog, Rain, Storm, Snow, Sunset, Night } public static class Settings { private static MelonPreferences_Category cat; private static bool loading; private static MelonPreferences_Entry<bool> enabled; private static MelonPreferences_Entry<bool> lensFlare; private static MelonPreferences_Entry<bool> glare; private static MelonPreferences_Entry<bool> lensDirt; private static MelonPreferences_Entry<bool> weatherSound; private static MelonPreferences_Entry<bool> lightning; private static MelonPreferences_Entry<string> preset; private static MelonPreferences_Entry<string> resMode; private static MelonPreferences_Entry<string> msaa; private static MelonPreferences_Entry<string> shadows; private static MelonPreferences_Entry<string> ao; private static MelonPreferences_Entry<string> ssr; private static MelonPreferences_Entry<string> tex; private static MelonPreferences_Entry<string> detail; private static MelonPreferences_Entry<string> bloom; private static MelonPreferences_Entry<string> bloomQuality; private static MelonPreferences_Entry<string> tonemap; private static MelonPreferences_Entry<string> godRays; private static MelonPreferences_Entry<string> weather; private static MelonPreferences_Entry<float> resolution; private static MelonPreferences_Entry<float> minResolution; private static MelonPreferences_Entry<float> sharpen; private static MelonPreferences_Entry<float> exposure; private static MelonPreferences_Entry<float> contrast; private static MelonPreferences_Entry<float> saturation; private static MelonPreferences_Entry<float> temperature; private static MelonPreferences_Entry<float> vignette; private static MelonPreferences_Entry<float> chroma; private static MelonPreferences_Entry<float> grain; private static MelonPreferences_Entry<float> weatherIntensity; private static MelonPreferences_Entry<float> weatherVolume; public static bool Enabled { get { return enabled.Value; } set { enabled.Value = value; Touch(custom: false); } } public static Preset Preset { get { return E(preset, Preset.Balanced); } set { preset.Value = value.ToString(); Touch(custom: false); } } public static ResMode ResMode { get { return E(resMode, ResMode.Auto); } set { SetE(resMode, value); } } public static float Resolution { get { return Clamp(resolution.Value, 0.5f, 2f); } set { resolution.Value = Clamp(value, 0.5f, 2f); Touch(custom: true); } } public static float MinResolution { get { return Clamp(minResolution.Value, 0.5f, 2f); } set { minResolution.Value = Clamp(value, 0.5f, 2f); Touch(custom: true); } } public static Msaa Msaa { get { return E(msaa, Msaa.Game); } set { SetE(msaa, value); } } public static Quality4 Shadows { get { return E(shadows, Quality4.Game); } set { SetE(shadows, value); } } public static AoMode Ao { get { return E(ao, AoMode.Game); } set { SetE(ao, value); } } public static Reflections Ssr { get { return E(ssr, Reflections.Game); } set { SetE(ssr, value); } } public static TexMode Textures { get { return E(tex, TexMode.Game); } set { SetE(tex, value); } } public static Detail Detail { get { return E(detail, Detail.Game); } set { SetE(detail, value); } } public static float Sharpen { get { return Clamp(sharpen.Value, 0f, 1f); } set { sharpen.Value = Clamp(value, 0f, 1f); Touch(custom: true); } } public static BloomMode Bloom { get { return E(bloom, BloomMode.Game); } set { SetE(bloom, value); } } public static Quality4 BloomQuality { get { return E(bloomQuality, Quality4.Game); } set { SetE(bloomQuality, value); } } public static bool LensFlare { get { return lensFlare.Value; } set { lensFlare.Value = value; Touch(custom: true); } } public static bool Glare { get { return glare.Value; } set { glare.Value = value; Touch(custom: true); } } public static bool LensDirt { get { return lensDirt.Value; } set { lensDirt.Value = value; Touch(custom: true); } } public static ToneMap Tonemap { get { return E(tonemap, ToneMap.Game); } set { SetE(tonemap, value); } } public static float Exposure { get { return Clamp(exposure.Value, -2f, 2f); } set { exposure.Value = Clamp(value, -2f, 2f); Touch(custom: true); } } public static float Contrast { get { return Clamp(contrast.Value, -50f, 50f); } set { contrast.Value = Clamp(value, -50f, 50f); Touch(custom: true); } } public static float Saturation { get { return Clamp(saturation.Value, -50f, 50f); } set { saturation.Value = Clamp(value, -50f, 50f); Touch(custom: true); } } public static float Temperature { get { return Clamp(temperature.Value, -50f, 50f); } set { temperature.Value = Clamp(value, -50f, 50f); Touch(custom: true); } } public static float Vignette { get { return Clamp(vignette.Value, 0f, 0.6f); } set { vignette.Value = Clamp(value, 0f, 0.6f); Touch(custom: true); } } public static float Chroma { get { return Clamp(chroma.Value, 0f, 1f); } set { chroma.Value = Clamp(value, 0f, 1f); Touch(custom: true); } } public static float Grain { get { return Clamp(grain.Value, 0f, 1f); } set { grain.Value = Clamp(value, 0f, 1f); Touch(custom: true); } } public static GodRays GodRays { get { return E(godRays, GodRays.Game); } set { SetE(godRays, value); } } public static WeatherType Weather { get { return E(weather, WeatherType.Level); } set { SetE(weather, value, custom: false); } } public static float WeatherIntensity { get { return Clamp(weatherIntensity.Value, 0.25f, 1.5f); } set { weatherIntensity.Value = Clamp(value, 0.25f, 1.5f); Touch(custom: false); } } public static bool WeatherSound { get { return weatherSound.Value; } set { weatherSound.Value = value; Touch(custom: false); } } public static float WeatherVolume { get { return Clamp(weatherVolume.Value, 0f, 1f); } set { weatherVolume.Value = Clamp(value, 0f, 1f); Touch(custom: false); } } public static bool Lightning { get { return lightning.Value; } set { lightning.Value = value; Touch(custom: false); } } public static event Action Changed; public static void Init() { loading = true; cat = MelonPreferences.CreateCategory("BetterLab", "BetterLab"); enabled = cat.CreateEntry<bool>("Enabled", true, "BetterLab on/off", (string)null, false, false, (ValueValidator)null, (string)null); preset = cat.CreateEntry<string>("Preset", "Balanced", "Vanilla, Performance, Balanced, Quality, Ultra, RTX, Custom", (string)null, false, false, (ValueValidator)null, (string)null); resMode = cat.CreateEntry<string>("ResolutionMode", "Auto", "Game, Fixed, Auto (dynamic resolution keeps the headset frame rate)", (string)null, false, false, (ValueValidator)null, (string)null); resolution = cat.CreateEntry<float>("Resolution", 1.1f, "Render scale (Fixed) or the highest render scale (Auto), 0.5..2", (string)null, false, false, (ValueValidator)null, (string)null); minResolution = cat.CreateEntry<float>("MinResolution", 0.8f, "Lowest render scale in Auto mode", (string)null, false, false, (ValueValidator)null, (string)null); msaa = cat.CreateEntry<string>("MSAA", "Game", "Game, Off, X2, X4, X8", (string)null, false, false, (ValueValidator)null, (string)null); shadows = cat.CreateEntry<string>("Shadows", "Game", "Game, Low, Medium, High, Ultra", (string)null, false, false, (ValueValidator)null, (string)null); ao = cat.CreateEntry<string>("AmbientOcclusion", "Game", "Game, Off, Low, Medium, High, UltraGI", (string)null, false, false, (ValueValidator)null, (string)null); ssr = cat.CreateEntry<string>("Reflections", "Game", "Screen-space reflections: Game, Off, On, High", (string)null, false, false, (ValueValidator)null, (string)null); tex = cat.CreateEntry<string>("Textures", "AF16", "Game, AF16, Sharp, UltraSharp", (string)null, false, false, (ValueValidator)null, (string)null); detail = cat.CreateEntry<string>("DetailDistance", "Normal", "LOD distance: Game, Near, Normal, Far, Ultra", (string)null, false, false, (ValueValidator)null, (string)null); sharpen = cat.CreateEntry<float>("Sharpen", 0f, "FSR sharpening 0..1 (0 = off)", (string)null, false, false, (ValueValidator)null, (string)null); bloom = cat.CreateEntry<string>("Bloom", "Normal", "Game, Off, Soft, Normal, Strong", (string)null, false, false, (ValueValidator)null, (string)null); bloomQuality = cat.CreateEntry<string>("BloomQuality", "Medium", "Game, Low, Medium, High, Ultra", (string)null, false, false, (ValueValidator)null, (string)null); lensFlare = cat.CreateEntry<bool>("LensFlare", false, "", (string)null, false, false, (ValueValidator)null, (string)null); glare = cat.CreateEntry<bool>("Glare", false, "Anamorphic light streaks", (string)null, false, false, (ValueValidator)null, (string)null); lensDirt = cat.CreateEntry<bool>("LensDirt", false, "", (string)null, false, false, (ValueValidator)null, (string)null); tonemap = cat.CreateEntry<string>("Tonemapping", "Game", "Game, Neutral, ACES, Off", (string)null, false, false, (ValueValidator)null, (string)null); exposure = cat.CreateEntry<float>("Exposure", 0f, "EV, -2..2", (string)null, false, false, (ValueValidator)null, (string)null); contrast = cat.CreateEntry<float>("Contrast", 5f, "-50..50", (string)null, false, false, (ValueValidator)null, (string)null); saturation = cat.CreateEntry<float>("Saturation", 5f, "-50..50", (string)null, false, false, (ValueValidator)null, (string)null); temperature = cat.CreateEntry<float>("Temperature", 0f, "-50..50", (string)null, false, false, (ValueValidator)null, (string)null); vignette = cat.CreateEntry<float>("Vignette", 0.12f, "0..0.6", (string)null, false, false, (ValueValidator)null, (string)null); chroma = cat.CreateEntry<float>("ChromaticAberration", 0f, "0..1", (string)null, false, false, (ValueValidator)null, (string)null); grain = cat.CreateEntry<float>("FilmGrain", 0f, "0..1", (string)null, false, false, (ValueValidator)null, (string)null); godRays = cat.CreateEntry<string>("GodRays", "Game", "Volumetric light: Game, Off, Normal, Strong", (string)null, false, false, (ValueValidator)null, (string)null); weather = cat.CreateEntry<string>("Weather", "Level", "Level, Sunny, Clear, Cloudy, Overcast, Fog, Rain, Storm, Snow, Sunset, Night", (string)null, false, false, (ValueValidator)null, (string)null); weatherIntensity = cat.CreateEntry<float>("WeatherIntensity", 1f, "0.25..1.5", (string)null, false, false, (ValueValidator)null, (string)null); weatherSound = cat.CreateEntry<bool>("WeatherSound", true, "Rain, wind and thunder sounds", (string)null, false, false, (ValueValidator)null, (string)null); weatherVolume = cat.CreateEntry<float>("WeatherVolume", 0.8f, "0..1", (string)null, false, false, (ValueValidator)null, (string)null); lightning = cat.CreateEntry<bool>("Lightning", true, "Lightning in storms", (string)null, false, false, (ValueValidator)null, (string)null); loading = false; } private static T E<T>(MelonPreferences_Entry<string> e, T def) where T : struct, Enum { if (!Enum.TryParse<T>(e.Value, out var result)) { return def; } return result; } private static void SetE<T>(MelonPreferences_Entry<string> e, T v, bool custom = true) where T : struct, Enum { e.Value = v.ToString(); Touch(custom); } private static void Touch(bool custom) { if (!loading) { if (custom && !Presets.Applying && Preset != Preset.Custom) { preset.Value = Preset.Custom.ToString(); } if (!Presets.Applying) { MelonPreferences.Save(); Settings.Changed?.Invoke(); } } } private static float Clamp(float v, float lo, float hi) { return Math.Clamp(v, lo, hi); } public static void Save() { MelonPreferences.Save(); Settings.Changed?.Invoke(); } } public struct WeatherDef { public Grade grade; public float fog; public float volExt; public float skyAlpha; public float coverage; public float cloudAlpha; public float softness; public float stars; public float sun; public float sunTintAmount; public float rain; public float snow; public float wind; public float lightning; public float useCube; public Color fogColor; public Color albedo; public Color zenith; public Color horizon; public Color ground; public Color cloud; public Color shade; public Color sunGlow; public Color sunTint; public static WeatherDef Lerp(WeatherDef a, WeatherDef b, float t) { //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: 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_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: 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_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) return new WeatherDef { grade = Grade.Lerp(a.grade, b.grade, t), fog = Mathf.Lerp(a.fog, b.fog, t), volExt = Mathf.Lerp(a.volExt, b.volExt, t), skyAlpha = Mathf.Lerp(a.skyAlpha, b.skyAlpha, t), coverage = Mathf.Lerp(a.coverage, b.coverage, t), cloudAlpha = Mathf.Lerp(a.cloudAlpha, b.cloudAlpha, t), softness = Mathf.Lerp(a.softness, b.softness, t), stars = Mathf.Lerp(a.stars, b.stars, t), sun = Mathf.Lerp(a.sun, b.sun, t), sunTintAmount = Mathf.Lerp(a.sunTintAmount, b.sunTintAmount, t), rain = Mathf.Lerp(a.rain, b.rain, t), snow = Mathf.Lerp(a.snow, b.snow, t), wind = Mathf.Lerp(a.wind, b.wind, t), lightning = Mathf.Lerp(a.lightning, b.lightning, t), useCube = Mathf.Lerp(a.useCube, b.useCube, t), fogColor = Color.Lerp(a.fogColor, b.fogColor, t), albedo = Color.Lerp(a.albedo, b.albedo, t), zenith = Color.Lerp(a.zenith, b.zenith, t), horizon = Color.Lerp(a.horizon, b.horizon, t), ground = Color.Lerp(a.ground, b.ground, t), cloud = Color.Lerp(a.cloud, b.cloud, t), shade = Color.Lerp(a.shade, b.shade, t), sunGlow = Color.Lerp(a.sunGlow, b.sunGlow, t), sunTint = Color.Lerp(a.sunTint, b.sunTint, t) }; } } public static class Weather { private const float Transition = 5f; private const float RainHeight = 12f; private const float SnowHeight = 8f; private const int RoofMask = -2147482543; private static WeatherType target = WeatherType.Level; private static WeatherDef from; private static WeatherDef to; private static WeatherDef cur; private static float t = 1f; private static float intensity = -1f; private static bool started; private static bool levelCaptured; private static bool lvFog; private static FogMode lvFogMode; private static float lvFogDensity; private static Color lvFogColor; private static Light sun; private static float sunIntensity; private static Color sunColor; private static GameObject root; private static GameObject dome; private static GameObject rainGo; private static GameObject snowGo; private static GameObject audioGo; private static GameObject thunderGo; private static GameObject boltGo; private static Material domeMat; private static ParticleSystem rainPs; private static ParticleSystem snowPs; private static float rainBase = 4000f; private static float snowBase = 1100f; private static AudioSource rainA; private static AudioSource rainB; private static AudioSource windSrc; private static AudioSource thunderSrc; private static AudioLowPassFilter rainLp; private static AudioLowPassFilter thunderLp; private static AudioClip[] thunderClips; private static Light bolt; private static Cubemap cube; private static Il2CppStructArray<Color> cubePx; private static float cubeAt = -10f; private static Vector3 lastHead; private static Vector3 headVel; private static float indoor; private static float indoorTarget; private static float roofCheckAt; private static float roofHeight = -1f; private static float nextStrike = 8f; private static float strikeAt = -10f; private static float strikePower; private static readonly List<(float at, AudioClip clip, float vol)> pendingThunder = new List<(float, AudioClip, float)>(); private static float flash; public static bool Active { get { if (Settings.Enabled) { if (target == WeatherType.Level) { return t < 1f; } return true; } return false; } } public static Grade Grade { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return new Grade { filter = Color.white }; } return cur.grade; } } public static float Flash { get { if (!Active) { return 0f; } return flash; } } public static float VolumetricFog { get { if (!Active || !(cur.volExt > 0.0005f)) { return 0f; } return 1f / cur.volExt; } } public static Color FogAlbedo => cur.albedo; public static Cubemap SkyCube { get { if (!Active || !(cur.useCube > 0.5f)) { return null; } return cube; } } public static bool Animating { get { if (Active) { if (!(t < 1f) && !(flash > 0f)) { return Time.time - strikeAt < 1f; } return true; } return false; } } private static Color C(float r, float g, float b) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return new Color(r, g, b, 1f); } private static WeatherDef Neutral() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) return new WeatherDef { grade = new Grade { filter = Color.white }, fog = ((lvFog && (int)lvFogMode == 3) ? lvFogDensity : 0f), fogColor = lvFogColor, albedo = Color.white, zenith = C(0.4f, 0.5f, 0.65f), horizon = lvFogColor, ground = lvFogColor, cloud = Color.white, shade = C(0.5f, 0.5f, 0.5f), sunTint = Color.white, sun = 1f, softness = 0.2f }; } private static WeatherDef Def(WeatherType w) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unkno