Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Flash light Enhanced v1.0.0
Mods/FlashLightEnhanced.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.RegularExpressions; using FlashLightEnhanced; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.UI.Phone; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using S1API.Internal.Abstraction; using S1API.PhoneApp; using S1API.UI; using S1API.Utils; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(/*Could not decode attribute arguments.*/)] [assembly: MelonInfo(typeof(Mod), "Flash light Enhanced", "0.4.0", "Reborn Reaper", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: AssemblyTitle("Flash light Enhanced")] [assembly: AssemblyProduct("Flash light Enhanced")] [assembly: AssemblyFileVersion("0.4.0.0")] [assembly: AssemblyVersion("0.4.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : System.Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(/*Could not decode attribute arguments.*/)] internal sealed class NullableAttribute : System.Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(/*Could not decode attribute arguments.*/)] internal sealed class NullableContextAttribute : System.Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(/*Could not decode attribute arguments.*/)] internal sealed class RefSafetyRulesAttribute : System.Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FlashLightEnhanced { public sealed class FlashlightSettings { [field: CompilerGenerated] public bool Enabled { [CompilerGenerated] get; [CompilerGenerated] set; } = true; [field: CompilerGenerated] public string LightColor { [CompilerGenerated] get; [CompilerGenerated] set; } = "#FFFFFF"; [field: CompilerGenerated] public float Intensity { [CompilerGenerated] get; [CompilerGenerated] set; } = 3f; [field: CompilerGenerated] public float Range { [CompilerGenerated] get; [CompilerGenerated] set; } = 40f; [field: CompilerGenerated] public float SpotAngle { [CompilerGenerated] get; [CompilerGenerated] set; } = 80f; public FlashlightSettings Copy() { return (FlashlightSettings)base.MemberwiseClone(); } public void RestoreAppearanceDefaults() { FlashlightSettings flashlightSettings = new FlashlightSettings(); LightColor = flashlightSettings.LightColor; Intensity = flashlightSettings.Intensity; Range = flashlightSettings.Range; SpotAngle = flashlightSettings.SpotAngle; } public void Validate() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (LightColor == null || !Regex.IsMatch(LightColor, "\\A#[0-9a-fA-F]{6}\\z")) { throw new FormatException("LightColor must use #RRGGBB, for example #FFFFFF."); } Check(Intensity, 0f, 10f, "Intensity"); Check(Range, 1f, 200f, "Range"); Check(SpotAngle, 1f, 179f, "SpotAngle"); } private static void Check(float value, float min, float max, string name) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (float.IsNaN(value) || float.IsInfinity(value) || value < min || value > max) { throw new FormatException($"{name} must be between {min} and {max}."); } } } public sealed class LumenApp : PhoneApp { private static LumenApp? current; private static Sprite? icon; private static readonly Color Background = new Color(0.018f, 0.022f, 0.018f, 1f); private static readonly Color Card = new Color(0.055f, 0.067f, 0.055f, 1f); private static readonly Color Accent = new Color(0.5f, 1f, 0f, 1f); private static readonly Color Muted = new Color(0.64f, 0.71f, 0.62f, 1f); private InputField hue; private InputField output; private InputField projection; private InputField spread; private Text enabledLabel; private Text status; private Image enabledImage; private Image swatch; private GameObject? root; private bool draftEnabled; private bool dirty; private bool syncing; private bool wasOpen; private bool ownsTyping; private int loadedRevision = -1; private int fontSize; private float nextError; protected override string AppName => "FlashLightEnhanced_Lumen"; protected override string AppTitle => "Lumen"; protected override string IconLabel => "Lumen"; protected override string IconFileName => "FlashLightEnhanced/Lumen.png"; protected override Sprite? IconSprite => LoadIcon(); private SettingsStore Store => Mod.SharedSettings ?? throw new InvalidOperationException("Settings are not ready."); protected override void OnCreatedUI(GameObject container) { //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Expected O, but got Unknown //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Expected O, but got Unknown //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Expected O, but got Unknown //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) root = container; current = this; Rect rect = container.GetComponent<RectTransform>().rect; fontSize = Mathf.Clamp(Mathf.RoundToInt(((Rect)(ref rect)).height * 0.038f), 12, 30); Image obj = container.AddComponent<Image>(); ((Graphic)obj).color = Background; ((Graphic)obj).raycastTarget = true; Image component = Panel("Icon", container.transform, Color.white, 0.035f, 0.845f, 0.14f, 0.98f).GetComponent<Image>(); component.sprite = LoadIcon(); component.preserveAspect = true; Label("Title", "LUMEN", container.transform, 0.17f, 0.89f, 0.75f, 0.98f, fontSize + 12, Accent); Label("Subtitle", "FLASHLIGHT ENHANCED", container.transform, 0.17f, 0.835f, 0.75f, 0.9f, fontSize - 3, Muted); MakeButton("Back", "Back", container.transform, 0.85f, 0.87f, 0.96f, 0.96f, (Action)([CompilerGenerated] () => { ReleaseTyping(); ((PhoneApp)this).CloseApp(); })); status = Label("Status", "Changes are saved when you press Apply.", container.transform, 0.04f, 0.77f, 0.96f, 0.825f, fontSize - 3, Muted); GameObject val = Row("Enabled", "Custom appearance", container.transform, 0.65f, 0.75f); GameObject val2 = MakeButton("Enabled", "", val.transform, 0.69f, 0.14f, 0.97f, 0.86f, (Action)([CompilerGenerated] () => { draftEnabled = !draftEnabled; UpdateEnabled(); MarkDirty(); })); enabledImage = val2.GetComponent<Image>(); enabledLabel = val2.GetComponentInChildren<Text>(); GameObject val3 = Row("Hue", "Colour / #RRGGBB", container.transform, 0.52f, 0.63f); hue = Field("Hue", val3.transform, 0.61f, 0.15f, 0.91f, 0.85f); swatch = Panel("ColourPreview", val3.transform, Color.white, 0.93f, 0.19f, 0.98f, 0.81f).GetComponent<Image>(); MakeButton("Green", "Green", val3.transform, 0.31f, 0.18f, 0.44f, 0.82f, (Action)([CompilerGenerated] () => { hue.text = "#80FF00"; })); MakeButton("White", "White", val3.transform, 0.46f, 0.18f, 0.59f, 0.82f, (Action)([CompilerGenerated] () => { hue.text = "#FFFFFF"; })); output = NumberRow("Output", "Brightness / 0-10", container.transform, 0.39f, 0.5f, 0.5f, 0f, 10f); projection = NumberRow("Projection", "Distance / 1-200", container.transform, 0.26f, 0.37f, 5f, 1f, 200f); spread = NumberRow("Spread", "Degrees / 1-179", container.transform, 0.13f, 0.24f, 5f, 1f, 179f); MakeButton("Defaults", "Restore defaults", container.transform, 0.04f, 0.025f, 0.37f, 0.105f, new Action(RestoreDefaults)); GameObject obj2 = MakeButton("Apply", "Apply", container.transform, 0.7f, 0.025f, 0.96f, 0.105f, new Action(Apply)); ((Graphic)obj2.GetComponent<Image>()).color = Accent; ((Graphic)obj2.GetComponentInChildren<Text>()).color = Background; LoadSettings(); Mod.LogInfo("Lumen phone interface created."); } internal static void TickCurrent() { LumenApp lumenApp = current; if (lumenApp == null) { return; } try { lumenApp.Tick(); } catch (System.Exception ex) { lumenApp.ReleaseTyping(); if (Time.realtimeSinceStartup >= lumenApp.nextError) { lumenApp.nextError = Time.realtimeSinceStartup + 30f; Mod.LogWarning("Lumen UI update failed: " + ex.Message); } } } private void Tick() { if ((Object)(object)root == (Object)null) { ShutdownCurrent(); return; } bool flag = ((PhoneApp)this).IsOpen(); if (flag && !wasOpen) { Store.Reload(); LoadSettings(); } if (flag && !dirty && loadedRevision != Store.Revision) { LoadSettings(); } if (flag) { if (hue.isFocused || output.isFocused || projection.isFocused || spread.isFocused) { GameInput.IsTyping = true; ownsTyping = true; } else { ReleaseTyping(); } } else { ReleaseTyping(); } wasOpen = flag; } protected override void OnPhoneClosed() { ReleaseTyping(); } protected override void OnDestroyed() { ReleaseTyping(); if (current == this) { current = null; } ((PhoneApp)this).OnDestroyed(); root = null; hue = (output = (projection = (spread = null))); enabledLabel = (status = null); enabledImage = (swatch = null); } internal static void ShutdownCurrent() { LumenApp lumenApp = current; current = null; if (lumenApp == null) { return; } try { ((Registerable)lumenApp).OnDestroyed(); } catch (System.Exception ex) { Mod.LogWarning("Lumen cleanup: " + ex.Message); } } private void ReleaseTyping() { if (ownsTyping) { GameInput.IsTyping = false; ownsTyping = false; } } private void MarkDirty() { if (!syncing) { dirty = true; Message("Unsaved changes - press Apply.", error: false); UpdateSwatch(); } } private void LoadSettings() { syncing = true; try { FlashlightSettings flashlightSettings = Store.Current; draftEnabled = flashlightSettings.Enabled; hue.text = flashlightSettings.LightColor; output.text = Format(flashlightSettings.Intensity); projection.text = Format(flashlightSettings.Range); spread.text = Format(flashlightSettings.SpotAngle); loadedRevision = Store.Revision; dirty = false; UpdateEnabled(); UpdateSwatch(); Message("Changes are saved when you press Apply.", error: false); } finally { syncing = false; } } private void Apply() { Store.Reload(); if (loadedRevision != Store.Revision) { Message("Settings changed elsewhere. Close and reopen Lumen before applying.", error: true); return; } if (!LumenDraft.TryBuild(draftEnabled, hue.text, output.text, projection.text, spread.text, out FlashlightSettings settings, out string error)) { Message(error, error: true); return; } if (!Store.TrySave(settings)) { Message("Save failed. Previous settings retained; check the mod log.", error: true); return; } LoadSettings(); Message("Saved. Your flashlight settings are up to date.", error: false); ReleaseTyping(); } private void RestoreDefaults() { Store.Reload(); FlashlightSettings flashlightSettings = Store.Current.Copy(); flashlightSettings.RestoreAppearanceDefaults(); if (!Store.TrySave(flashlightSettings)) { Message("Could not restore defaults; previous settings retained.", error: true); return; } LoadSettings(); Message("Defaults restored. Enabled is unchanged.", error: false); ReleaseTyping(); } private void UpdateEnabled() { //IL_0034: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) enabledLabel.text = (draftEnabled ? "Enabled" : "Disabled"); ((Graphic)enabledLabel).color = (draftEnabled ? Background : Muted); ((Graphic)enabledImage).color = (Color)(draftEnabled ? Accent : new Color(0.14f, 0.17f, 0.14f, 1f)); } private void UpdateSwatch() { //IL_0030: 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) if (!((Object)(object)swatch == (Object)null)) { Color val = default(Color); ((Graphic)swatch).color = (ColorUtility.TryParseHtmlString(hue.text, ref val) ? val : Color.gray); } } private void Message(string text, bool error) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) status.text = text; ((Graphic)status).color = (Color)(error ? new Color(1f, 0.47f, 0.35f, 1f) : Muted); } private InputField NumberRow(string title, string description, Transform parent, float bottom, float top, float step, float min, float max) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown GameObject val = Row(title, description, parent, bottom, top); InputField field = Field(title, val.transform, 0.54f, 0.15f, 0.83f, 0.85f); MakeButton("Minus", "-", val.transform, 0.4f, 0.15f, 0.51f, 0.85f, (Action)delegate { Adjust(0f - step); }); MakeButton("Plus", "+", val.transform, 0.86f, 0.15f, 0.97f, 0.85f, (Action)delegate { Adjust(step); }); return field; void Adjust(float delta) { float num = default(float); if (float.TryParse(field.text, (NumberStyles)167, (IFormatProvider)(object)CultureInfo.InvariantCulture, ref num) && !float.IsNaN(num) && !float.IsInfinity(num)) { field.text = Format(Mathf.Clamp(num + delta, min, max)); } } } private GameObject Row(string title, string description, Transform parent, float bottom, float top) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) GameObject val = Panel(title + "Row", parent, Card, 0.04f, bottom, 0.96f, top); Label(title + "Label", title, val.transform, 0.025f, 0.46f, 0.38f, 0.91f, fontSize, Color.white); Label(title + "Help", description, val.transform, 0.025f, 0.06f, 0.38f, 0.46f, fontSize - 4, Muted); return val; } private InputField Field(string name, Transform parent, float left, float bottom, float right, float top) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) GameObject val = Panel(name + "Input", parent, new Color(0.015f, 0.02f, 0.015f, 1f), left, bottom, right, top); Text val2 = Label("Text", "", val.transform, 0.05f, 0.05f, 0.95f, 0.95f, fontSize, Color.white); val2.alignment = (TextAnchor)4; InputField val3 = val.AddComponent<InputField>(); val3.textComponent = val2; ((Selectable)val3).targetGraphic = (Graphic)(object)val.GetComponent<Image>(); val3.lineType = (LineType)0; val3.characterLimit = 16; val3.caretColor = Accent; val3.customCaretColor = true; val3.selectionColor = new Color(0.3f, 0.6f, 0.1f, 0.6f); EventHelper.AddListener<string>((Action<string>)([CompilerGenerated] (string _) => { MarkDirty(); }), (UnityEvent<string>)(object)val3.onValueChanged); return val3; } private GameObject MakeButton(string name, string title, Transform parent, float left, float bottom, float right, float top, Action action) { //IL_0020: 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) GameObject val = Panel(name + "Button", parent, new Color(0.13f, 0.18f, 0.1f, 1f), left, bottom, right, top); Label("Label", title, val.transform, 0.03f, 0.03f, 0.97f, 0.97f, fontSize, Accent).alignment = (TextAnchor)4; Button val2 = val.AddComponent<Button>(); ((Selectable)val2).targetGraphic = (Graphic)(object)val.GetComponent<Image>(); EventHelper.AddListener(action, (UnityEvent)(object)val2.onClick); return val; } private static GameObject Panel(string name, Transform parent, Color colour, float left, float bottom, float right, float top) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown GameObject val = new GameObject(name); RectTransform obj = val.AddComponent<RectTransform>(); ((Transform)obj).SetParent(parent, false); obj.anchorMin = new Vector2(left, bottom); obj.anchorMax = new Vector2(right, top); Vector2 offsetMin = (obj.offsetMax = Vector2.zero); obj.offsetMin = offsetMin; val.layer = ((Component)parent).gameObject.layer; ((Graphic)val.AddComponent<Image>()).color = colour; return val; } private static Text Label(string name, string value, Transform parent, float left, float bottom, float right, float top, int size, Color colour) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Text obj = UIFactory.Text(name, value, parent, size, (TextAnchor)3, (FontStyle)0); RectTransform component = ((Component)obj).GetComponent<RectTransform>(); component.anchorMin = new Vector2(left, bottom); component.anchorMax = new Vector2(right, top); Vector2 offsetMin = (component.offsetMax = Vector2.zero); component.offsetMin = offsetMin; ((Component)obj).gameObject.layer = ((Component)parent).gameObject.layer; ((Graphic)obj).color = colour; ((Graphic)obj).raycastTarget = false; obj.supportRichText = false; obj.resizeTextForBestFit = true; obj.resizeTextMinSize = Math.Max(8, size - 5); obj.resizeTextMaxSize = size; return obj; } private static Sprite? LoadIcon() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)icon != (Object)null) { return icon; } Stream manifestResourceStream = typeof(LumenApp).Assembly.GetManifestResourceStream("FlashLightEnhanced.Lumen.png"); try { if (manifestResourceStream == null) { throw new InvalidOperationException("Embedded Lumen icon is missing."); } MemoryStream val = new MemoryStream(); try { manifestResourceStream.CopyTo((Stream)(object)val); Texture2D val2 = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val2, Il2CppStructArray<byte>.op_Implicit(val.ToArray()))) { Object.Destroy((Object)(object)val2); throw new InvalidOperationException("Could not decode the Lumen icon."); } ((Texture)val2).filterMode = (FilterMode)1; icon = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f)); return icon; } finally { ((System.IDisposable)val)?.Dispose(); } } finally { ((System.IDisposable)manifestResourceStream)?.Dispose(); } } private static string Format(float value) { return value.ToString("G", (IFormatProvider)(object)CultureInfo.InvariantCulture); } } internal static class LumenDraft { public static bool TryBuild(bool enabled, string hue, string output, string projection, string spread, out FlashlightSettings settings, out string error) { settings = new FlashlightSettings(); error = ""; if (!Read(output, "Output", 0f, 10f, out var value, out error) || !Read(projection, "Projection", 1f, 200f, out var value2, out error) || !Read(spread, "Spread", 1f, 179f, out var value3, out error)) { return false; } settings = new FlashlightSettings { Enabled = enabled, LightColor = hue.Trim().ToUpperInvariant(), Intensity = value, Range = value2, SpotAngle = value3 }; try { settings.Validate(); return true; } catch (FormatException) { error = "Hue must be #RRGGBB, for example #80FF00."; return false; } } private static bool Read(string text, string label, float min, float max, out float value, out string error) { error = ""; if (!float.TryParse(text, (NumberStyles)167, (IFormatProvider)(object)CultureInfo.InvariantCulture, ref value) || float.IsNaN(value) || float.IsInfinity(value) || value < min || value > max) { error = $"{label} must be {min} to {max}. Use a dot for decimals."; return false; } return true; } } internal sealed class MenuPreferences { private readonly SettingsStore store; private readonly MelonPreferences_Entry<bool> enabled; private readonly MelonPreferences_Entry<bool> restoreDefaults; private readonly MelonPreferences_Entry<string> hue; private readonly MelonPreferences_Entry<float> output; private readonly MelonPreferences_Entry<float> projection; private readonly MelonPreferences_Entry<float> spread; private bool synchronizing; private int revision = -1; public MenuPreferences(SettingsStore store) { this.store = store; MelonPreferences_Category val = MelonPreferences.CreateCategory("FlashLightEnhanced", "Flashlight settings"); FlashlightSettings flashlightSettings = new FlashlightSettings(); enabled = val.CreateEntry<bool>("Enabled", flashlightSettings.Enabled, "Enabled", "Enable custom lighting. Disable to restore the original flashlight settings.", false, false, (ValueValidator)null, (string)null); hue = val.CreateEntry<string>("Hue", flashlightSettings.LightColor, "Hue", "Beam colour in #RRGGBB format. White: #FFFFFF. Green: #00FF66.", false, false, (ValueValidator)null, (string)null); output = val.CreateEntry<float>("Output", flashlightSettings.Intensity, "Output", "Brightness, from 0 to 10.", false, false, (ValueValidator)null, (string)null); projection = val.CreateEntry<float>("Projection", flashlightSettings.Range, "Projection", "Beam distance, from 1 to 200.", false, false, (ValueValidator)null, (string)null); spread = val.CreateEntry<float>("Spread", flashlightSettings.SpotAngle, "Spread", "Beam angle in degrees, from 1 to 179.", false, false, (ValueValidator)null, (string)null); restoreDefaults = val.CreateEntry<bool>("RestoreDefaults", false, "Restore default settings", "Turn on once to restore Hue #FFFFFF, Output 3, Projection 40 and Spread 80. Keeps Enabled unchanged. Reopen this panel to refresh the displayed values.", false, true, (ValueValidator)null, (string)null); SyncFromStore(); ((MelonEventBase<LemonAction<bool, bool>>)(object)enabled.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)([CompilerGenerated] (bool _, bool value) => { Change(delegate(FlashlightSettings s) { s.Enabled = value; }); }), 0, false); ((MelonEventBase<LemonAction<string, string>>)(object)hue.OnEntryValueChanged).Subscribe((LemonAction<string, string>)([CompilerGenerated] (string _, string value) => { Change(delegate(FlashlightSettings s) { s.LightColor = value; }); }), 0, false); ((MelonEventBase<LemonAction<float, float>>)(object)output.OnEntryValueChanged).Subscribe((LemonAction<float, float>)([CompilerGenerated] (float _, float value) => { Change(delegate(FlashlightSettings s) { s.Intensity = value; }); }), 0, false); ((MelonEventBase<LemonAction<float, float>>)(object)projection.OnEntryValueChanged).Subscribe((LemonAction<float, float>)([CompilerGenerated] (float _, float value) => { Change(delegate(FlashlightSettings s) { s.Range = value; }); }), 0, false); ((MelonEventBase<LemonAction<float, float>>)(object)spread.OnEntryValueChanged).Subscribe((LemonAction<float, float>)([CompilerGenerated] (float _, float value) => { Change(delegate(FlashlightSettings s) { s.SpotAngle = value; }); }), 0, false); ((MelonEventBase<LemonAction<bool, bool>>)(object)restoreDefaults.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)([CompilerGenerated] (bool _, bool value) => { if (value) { Change(delegate(FlashlightSettings s) { s.RestoreAppearanceDefaults(); }); } }), 0, false); } private void Change(Action<FlashlightSettings> edit) { if (!synchronizing) { store.Reload(); FlashlightSettings flashlightSettings = store.Current.Copy(); edit.Invoke(flashlightSettings); store.TrySave(flashlightSettings); revision = -1; SyncFromStore(); } } public void SyncFromStore() { if (revision == store.Revision) { return; } synchronizing = true; try { FlashlightSettings current = store.Current; enabled.Value = current.Enabled; hue.Value = current.LightColor; output.Value = current.Intensity; projection.Value = current.Range; spread.Value = current.SpotAngle; restoreDefaults.Value = false; revision = store.Revision; } finally { synchronizing = false; } } } public sealed class Mod : MelonMod { private sealed class OriginalLight { public readonly Light Light; private readonly Color color; private readonly float intensity; private readonly float range; private readonly float angle; public OriginalLight(Light light) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Light = light; color = light.color; intensity = light.intensity; range = light.range; angle = light.spotAngle; } public void Restore() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Light.color = color; Light.intensity = intensity; Light.range = range; Light.spotAngle = angle; } } private static Mod? instance; private SettingsStore store; private MenuPreferences menu; private readonly List<OriginalLight> originals = new List<OriginalLight>(); private GameObject? flashlight; private float nextCheck; private float nextError; private int appliedRevision = -1; private bool warnedMissingLight; [field: CompilerGenerated] internal static SettingsStore? SharedSettings { [CompilerGenerated] get; [CompilerGenerated] private set; } internal static void LogInfo(string message) { Mod? mod = instance; if (mod != null) { ((MelonBase)mod).LoggerInstance.Msg(message); } } internal static void LogWarning(string message) { Mod? mod = instance; if (mod != null) { ((MelonBase)mod).LoggerInstance.Warning(message); } } public override void OnInitializeMelon() { instance = this; store = new SettingsStore(Path.Combine(MelonEnvironment.UserDataDirectory, "FlashLightEnhanced.json"), [CompilerGenerated] (string message) => { ((MelonBase)this).LoggerInstance.Msg(message); }, [CompilerGenerated] (string message) => { ((MelonBase)this).LoggerInstance.Warning(message); }, Path.Combine(MelonEnvironment.UserDataDirectory, "BetterFlashlightReborn.json")); store.Reload(); SharedSettings = store; menu = new MenuPreferences(store); ((MelonBase)this).LoggerInstance.Msg("Ready. Configuration reloads every second; the game controls the flashlight toggle."); } public override void OnLateUpdate() { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_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) LumenApp.TickCurrent(); if (Time.realtimeSinceStartup < nextCheck) { return; } nextCheck = Time.realtimeSinceStartup + 1f; store.Reload(); menu.SyncFromStore(); try { Phone val = PlayerSingleton<Phone>.Instance; GameObject val2 = (((Object)(object)val != (Object)null) ? val.PhoneFlashlight : null); if ((Object)(object)flashlight != (Object)(object)val2) { Restore(); flashlight = val2; warnedMissingLight = false; } if ((Object)(object)flashlight == (Object)null) { return; } Il2CppArrayBase<Light> componentsInChildren = flashlight.GetComponentsInChildren<Light>(true); bool flag = false; System.Collections.Generic.IEnumerator<Light> enumerator = componentsInChildren.GetEnumerator(); Enumerator<OriginalLight> enumerator2; try { while (((System.Collections.IEnumerator)enumerator).MoveNext()) { Light current = enumerator.Current; if ((Object)(object)current == (Object)null || (int)current.type != 0) { continue; } flag = true; bool flag2 = false; enumerator2 = originals.GetEnumerator(); try { while (enumerator2.MoveNext()) { if ((Object)(object)enumerator2.Current.Light == (Object)(object)current) { flag2 = true; break; } } } finally { ((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } if (!flag2) { originals.Add(new OriginalLight(current)); appliedRevision = -1; ((MelonBase)this).LoggerInstance.Msg("Bound local flashlight spotlight: " + ((Object)current).name); } } } finally { ((System.IDisposable)enumerator)?.Dispose(); } originals.RemoveAll((Predicate<OriginalLight>)((OriginalLight original) => (Object)(object)original.Light == (Object)null)); if (!flag && !warnedMissingLight) { warnedMissingLight = true; ((MelonBase)this).LoggerInstance.Warning("No spotlight under PhoneFlashlight; leaving vanilla behaviour intact."); } enumerator2 = originals.GetEnumerator(); try { while (enumerator2.MoveNext()) { OriginalLight current2 = enumerator2.Current; if (!((Object)(object)current2.Light == (Object)null)) { if (store.Current.Enabled) { Apply(current2.Light, store.Current); } else if (appliedRevision != store.Revision) { current2.Restore(); } } } } finally { ((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } appliedRevision = store.Revision; } catch (System.Exception ex) { if (Time.realtimeSinceStartup >= nextError) { nextError = Time.realtimeSinceStartup + 30f; ((MelonBase)this).LoggerInstance.Warning("Flashlight binding failed; will retry: " + ex.Message); } } } private static void Apply(Light light, FlashlightSettings settings) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) string lightColor = settings.LightColor; Color color = default(Color); ((Color)(ref color))..ctor((float)(int)byte.Parse(lightColor.Substring(1, 2), (NumberStyles)515) / 255f, (float)(int)byte.Parse(lightColor.Substring(3, 2), (NumberStyles)515) / 255f, (float)(int)byte.Parse(lightColor.Substring(5, 2), (NumberStyles)515) / 255f, 1f); light.color = color; light.intensity = settings.Intensity; light.range = settings.Range; light.spotAngle = settings.SpotAngle; } private void Restore() { //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) Enumerator<OriginalLight> enumerator = originals.GetEnumerator(); try { while (enumerator.MoveNext()) { OriginalLight current = enumerator.Current; if ((Object)(object)current.Light != (Object)null) { current.Restore(); } } } finally { ((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } originals.Clear(); flashlight = null; appliedRevision = -1; } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { if (sceneName == "Main") { LumenApp.ShutdownCurrent(); } } public override void OnDeinitializeMelon() { LumenApp.ShutdownCurrent(); Restore(); SharedSettings = null; instance = null; } } public sealed class SettingsStore { private readonly string path; private readonly string? legacyPath; private bool migrationChecked; private readonly Action<string> info; private readonly Action<string> warning; private string? lastText; private string? lastError; [field: CompilerGenerated] public FlashlightSettings Current { [CompilerGenerated] get; [CompilerGenerated] private set; } = new FlashlightSettings(); [field: CompilerGenerated] public int Revision { [CompilerGenerated] get; [CompilerGenerated] private set; } public SettingsStore(string path, Action<string> info, Action<string> warning, string? legacyPath = null) { this.path = path; this.legacyPath = legacyPath; this.info = info; this.warning = warning; } public bool TrySave(FlashlightSettings settings) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) string text = null; try { settings.Validate(); FlashlightSettings flashlightSettings = settings.Copy(); string text2 = JsonSerializer.Serialize<FlashlightSettings>(flashlightSettings, new JsonSerializerOptions { WriteIndented = true }); Directory.CreateDirectory(Path.GetDirectoryName(path)); string text3 = path; Guid val = Guid.NewGuid(); text = text3 + "." + ((Guid)(ref val)).ToString("N") + ".tmp"; File.WriteAllText(text, text2); File.Move(text, path, true); Current = flashlightSettings; lastText = text2; lastError = null; Revision++; return true; } catch (System.Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is FormatException) { warning.Invoke("Could not save flashlight settings; keeping previous values. " + ex.Message); return false; } finally { if (text != null) { try { File.Delete(text); } catch (IOException) { } catch (UnauthorizedAccessException) { } } } } public void Reload() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) try { if (!migrationChecked) { if (!File.Exists(path) && legacyPath != null && File.Exists(legacyPath)) { Directory.CreateDirectory(Path.GetDirectoryName(path)); File.Copy(legacyPath, path, false); info.Invoke("Migrated previous project configuration to: " + path); } migrationChecked = true; } if (!File.Exists(path)) { Directory.CreateDirectory(Path.GetDirectoryName(path)); FileStream val = new FileStream(path, (FileMode)1, (FileAccess)2, (FileShare)0); try { JsonSerializer.Serialize<FlashlightSettings>((Stream)(object)val, Current, new JsonSerializerOptions { WriteIndented = true }); info.Invoke("Created configuration: " + path); } finally { ((System.IDisposable)val)?.Dispose(); } } string text = File.ReadAllText(path); if (!(text == lastText)) { lastText = text; FlashlightSettings flashlightSettings = JsonSerializer.Deserialize<FlashlightSettings>(text, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? throw new FormatException("Configuration must be a JSON object."); flashlightSettings.Validate(); Current = flashlightSettings; Revision++; lastError = null; info.Invoke("Loaded flashlight settings: " + path); } } catch (System.Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is JsonException || ex is FormatException) { string message = ex.Message; if (message != lastError) { warning.Invoke("Keeping last valid flashlight settings. " + path + ": " + message); } lastError = message; } } } }