using System; using System.Collections.Generic; using System.Diagnostics; 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 SleepeyDev.OnTogetherPomoSound.Patches; using SleepeyDev.OnTogetherPomoSound.Pomodoro; using SleepeyDev.OnTogetherPomoSound.UI; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SleepeyDev")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("OnTogetherPomoSound")] [assembly: AssemblyTitle("OnTogetherPomoSound")] [assembly: AssemblyVersion("1.0.0.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 SleepeyDev.OnTogetherPomoSound { public static class Conflict { private const string LocalPlaylistGuid = "com.sleepeydev.ontogether.localplaylist"; private static readonly Version SplitVersion = new Version(0, 6, 0); private static bool _checked; private static bool _standDown; public static bool StandDown { get { if (_checked) { return _standDown; } _checked = true; _standDown = Detect(); return _standDown; } } private static bool Detect() { try { if (!Chainloader.PluginInfos.TryGetValue("com.sleepeydev.ontogether.localplaylist", out var value) || value == null || value.Metadata == null) { return false; } Version version = value.Metadata.Version; if (version == null || version >= SplitVersion) { return false; } Plugin.Log.LogWarning((object)("On-Together Local Playlist " + version?.ToString() + " is installed and still carries the Pomodoro tick volume itself, so this mod is standing down to avoid a duplicate row and two plugins fighting over the same AudioSource.")); Plugin.Log.LogWarning((object)("Update Local Playlist to " + SplitVersion?.ToString() + " or newer and this mod takes over. Your tick volume stays where it is either way.")); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not check for an older Local Playlist: " + ex.Message)); return false; } } } public static class HarmonyBootstrap { private static readonly Type[] PatchClasses = new Type[1] { typeof(UiBuildPatches) }; public static void ApplyAll() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("com.sleepeydev.ontogether.pomosound"); int num = 0; Type[] patchClasses = PatchClasses; foreach (Type type in patchClasses) { try { val.CreateClassProcessor(type).Patch(); num++; } catch (Exception ex) { Plugin.Log.LogError((object)("Patch class " + type.Name + " failed to apply (that feature is off): " + ex.Message)); } } Plugin.Log.LogInfo((object)("Applied " + num + "/" + PatchClasses.Length + " patch classes.")); } } public static class ModConfig { public static ConfigEntry Enabled; public static ConfigEntry TickTockVolumeScale; public static ConfigEntry TickRowEnabled; public static ConfigEntry RowShrink; public static ConfigEntry RowHeight; public static ConfigEntry TickRowLabel; public static ConfigEntry VerboseLogging; public static ConfigEntry DumpUi; public static ConfigEntry DumpUiKey; public static void Bind(ConfigFile cfg) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown Enabled = cfg.Bind("Pomodoro", "Enabled", true, "Master switch for the tick-tock volume fix."); TickTockVolumeScale = cfg.Bind("Pomodoro", "TickTockVolumeScale", 0f, new ConfigDescription("Loudness of the Pomodoro ticking clock, as a fraction of the phase-end bell volume.\nThe game itself forces these two to be equal (SoundManager.SetPomodoroVolume), which is why\nturning the bell down also turns the ticking down. 0 = ticking silent, bell unchanged.\n1 = vanilla behaviour. The game's own per-phase tick toggles keep working either way.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); TickRowEnabled = cfg.Bind("UI", "TickRowEnabled", true, "Add a 'Tick volume' slider to the Pomodoro sound settings, under the bell volume."); RowShrink = cfg.Bind("UI", "RowShrink", true, "Shrink the Pomodoro sound rows so the added one fits inside the panel. The four vanilla\nrows already just overflow it, so a fifth needs the room."); RowHeight = cfg.Bind("UI", "RowHeight", 79f, new ConfigDescription("Height of each Pomodoro sound row when RowShrink is on.", (AcceptableValueBase)(object)new AcceptableValueRange(40f, 110f), Array.Empty())); TickRowLabel = cfg.Bind("UI", "TickRowLabel", "Tick volume", "Caption of the added Pomodoro row."); VerboseLogging = cfg.Bind("Diagnostics", "VerboseLogging", false, "Log what the row build did. Noisy; for bug reports."); DumpUi = cfg.Bind("Diagnostics", "DumpUi", false, "Dump the Pomodoro sound settings tree to the log when it is built. Attach the log to a\nbug report if the row lands in the wrong place."); DumpUiKey = cfg.Bind("Diagnostics", "DumpUiKey", (KeyCode)283, "Key that dumps that tree on demand. F4-F6 and F10-F11 are taken by Day and Night,\nF7-F9 by FrameCare and BlueSage, and F3 by Local Playlist, so F1-F2 are the free ones."); } } public sealed class ModRoot : MonoBehaviour { public static ModRoot Instance { get; private set; } public static void Create() { //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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("OTPS_ModRoot") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent(); } } private void Update() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) try { TickTockVolume.Tick(); } catch (Exception ex) { Plugin.Log.LogError((object)("TickTockVolume.Tick threw, disabling: " + ex)); TickTockVolume.Disable(); } if (ModConfig.DumpUiKey != null && Input.GetKeyDown(ModConfig.DumpUiKey.Value)) { UiBuilder.DumpNow(); } } } [BepInPlugin("com.sleepeydev.ontogether.pomosound", "On-Together Pomodoro Sound", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.sleepeydev.ontogether.pomosound"; public static ManualLogSource Log { get; private set; } private void Awake() { Log = ((BaseUnityPlugin)this).Logger; try { ModConfig.Bind(((BaseUnityPlugin)this).Config); } catch (Exception ex) { Log.LogError((object)("Config binding failed - some features will switch themselves off: " + ex)); } ModRoot.Create(); HarmonyBootstrap.ApplyAll(); Log.LogInfo((object)("Pomodoro Sound " + ((BaseUnityPlugin)this).Info.Metadata.Version?.ToString() + " ready.")); Refl.LogHealth(); } } public static class Refl { private static readonly List Missing = new List(); public static readonly FieldRef PomodoroBell = Field("_pomodoroBell"); public static readonly FieldRef PomodoroTickTock = Field("_pomodoroTickTock"); public static readonly FieldRef PomodoroBellVolume = Field("_pomodoroBellVolume"); public static bool PomodoroReady { get { if (PomodoroBell != null) { return PomodoroTickTock != null; } return false; } } public static bool PomodoroUiReady { get { if (PomodoroReady) { return PomodoroBellVolume != null; } return false; } } private static FieldRef Field(string name) { try { FieldInfo fieldInfo = AccessTools.Field(typeof(TOwner), name); if (fieldInfo == null || !typeof(TField).IsAssignableFrom(fieldInfo.FieldType)) { Missing.Add(typeof(TOwner).Name + "." + name); return null; } return AccessTools.FieldRefAccess(name); } catch (Exception) { Missing.Add(typeof(TOwner).Name + "." + name); return null; } } public static void LogHealth() { if (Missing.Count == 0) { Plugin.Log.LogInfo((object)"Game handles: all resolved."); return; } Plugin.Log.LogWarning((object)("Game handles missing (the game was probably updated): " + string.Join(", ", Missing.ToArray()))); Plugin.Log.LogWarning((object)("Feature availability - tick volume fix: " + (PomodoroReady ? "on" : "OFF") + ", tick volume slider: " + (PomodoroUiReady ? "on" : "OFF"))); } } } namespace SleepeyDev.OnTogetherPomoSound.UI { public sealed class DragWatcher : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IPointerUpHandler { public bool IsDragging { get; private set; } public event Action Down; public event Action Up; public static DragWatcher Attach(GameObject go) { if ((Object)(object)go == (Object)null) { return null; } DragWatcher component = go.GetComponent(); if (!((Object)(object)component != (Object)null)) { return go.AddComponent(); } return component; } public void OnPointerDown(PointerEventData eventData) { if (!IsDragging) { IsDragging = true; Fire(this.Down); } } public void OnPointerUp(PointerEventData eventData) { Release(); } private void Update() { if (IsDragging && !Input.GetMouseButton(0)) { Release(); } } private void OnDisable() { if (IsDragging) { Release(); } } private void Release() { if (IsDragging) { IsDragging = false; Fire(this.Up); } } private void Fire(Action a) { if (a == null) { return; } try { a(); } catch (Exception ex) { Plugin.Log.LogError((object)("DragWatcher handler threw: " + ex)); } } } public static class GameUi { public const string Prefix = "OTPS_"; public static Transform Existing(Transform parent, string name) { if (!((Object)(object)parent == (Object)null)) { return parent.Find(name); } return null; } public static GameObject CloneObject(GameObject donor, Transform parent, string name) { if ((Object)(object)donor == (Object)null || (Object)(object)parent == (Object)null) { return null; } GameObject obj = Object.Instantiate(donor, parent, false); ((Object)obj).name = name; StripLocalizers(obj); obj.SetActive(true); return obj; } public static void ClearListeners(UnityEvent evt) { if (evt != null) { for (int num = ((UnityEventBase)evt).GetPersistentEventCount() - 1; num >= 0; num--) { ((UnityEventBase)evt).SetPersistentListenerState(num, (UnityEventCallState)0); } ((UnityEventBase)evt).RemoveAllListeners(); } } public static void ClearListeners(UnityEvent evt) { if (evt != null) { for (int num = ((UnityEventBase)evt).GetPersistentEventCount() - 1; num >= 0; num--) { ((UnityEventBase)evt).SetPersistentListenerState(num, (UnityEventCallState)0); } ((UnityEventBase)evt).RemoveAllListeners(); } } public static int StripScripts(GameObject root) { if ((Object)(object)root == (Object)null) { return 0; } Assembly assembly = typeof(SoundManager).Assembly; int num = 0; Component[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); bool flag = type.Name.IndexOf("Localize", StringComparison.Ordinal) >= 0; bool flag2 = type.Assembly == assembly; if (flag || flag2) { Object.Destroy((Object)(object)val); num++; } } } return num; } public static int StripLocalizers(GameObject root) { return StripScripts(root); } public static void Place(RectTransform rt, Vector2 anchoredPos, Vector2 sizeDelta) { //IL_0031: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rt == (Object)null) { return; } LayoutGroup val = (((Object)(object)((Transform)rt).parent == (Object)null) ? null : ((Component)((Transform)rt).parent).GetComponent()); if ((Object)(object)val == (Object)null) { rt.anchoredPosition = anchoredPos; rt.sizeDelta = sizeDelta; return; } HorizontalOrVerticalLayoutGroup val2 = (HorizontalOrVerticalLayoutGroup)(object)((val is HorizontalOrVerticalLayoutGroup) ? val : null); if ((Object)(object)val2 != (Object)null && val2.childControlHeight) { LayoutElement val3 = ((Component)rt).GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)rt).gameObject.AddComponent(); } val3.preferredHeight = sizeDelta.y; } else { rt.sizeDelta = new Vector2(rt.sizeDelta.x, sizeDelta.y); } } public static void DropFocus() { if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } } public static void DumpHierarchy(Transform root, string title, int maxDepth = 6) { if ((Object)(object)root == (Object)null) { Plugin.Log.LogInfo((object)("[dump] " + title + ": ")); return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[dump] ").Append(title).Append('\n'); Describe(root, stringBuilder, 0, maxDepth); Plugin.Log.LogInfo((object)stringBuilder.ToString()); } private static void Describe(Transform t, StringBuilder sb, int depth, int maxDepth) { //IL_00eb: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)t == (Object)null || depth > maxDepth) { return; } sb.Append(' ', depth * 2).Append(((Object)t).name); sb.Append(" [").Append(((Component)t).gameObject.activeSelf ? "on" : "off").Append(", sib ") .Append(t.GetSiblingIndex()) .Append(']'); Component[] components = ((Component)t).GetComponents(); sb.Append(" {"); for (int i = 0; i < components.Length; i++) { if (i > 0) { sb.Append(", "); } sb.Append(((Object)(object)components[i] == (Object)null) ? "" : ((object)components[i]).GetType().Name); } sb.Append('}'); RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null); if (val != null) { sb.Append(" aMin").Append(V(val.anchorMin)).Append(" aMax") .Append(V(val.anchorMax)) .Append(" piv") .Append(V(val.pivot)) .Append(" pos") .Append(V(val.anchoredPosition)) .Append(" size") .Append(V(val.sizeDelta)) .Append(" scale") .Append(V(((Transform)val).localScale)); } LayoutGroup val2 = (((Object)(object)t.parent == (Object)null) ? null : ((Component)t.parent).GetComponent()); if ((Object)(object)val2 != (Object)null) { sb.Append(" [LAYOUT-DRIVEN by ").Append(((object)val2).GetType().Name).Append(']'); } LayoutGroup component = ((Component)t).GetComponent(); if ((Object)(object)component != (Object)null) { sb.Append(" ").Append(DescribeLayout(component)); } Selectable component2 = ((Component)t).GetComponent(); Slider val3 = (Slider)(object)((component2 is Slider) ? component2 : null); if (val3 != null) { sb.Append(" slider(persistent=").Append(((UnityEventBase)val3.onValueChanged).GetPersistentEventCount()).Append(')'); } else { Button val4 = (Button)(object)((component2 is Button) ? component2 : null); if (val4 != null) { sb.Append(" button(persistent=").Append(((UnityEventBase)val4.onClick).GetPersistentEventCount()).Append(')'); } } TMP_Text component3 = ((Component)t).GetComponent(); if ((Object)(object)component3 != (Object)null) { string text = component3.text ?? ""; if (text.Length > 40) { text = text.Substring(0, 40) + "..."; } sb.Append(" text=\"").Append(text).Append('"'); } sb.Append('\n'); for (int j = 0; j < t.childCount; j++) { Describe(t.GetChild(j), sb, depth + 1, maxDepth); } } public static string DescribeLayout(LayoutGroup g) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)g == (Object)null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((object)g).GetType().Name).Append("(pad ").Append(g.padding.left) .Append(',') .Append(g.padding.right) .Append(',') .Append(g.padding.top) .Append(',') .Append(g.padding.bottom) .Append(" align=") .Append(g.childAlignment); HorizontalOrVerticalLayoutGroup val = (HorizontalOrVerticalLayoutGroup)(object)((g is HorizontalOrVerticalLayoutGroup) ? g : null); if (val != null) { stringBuilder.Append(" spacing=").Append(val.spacing).Append(" ctrlW=") .Append(val.childControlWidth) .Append(" ctrlH=") .Append(val.childControlHeight) .Append(" expW=") .Append(val.childForceExpandWidth) .Append(" expH=") .Append(val.childForceExpandHeight) .Append(" reverse=") .Append(val.reverseArrangement); } return stringBuilder.Append(')').ToString(); } private static string V(Vector2 v) { return "(" + v.x.ToString("0.##") + "," + v.y.ToString("0.##") + ")"; } private static string V(Vector3 v) { return "(" + v.x.ToString("0.##") + "," + v.y.ToString("0.##") + ")"; } } public sealed class StaticText : MonoBehaviour { private TMP_Text _label; public string Text; public static StaticText Apply(TMP_Text label, string text) { if ((Object)(object)label == (Object)null) { return null; } StaticText staticText = ((Component)label).gameObject.GetComponent(); if ((Object)(object)staticText == (Object)null) { staticText = ((Component)label).gameObject.AddComponent(); } staticText._label = label; staticText.Text = text; label.text = text; return staticText; } private void OnEnable() { if ((Object)(object)_label != (Object)null && Text != null) { _label.text = Text; } } } public static class TickVolumeRow { private const string RowName = "OTPS_TickVolumeRow"; private static bool _failed; public static void Build(PomodoroController pc) { if (_failed || Conflict.StandDown || !ModConfig.TickRowEnabled.Value) { return; } if (!Refl.PomodoroUiReady) { Plugin.Log.LogWarning((object)"Tick volume row: game handles missing, skipping. The ticking volume still follows Pomodoro/TickTockVolumeScale."); _failed = true; return; } Slider val = Refl.PomodoroBellVolume.Invoke(pc); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Tick volume row: no bell-volume slider on this PomodoroController."); return; } Transform parent = ((Component)val).transform.parent; Transform val2 = (((Object)(object)parent != (Object)null) ? parent.parent : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)"Tick volume row: the bell slider is not two levels inside a settings group."); } else { if ((Object)(object)GameUi.Existing(val2, "OTPS_TickVolumeRow") != (Object)null) { return; } GameObject val3 = GameUi.CloneObject(((Component)parent).gameObject, val2, "OTPS_TickVolumeRow"); if ((Object)(object)val3 == (Object)null) { Plugin.Log.LogWarning((object)"Tick volume row: cloning the bell row failed."); return; } val3.transform.SetSiblingIndex(parent.GetSiblingIndex() + 1); Slider componentInChildren = val3.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { Object.Destroy((Object)(object)val3); Plugin.Log.LogWarning((object)"Tick volume row: the cloned row has no slider."); return; } GameUi.ClearListeners((UnityEvent)(object)componentInChildren.onValueChanged); componentInChildren.minValue = 0f; componentInChildren.maxValue = 1f; componentInChildren.wholeNumbers = false; componentInChildren.SetValueWithoutNotify(TickTockVolume.Scale); ((UnityEvent)(object)componentInChildren.onValueChanged).AddListener((UnityAction)TickTockVolume.SetLive); DragWatcher.Attach(((Component)componentInChildren).gameObject).Up += GameUi.DropFocus; TMP_Text val4 = FindLabel(val3.transform, ((Component)componentInChildren).transform); if ((Object)(object)val4 != (Object)null) { StaticText.Apply(val4, ModConfig.TickRowLabel.Value); } else { Plugin.Log.LogWarning((object)"Tick volume row: no label found in the clone; the row is unlabelled."); } ShrinkRows(val2); Plugin.Log.LogInfo((object)("Tick volume row added at sibling " + val3.transform.GetSiblingIndex() + " under " + ((Object)val2).name + " " + GameUi.DescribeLayout(((Component)val2).GetComponent()))); } } private static TMP_Text FindLabel(Transform row, Transform slider) { TMP_Text[] componentsInChildren = ((Component)row).GetComponentsInChildren(true); foreach (TMP_Text val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.transform.IsChildOf(slider)) { return val; } } return null; } private static void ShrinkRows(Transform group) { //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_0058: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.RowShrink.Value) { return; } float num = Mathf.Max(20f, ModConfig.RowHeight.Value); int num2 = 0; for (int i = 0; i < group.childCount; i++) { Transform child = group.GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (val != null && ((Component)val).gameObject.activeSelf) { GameUi.Place(val, val.anchoredPosition, new Vector2(val.sizeDelta.x, num)); num2++; } } if (ModConfig.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Tick volume row: shrank " + num2 + " row(s) to " + num + " px.")); } } public static void Reset() { _failed = false; } } public static class UiBuilder { private static PomodoroController _pomodoro; public static void BuildPomodoroUi(PomodoroController pc) { if (!((Object)(object)pc == (Object)null)) { _pomodoro = pc; try { TickVolumeRow.Build(pc); } catch (Exception ex) { Plugin.Log.LogError((object)("Tick volume row build failed: " + ex)); } if (ModConfig.DumpUi.Value) { Dump(); } } } public static void DumpNow() { Dump(); } private static void Dump() { try { if (!((Object)(object)_pomodoro == (Object)null) && Refl.PomodoroBellVolume != null) { Slider val = Refl.PomodoroBellVolume.Invoke(_pomodoro); GameUi.DumpHierarchy(((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform.parent != (Object)null) ? ((Component)val).transform.parent.parent : null, "pomodoro sound settings (Group_Sounds)"); } } catch (Exception ex) { Plugin.Log.LogError((object)("UI dump failed: " + ex)); } } } } namespace SleepeyDev.OnTogetherPomoSound.Pomodoro { public static class TickTockVolume { private const float CommitDelay = 0.6f; private static bool _disabled; private static bool _wasApplying; private static bool _loggedOnce; private static AudioSource _bell; private static AudioSource _tick; private static float _nextResolveTime; private static bool _hasLive; private static float _live; private static float _commitAt; public static float Scale => Mathf.Clamp01(_hasLive ? _live : ModConfig.TickTockVolumeScale.Value); public static void Disable() { _disabled = true; } public static void SetLive(float scale) { _live = Mathf.Clamp01(scale); _hasLive = true; _commitAt = Time.unscaledTime + 0.6f; } public static void Tick() { if (_disabled || Conflict.StandDown || !Refl.PomodoroReady) { return; } CommitIfDue(); bool value = ModConfig.Enabled.Value; if (!Resolve()) { return; } if (!value) { if (_wasApplying) { _tick.volume = _bell.volume; _wasApplying = false; } return; } float num = _bell.volume * Scale; if (!Mathf.Approximately(_tick.volume, num)) { _tick.volume = num; } if (!_wasApplying) { _wasApplying = true; if (!_loggedOnce) { _loggedOnce = true; Plugin.Log.LogInfo((object)("Pomodoro tick-tock volume decoupled from the bell (scale " + Scale.ToString("0.00") + ").")); } } } private static void CommitIfDue() { if (_hasLive && !(_commitAt <= 0f) && !(Time.unscaledTime < _commitAt)) { _commitAt = 0f; if (!Mathf.Approximately(ModConfig.TickTockVolumeScale.Value, _live)) { ModConfig.TickTockVolumeScale.Value = _live; Plugin.Log.LogInfo((object)("Tick volume saved: " + _live.ToString("0.00"))); } } } private static bool Resolve() { if ((Object)(object)_bell != (Object)null && (Object)(object)_tick != (Object)null) { return true; } if (Time.unscaledTime < _nextResolveTime) { return false; } _nextResolveTime = Time.unscaledTime + 1f; SoundManager i = MonoSingleton.I; if ((Object)(object)i == (Object)null) { return false; } _bell = Refl.PomodoroBell.Invoke(i); _tick = Refl.PomodoroTickTock.Invoke(i); if ((Object)(object)_bell != (Object)null) { return (Object)(object)_tick != (Object)null; } return false; } } } namespace SleepeyDev.OnTogetherPomoSound.Patches { [HarmonyPatch] public static class UiBuildPatches { [HarmonyPatch(typeof(PomodoroController), "Start")] [HarmonyPostfix] private static void PomodoroController_Start_Postfix(PomodoroController __instance) { try { UiBuilder.BuildPomodoroUi(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("BuildPomodoroUi: " + ex)); } } } }