Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ClockDaddyPlus v0.1.1
plugins/ClockDaddyPlus/ClockDaddyPlus.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Laoch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) Laoch")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+4722fa699af23d00d746ac781356a0dc72fd86cd")] [assembly: AssemblyProduct("ClockDaddyPlus")] [assembly: AssemblyTitle("ClockDaddyPlus")] [assembly: InternalsVisibleTo("ClockDaddyPlus.Harness")] [assembly: AssemblyVersion("0.1.1.0")] [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 ClockDaddyPlus { public enum PingSound { None, Chime, Bell, Beeps, Ding, Rising, Westminster, Marimba, Gong, Pulse, MusicBox } internal static class Chime { private const int Rate = 44100; private static readonly Dictionary<PingSound, AudioClip> Clips = new Dictionary<PingSound, AudioClip>(); public static AudioClip Get(PingSound sound) { if (Clips.TryGetValue(sound, out var value)) { return value; } float[] array = Samples(sound); value = ((array == null) ? null : Build("ClockDaddy_" + sound, array)); Clips[sound] = value; return value; } private static float[] Samples(PingSound sound) { return sound switch { PingSound.Chime => ChimeSamples(), PingSound.Bell => BellSamples(), PingSound.Beeps => BeepSamples(), PingSound.Ding => DingSamples(), PingSound.Rising => RisingSamples(), PingSound.Westminster => WestminsterSamples(), PingSound.Marimba => MarimbaSamples(), PingSound.Gong => GongSamples(), PingSound.Pulse => PulseSamples(), PingSound.MusicBox => MusicBoxSamples(), _ => null, }; } private static AudioClip Build(string name, float[] samples) { AudioClip obj = AudioClip.Create(name, samples.Length, 1, 44100, false); obj.SetData(samples, 0); return obj; } private static float[] ChimeSamples() { float[] buf = new float[70560]; AddBell(buf, 0f, 1318.5f, 0.9f, 3.5f); AddBell(buf, 0.45f, 1046.5f, 1.1f, 3f); return Normalize(buf, 0.8f); } private static float[] BellSamples() { float[] buf = new float[105840]; AddBell(buf, 0f, 523.25f, 2.3f, 1.8f); return Normalize(buf, 0.8f); } private static float[] BeepSamples() { float[] array = new float[39690]; for (int i = 0; i < 3; i++) { int num = (int)((float)(44100 * i) * 0.28f); int num2 = 6174; for (int j = 0; j < num2 && num + j < array.Length; j++) { float num3 = (float)j / 44100f; float num4 = Mathf.Min(1f, (float)Mathf.Min(j, num2 - j) / 220.5f); float num5 = Mathf.Sin(MathF.PI * 3520f * num3) + 0.3f * Mathf.Sin(MathF.PI * 7040f * num3); array[num + j] += num5 * num4; } } return Normalize(array, 0.6f); } private static float[] DingSamples() { float[] buf = new float[44100]; AddBell(buf, 0f, 1760f, 1f, 4.5f); return Normalize(buf, 0.7f); } private static float[] RisingSamples() { float[] buf = new float[66150]; float[] array = new float[4] { 1046.5f, 1318.51f, 1567.98f, 2093f }; for (int i = 0; i < array.Length; i++) { AddBell(buf, (float)i * 0.14f, array[i], 1f, 4f); } return Normalize(buf, 0.75f); } private static float[] WestminsterSamples() { float[] buf = new float[132300]; float[] array = new float[4] { 659.25f, 523.25f, 587.33f, 392f }; for (int i = 0; i < array.Length; i++) { AddBell(buf, (float)i * 0.55f, array[i], (i == array.Length - 1) ? 1.35f : 1.2f, 2.2f); } return Normalize(buf, 0.8f); } private static float[] MarimbaSamples() { float[] buf = new float[39690]; AddMallet(buf, 0f, 783.99f); AddMallet(buf, 0.16f, 1046.5f); AddMallet(buf, 0.32f, 1046.5f); return Normalize(buf, 0.75f); } private static float[] GongSamples() { float[] array = new float[154350]; float[] array2 = new float[6] { 1f, 1.52f, 1.53f, 2.31f, 3.17f, 4.4f }; float[] array3 = new float[6] { 1f, 0.6f, 0.5f, 0.4f, 0.25f, 0.12f }; for (int i = 0; i < array.Length; i++) { float num = (float)i / 44100f; float num2 = Mathf.Min(1f, num / 0.06f) * Mathf.Exp((0f - num) * 1.1f); float num3 = 0f; for (int j = 0; j < array2.Length; j++) { num3 += array3[j] * Mathf.Sin(MathF.PI * 220f * array2[j] * num) * Mathf.Exp((0f - num) * 0.4f * (float)j); } array[i] = num3 * num2; } return Normalize(array, 0.85f); } private static float[] PulseSamples() { float[] buf = new float[52920]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 4; j++) { AddBeep(buf, (float)i * 0.6f + (float)j * 0.09f, 0.05f, 2637f); } } return Normalize(buf, 0.55f); } private static float[] MusicBoxSamples() { float[] buf = new float[97020]; float[] array = new float[6] { 1567.98f, 1318.51f, 1046.5f, 1174.66f, 1567.98f, 2093f }; float[] array2 = new float[6] { 0f, 0.18f, 0.36f, 0.54f, 0.78f, 1.02f }; for (int i = 0; i < array.Length; i++) { AddTine(buf, array2[i], array[i], (i == array.Length - 1) ? 1.2f : 0.7f); } return Normalize(buf, 0.7f); } private static void AddBeep(float[] buf, float startSec, float lengthSec, float freq) { int num = (int)(startSec * 44100f); int num2 = (int)(lengthSec * 44100f); for (int i = 0; i < num2 && num + i < buf.Length; i++) { float num3 = (float)i / 44100f; float num4 = Mathf.Min(1f, (float)Mathf.Min(i, num2 - i) / 176.40001f); buf[num + i] += Mathf.Sin(MathF.PI * 2f * freq * num3) * num4; } } private static void AddMallet(float[] buf, float startSec, float freq) { int num = (int)(startSec * 44100f); int num2 = 22050; for (int i = 0; i < num2 && num + i < buf.Length; i++) { float num3 = (float)i / 44100f; float num4 = Mathf.Min(1f, num3 / 0.002f); float num5 = Mathf.Sin(MathF.PI * 2f * freq * num3) * Mathf.Exp((0f - num3) * 9f) + 0.35f * Mathf.Sin(MathF.PI * 2f * freq * 4f * num3) * Mathf.Exp((0f - num3) * 40f) + 0.1f * Mathf.Sin(MathF.PI * 2f * freq * 10f * num3) * Mathf.Exp((0f - num3) * 80f); buf[num + i] += num5 * num4; } } private static void AddTine(float[] buf, float startSec, float freq, float lengthSec) { int num = (int)(startSec * 44100f); int num2 = (int)(lengthSec * 44100f); for (int i = 0; i < num2 && num + i < buf.Length; i++) { float num3 = (float)i / 44100f; float num4 = Mathf.Min(1f, num3 / 0.002f); float num5 = Mathf.Sin(MathF.PI * 2f * freq * num3) * Mathf.Exp((0f - num3) * 4f) + 0.3f * Mathf.Sin(MathF.PI * 2f * freq * 3.01f * num3) * Mathf.Exp((0f - num3) * 12f) + 0.12f * Mathf.Sin(MathF.PI * 2f * freq * 5.4f * num3) * Mathf.Exp((0f - num3) * 25f); buf[num + i] += num5 * num4; } } private static void AddBell(float[] buf, float startSec, float freq, float lengthSec, float decay) { float[] array = new float[4] { 1f, 2f, 2.76f, 5.4f }; float[] array2 = new float[4] { 1f, 0.5f, 0.25f, 0.1f }; int num = (int)(startSec * 44100f); int num2 = (int)(lengthSec * 44100f); for (int i = 0; i < num2 && num + i < buf.Length; i++) { float num3 = (float)i / 44100f; float num4 = Mathf.Min(1f, num3 / 0.004f); float num5 = 0f; for (int j = 0; j < array.Length; j++) { num5 += array2[j] * Mathf.Sin(MathF.PI * 2f * freq * array[j] * num3) * Mathf.Exp((0f - num3) * decay * (1f + (float)j)); } buf[num + i] += num5 * num4; } } private static float[] Normalize(float[] buf, float peak) { float num = 0f; foreach (float num2 in buf) { num = Mathf.Max(num, Mathf.Abs(num2)); } if (num > 0f) { for (int j = 0; j < buf.Length; j++) { buf[j] *= peak / num; } } return buf; } } [BepInPlugin("com.laoch.clockdaddyplus", "ClockDaddyPlus", "0.1.1")] public class ClockDaddyPlusPlugin : BaseUnityPlugin { public const string PluginGuid = "com.laoch.clockdaddyplus"; public const string PluginName = "ClockDaddyPlus"; public const string PluginVersion = "0.1.1"; private GUIStyle _style; private Font _font; private float _nextFontSearch; private readonly GUIContent _content = new GUIContent(); private readonly StringBuilder _sb = new StringBuilder(); internal static ClockDaddyPlusPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal Timers Timers { get; private set; } private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; Settings.Bind(((BaseUnityPlugin)this).Config); new Harmony("com.laoch.clockdaddyplus").PatchAll(typeof(ClockDaddyPlusPlugin).Assembly); AudioSource val = ((Component)this).gameObject.AddComponent<AudioSource>(); val.playOnAwake = false; val.spatialBlend = 0f; val.ignoreListenerPause = true; Timers = new Timers(val, Path.Combine(Paths.ConfigPath, "com.laoch.clockdaddyplus.timers.txt")); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ClockDaddyPlus 0.1.1 loaded. Set timers up in F1; Shift + / - to pick, Shift+T to start."); } private void Update() { //IL_000c: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!IsTyping()) { KeyboardShortcut value = Settings.NextKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Timers.Cycle(1); } value = Settings.PrevKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Timers.Cycle(-1); } value = Settings.StartStopKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Timers.StartOrStopSelected(); } value = Settings.StopAllKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Timers.StopAll(); } } Timers.Update(); } private static bool IsTyping() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible()) { return InputGuard.TypingInConfigManager; } return true; } private static bool HudAllowed() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } if (Hud.IsUserHidden()) { return false; } if (Settings.HideInMenus.Value && (Minimap.IsOpen() || InventoryGui.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible())) { return false; } return true; } private void OnGUI() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if ((int)Event.current.type != 7 || !HudAllowed()) { return; } GUIStyle style = GetStyle(); style.fontSize = Settings.FontSize.Value; float x = (float)Screen.width * Settings.PositionX.Value / 100f; float y = (float)Screen.height * Settings.PositionY.Value / 100f; float lineHeight = style.lineHeight + 4f; if (Time.realtimeSinceStartup < Timers.PickerUntil) { DrawLine(ref y, x, lineHeight, PickerText(), Settings.SelectColor.Value); } if (!Settings.ShowTimers.Value) { return; } bool flag = Mathf.Repeat(Time.unscaledTime * 1.5f, 1f) < 0.5f; foreach (RunningTimer item in Timers.Running) { if (Timers.IsLive(item)) { if (item.IsDone) { DrawLine(ref y, x, lineHeight, item.Name + " DONE", flag ? Settings.DoneColor.Value : Settings.TextColor.Value); } else { DrawLine(ref y, x, lineHeight, item.Name + " " + Durations.Format(item.Remaining()), Settings.TextColor.Value); } } } } private string PickerText() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) int selected = Timers.Selected; if (selected < 0) { return "No timers enabled (F1)"; } SlotSettings slotSettings = Settings.Slots[selected]; string value = KeyText(Settings.StartStopKey.Value); _sb.Length = 0; _sb.Append("< ").Append(slotSettings.Label).Append(" "); if (Timers.TryGet(selected, out var timer)) { _sb.Append(timer.IsDone ? "done" : (Durations.Format(timer.Remaining()) + " left")).Append(" > ").Append(value) .Append(timer.IsDone ? " clear" : " stop"); } else { _sb.Append(Durations.Format(slotSettings.Length)).Append((slotSettings.Clock.Value == TimerClock.World) ? " (world)" : "").Append(" > ") .Append(value) .Append(" start"); } return _sb.ToString(); } internal static string KeyText(KeyboardShortcut k) { //IL_0002: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref k)).MainKey == 0) { return "(no key)"; } StringBuilder stringBuilder = new StringBuilder(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref k)).Modifiers) { stringBuilder.Append(KeyName(modifier)).Append('+'); } return stringBuilder.Append(KeyName(((KeyboardShortcut)(ref k)).MainKey)).ToString(); } private unsafe static string KeyName(KeyCode c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0021: 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_0045: Expected I4, but got Unknown if ((int)c <= 61) { if ((int)c == 45) { return "-"; } if ((int)c == 61) { return "="; } } else { if ((int)c == 269) { return "Num-"; } if ((int)c == 270) { return "Num+"; } switch (c - 303) { case 0: case 1: return "Shift"; case 2: case 3: return "Ctrl"; case 4: case 5: return "Alt"; } } string text = ((object)(*(KeyCode*)(&c))/*cast due to .constrained prefix*/).ToString(); if (!text.StartsWith("Alpha")) { return text; } return text.Substring(5); } private void DrawLine(ref float y, float x, float lineHeight, string text, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) GUIStyle style = _style; _content.text = text; Vector2 val = style.CalcSize(_content); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(Mathf.Clamp(x, 0f, Mathf.Max(0f, (float)Screen.width - val.x)), y, val.x, val.y); style.normal.textColor = new Color(0f, 0f, 0f, 0.8f); GUI.Label(new Rect(((Rect)(ref val2)).x + 1f, ((Rect)(ref val2)).y + 1f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), _content, style); style.normal.textColor = color; GUI.Label(val2, _content, style); y += lineHeight; } private GUIStyle GetStyle() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (_style == null) { _style = new GUIStyle(GUI.skin.label) { richText = false, wordWrap = false, clipping = (TextClipping)0 }; } if ((Object)(object)_font == (Object)null && Time.unscaledTime >= _nextFontSearch) { _nextFontSearch = Time.unscaledTime + 5f; Font[] array = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val in array) { if (((Object)val).name == "AveriaSerifLibre-Bold") { _font = val; break; } } if ((Object)(object)_font != (Object)null) { _style.font = _font; } } _style.fontStyle = (FontStyle)(Settings.BoldText.Value ? 1 : 0); return _style; } } internal sealed class ConfigurationManagerAttributes { public int? Order; public Action<ConfigEntryBase> CustomDrawer; public bool? HideDefaultButton; public bool? HideSettingName; public bool? IsAdvanced; } internal static class Durations { public static TimeSpan Parse(string text, TimeSpan fallback) { if (string.IsNullOrWhiteSpace(text)) { return fallback; } string[] array = text.Trim().Split(':'); try { TimeSpan timeSpan; switch (array.Length) { case 1: timeSpan = TimeSpan.FromMinutes(double.Parse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture)); break; case 2: timeSpan = new TimeSpan(0, int.Parse(array[0], CultureInfo.InvariantCulture), int.Parse(array[1], CultureInfo.InvariantCulture)); break; case 3: timeSpan = new TimeSpan(int.Parse(array[0], CultureInfo.InvariantCulture), int.Parse(array[1], CultureInfo.InvariantCulture), int.Parse(array[2], CultureInfo.InvariantCulture)); break; default: return fallback; } return (timeSpan > TimeSpan.Zero) ? timeSpan : fallback; } catch (FormatException) { return fallback; } catch (OverflowException) { return fallback; } } public static string Format(TimeSpan t) { if (t < TimeSpan.Zero) { t = TimeSpan.Zero; } int num = (int)Math.Ceiling(t.TotalSeconds); int num2 = num / 3600; int num3 = num / 60 % 60; int num4 = num % 60; if (num2 <= 0) { return $"{num3}:{num4:00}"; } return $"{num2}:{num3:00}:{num4:00}"; } } internal static class InputGuard { [HarmonyPatch(typeof(TextInput), "IsVisible")] private static class TextInputIsVisible { private static void Postfix(ref bool __result) { if (!__result && TypingInConfigManager) { __result = true; } } } private const string ConfigManagerGuid = "com.bepis.bepinex.configurationmanager"; private static object _cm; private static PropertyInfo _displaying; private static bool _looked; public static bool TypingInConfigManager { get { if (GUIUtility.keyboardControl == 0) { return false; } if (!_looked) { _looked = true; if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && (Object)(object)value.Instance != (Object)null) { _cm = value.Instance; _displaying = _cm.GetType().GetProperty("DisplayingWindow", BindingFlags.Instance | BindingFlags.Public); } } if (_cm == null || _displaying == null) { return false; } try { return (bool)_displaying.GetValue(_cm, null); } catch { return false; } } } } public enum TimerClock { Real, World } public enum AlertMessage { None, Center, TopLeft } internal sealed class SlotSettings { public int Index; public ConfigEntry<bool> Enabled; public ConfigEntry<string> Name; public ConfigEntry<string> Duration; public ConfigEntry<TimerClock> Clock; public TimeSpan Length => Durations.Parse(Duration.Value, TimeSpan.FromMinutes(5.0)); public string Label { get { if (!string.IsNullOrWhiteSpace(Name.Value)) { return Name.Value.Trim(); } return $"Timer {Index + 1}"; } } } internal static class Settings { public const int SlotCount = 6; private const string SKeys = "1 - Hotkeys"; private const string SDisplay = "2 - Display"; private const string SAlert = "3 - Alerts"; public static ConfigEntry<KeyboardShortcut> NextKey; public static ConfigEntry<KeyboardShortcut> PrevKey; public static ConfigEntry<KeyboardShortcut> StartStopKey; public static ConfigEntry<KeyboardShortcut> StopAllKey; public static ConfigEntry<bool> ShowTimers; public static ConfigEntry<float> PositionX; public static ConfigEntry<float> PositionY; public static ConfigEntry<int> FontSize; public static ConfigEntry<bool> BoldText; public static ConfigEntry<Color> TextColor; public static ConfigEntry<Color> SelectColor; public static ConfigEntry<Color> DoneColor; public static ConfigEntry<float> SelectorSeconds; public static ConfigEntry<bool> HideInMenus; public static ConfigEntry<PingSound> Sound; public static ConfigEntry<float> Volume; public static ConfigEntry<AlertMessage> MessageStyle; public static ConfigEntry<string> DoneMessage; public static ConfigEntry<int> KeepDoneSeconds; public static ConfigEntry<int> RepeatSeconds; public static readonly SlotSettings[] Slots = new SlotSettings[6]; private static ConfigFile _cfg; private static int _order; private static readonly (string name, string duration, TimerClock clock, bool on)[] Defaults = new(string, string, TimerClock, bool)[6] { ("Puff farm", "1:00:00", TimerClock.World, true), ("Mistwalker", "20:00", TimerClock.Real, true), ("Food", "25:00", TimerClock.Real, true), ("Fermenter", "40:00", TimerClock.World, true), ("Timer 5", "5:00", TimerClock.Real, false), ("Timer 6", "15:00", TimerClock.Real, false) }; public static void Bind(ConfigFile cfg) { //IL_002a: 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_008c: 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_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: 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) _cfg = cfg; _order = 1000; NextKey = B<KeyboardShortcut>("1 - Hotkeys", "Next Timer", new KeyboardShortcut((KeyCode)61, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Select the next timer (Shift and the + / = key by default). The pick shows on screen for a moment."); PrevKey = B<KeyboardShortcut>("1 - Hotkeys", "Previous Timer", new KeyboardShortcut((KeyCode)45, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Select the previous timer."); StartStopKey = B<KeyboardShortcut>("1 - Hotkeys", "Start / Stop Timer", new KeyboardShortcut((KeyCode)116, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Start the selected timer, or stop it if it's already running."); StopAllKey = B<KeyboardShortcut>("1 - Hotkeys", "Stop All Timers", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), "Stop every running timer. Unset by default."); _order = 1000; ShowTimers = B("2 - Display", "Show Timers", value: true, "List running timers on screen with their countdown."); PositionX = B("2 - Display", "Position X (%)", 1f, "Left edge of the timer list, 0 = left of screen, 100 = right.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)); PositionY = B("2 - Display", "Position Y (%)", 22f, "Top of the timer list, 0 = top of screen, 100 = bottom.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)); FontSize = B("2 - Display", "Font Size", 20, "Text size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 48)); BoldText = B("2 - Display", "Bold Text", value: true, "Draw the timers in bold (matches ClockDaddy)."); TextColor = B<Color>("2 - Display", "Text Color", Color.white, "Running timers."); SelectColor = B<Color>("2 - Display", "Selected Color", new Color(1f, 0.84f, 0f, 1f), "The timer picker line."); DoneColor = B<Color>("2 - Display", "Done Color", new Color(1f, 0.35f, 0.2f, 1f), "Finished timers (they flash)."); SelectorSeconds = B("2 - Display", "Picker Shows For (seconds)", 4f, "How long the picker stays up after Next / Previous.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f)); HideInMenus = B("2 - Display", "Hide In Menus", value: false, "Hide the list in the inventory, Esc menu and big map."); _order = 1000; Sound = B("3 - Alerts", "Sound", PingSound.Chime, "Sound when a timer finishes. Use Test Sound to hear it."); Volume = B("3 - Alerts", "Volume", 0.7f, "Alert volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); B("3 - Alerts", "Test Sound", value: false, "Play the chosen sound at the chosen volume.", null, delegate { DrawTestSoundButton(); }, hideName: true); MessageStyle = B("3 - Alerts", "Message Style", AlertMessage.Center, "Where the \"done\" message pops up."); DoneMessage = B("3 - Alerts", "Done Message", "{name} is done!", "Text when a timer finishes. {name} is the timer's name."); KeepDoneSeconds = B("3 - Alerts", "Keep Finished For (seconds)", 60, "How long a finished timer stays in the list, flashing. Start/Stop on it clears it sooner.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 600)); RepeatSeconds = B("3 - Alerts", "Repeat Alert Every (seconds)", 0, "Ping again this often while a finished timer is still listed. 0 = once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 120)); for (int num = 0; num < 6; num++) { (string, string, TimerClock, bool) tuple = Defaults[num]; string section = $"{4 + num} - Timer {num + 1}"; _order = 1000; SlotSettings slotSettings = new SlotSettings { Index = num }; slotSettings.Enabled = B(section, "Enabled", tuple.Item4, "Include this timer when cycling with Next / Previous."); slotSettings.Name = B(section, "Name", tuple.Item1, "What it's called on screen and in the done message."); slotSettings.Duration = B(section, "Duration", tuple.Item2, "How long it runs: h:mm:ss, mm:ss, or plain minutes (e.g. 1:30:00, 20:00, 45)."); slotSettings.Clock = B(section, "Clock", tuple.Item3, "Real = wall-clock time (tool durability, food). World = the world's clock, which also jumps ahead when everyone sleeps (crops, fermenters)."); int captured = num; B(section, "Start / Stop", value: false, "Start or stop this timer now.", null, delegate { DrawSlotButton(captured); }, hideName: true); Slots[num] = slotSettings; } } private static ConfigEntry<T> B<T>(string section, string key, T value, string description, AcceptableValueBase acceptable = null, Action<ConfigEntryBase> drawer = null, bool hideName = false) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { Order = _order-- }; if (drawer != null) { configurationManagerAttributes.CustomDrawer = drawer; configurationManagerAttributes.HideDefaultButton = true; configurationManagerAttributes.HideSettingName = hideName; } return _cfg.Bind<T>(section, key, value, new ConfigDescription(description, acceptable, new object[1] { configurationManagerAttributes })); } private static void DrawTestSoundButton() { Timers timers = ClockDaddyPlusPlugin.Instance?.Timers; if (timers != null && GUILayout.Button($"Test Sound ({Sound.Value})", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { timers.PlaySound(); } } private static void DrawSlotButton(int index) { Timers timers = ClockDaddyPlusPlugin.Instance?.Timers; if (timers != null) { RunningTimer timer; string text = ((!timers.TryGet(index, out timer)) ? ("Start (" + Durations.Format(Slots[index].Length) + ")") : (timer.IsDone ? "Clear (done)" : ("Stop (" + Durations.Format(timer.Remaining()) + " left)"))); if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { timers.StartOrStop(index); } } } } internal sealed class RunningTimer { public int Slot; public string Name; public TimerClock Clock; public DateTime EndUtc; public double EndWorld; public string World; public bool IsDone; public float DoneAt; public float LastAlert; public TimeSpan Remaining() { if (Clock == TimerClock.Real) { return EndUtc - DateTime.UtcNow; } ZNet instance = ZNet.instance; if (!((Object)(object)instance != (Object)null)) { return TimeSpan.MaxValue; } return TimeSpan.FromSeconds(EndWorld - instance.GetTimeSeconds()); } } internal sealed class Timers { private readonly List<RunningTimer> _running = new List<RunningTimer>(); private readonly AudioSource _audio; private readonly string _saveFile; public int Selected { get; private set; } public float PickerUntil { get; private set; } internal int AlertCount { get; private set; } public IReadOnlyList<RunningTimer> Running => _running; private static bool InGame { get { if ((Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)ZNet.instance != (Object)null; } return false; } } private static string WorldName { get { if (!((Object)(object)ZNet.instance != (Object)null)) { return null; } return ZNet.instance.GetWorldName(); } } public Timers(AudioSource audio, string saveFile) { _audio = audio; _saveFile = saveFile; Load(); Selected = FirstEnabled(0, 1); } public bool TryGet(int slot, out RunningTimer timer) { timer = _running.FirstOrDefault((RunningTimer t) => t.Slot == slot); return timer != null; } public static bool IsLive(RunningTimer t) { if (t.Clock != TimerClock.Real) { if ((Object)(object)ZNet.instance != (Object)null) { return t.World == WorldName; } return false; } return true; } public void Cycle(int direction) { int num = FirstEnabled(Selected + direction, direction); if (num < 0) { Notify("ClockDaddy+: no timers enabled (turn some on in F1)"); return; } Selected = num; ShowPicker(); } public void ShowPicker() { PickerUntil = Time.realtimeSinceStartup + Settings.SelectorSeconds.Value; } private static int FirstEnabled(int start, int step) { int num = 6; for (int i = 0; i < num; i++) { int num2 = ((start + i * step) % num + num) % num; if (Settings.Slots[num2].Enabled.Value) { return num2; } } return -1; } public void StartOrStopSelected() { if (Selected < 0 || !Settings.Slots[Selected].Enabled.Value) { Selected = FirstEnabled(Math.Max(Selected, 0), 1); if (Selected < 0) { Notify("ClockDaddy+: no timers enabled (turn some on in F1)"); return; } } StartOrStop(Selected); ShowPicker(); } public void StartOrStop(int slot) { if (TryGet(slot, out var timer)) { _running.Remove(timer); Save(); Notify(timer.IsDone ? (timer.Name + " cleared") : (timer.Name + " stopped")); return; } SlotSettings slotSettings = Settings.Slots[slot]; RunningTimer runningTimer = new RunningTimer { Slot = slot, Name = slotSettings.Label, Clock = slotSettings.Clock.Value }; if (runningTimer.Clock == TimerClock.Real) { runningTimer.EndUtc = DateTime.UtcNow + slotSettings.Length; } else { if (!InGame) { Notify(runningTimer.Name + ": World timers can only start in a world"); return; } runningTimer.EndWorld = ZNet.instance.GetTimeSeconds() + slotSettings.Length.TotalSeconds; runningTimer.World = WorldName; } _running.Add(runningTimer); Save(); Notify(runningTimer.Name + " started (" + Durations.Format(slotSettings.Length) + ")"); } public void StopAll() { if (_running.Count != 0) { _running.Clear(); Save(); Notify("All timers stopped"); } } public void Update() { if (!InGame) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; bool flag = false; for (int num = _running.Count - 1; num >= 0; num--) { RunningTimer runningTimer = _running[num]; if (!IsLive(runningTimer)) { continue; } if (!runningTimer.IsDone) { if (runningTimer.Remaining() > TimeSpan.Zero) { continue; } runningTimer.IsDone = true; runningTimer.DoneAt = realtimeSinceStartup; Alert(runningTimer); flag = true; } int value = Settings.KeepDoneSeconds.Value; if (realtimeSinceStartup - runningTimer.DoneAt >= (float)value) { _running.RemoveAt(num); flag = true; continue; } int value2 = Settings.RepeatSeconds.Value; if (value2 > 0 && realtimeSinceStartup - runningTimer.LastAlert >= (float)value2) { Alert(runningTimer); } } if (flag) { Save(); } } private void Alert(RunningTimer t) { t.LastAlert = Time.realtimeSinceStartup; AlertCount++; PlaySound(); AlertMessage value = Settings.MessageStyle.Value; if (value != AlertMessage.None && !((Object)(object)MessageHud.instance == (Object)null)) { string text = (Settings.DoneMessage.Value ?? "").Replace("{name}", t.Name); if (text.Length != 0) { MessageHud.instance.ShowMessage((MessageType)((value == AlertMessage.TopLeft) ? 1 : 2), text, 0, (Sprite)null, true, true); } } } public void PlaySound() { AudioClip val = Chime.Get(Settings.Sound.Value); if ((Object)(object)val != (Object)null && (Object)(object)_audio != (Object)null) { _audio.PlayOneShot(val, Settings.Volume.Value); } } private static void Notify(string text) { if ((Object)(object)MessageHud.instance != (Object)null && InGame) { MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } private void Save() { try { IEnumerable<string> contents = from t in _running where !t.IsDone select string.Join("|", t.Slot.ToString(CultureInfo.InvariantCulture), t.Clock.ToString(), t.EndUtc.Ticks.ToString(CultureInfo.InvariantCulture), t.EndWorld.ToString("R", CultureInfo.InvariantCulture), (t.World ?? "").Replace("|", "/"), (t.Name ?? "").Replace("|", "/")); File.WriteAllLines(_saveFile, contents); } catch (Exception ex) { ManualLogSource log = ClockDaddyPlusPlugin.Log; if (log != null) { log.LogWarning((object)("Couldn't save timers: " + ex.Message)); } } } private void Load() { try { if (!File.Exists(_saveFile)) { return; } string[] array = File.ReadAllLines(_saveFile); foreach (string obj in array) { string[] array2 = obj.Split('|'); if (array2.Length >= 6 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var slot) && slot >= 0 && slot < 6 && !_running.Any((RunningTimer t) => t.Slot == slot) && Enum.TryParse<TimerClock>(array2[1], out var result)) { long.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2); double.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3); _running.Add(new RunningTimer { Slot = slot, Clock = result, EndUtc = new DateTime(result2, DateTimeKind.Utc), EndWorld = result3, World = ((array2[4].Length > 0) ? array2[4] : null), Name = array2[5] }); } } } catch (Exception ex) { ManualLogSource log = ClockDaddyPlusPlugin.Log; if (log != null) { log.LogWarning((object)("Couldn't load saved timers: " + ex.Message)); } } } } }