using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("CookingBellTimer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.12.0")] [assembly: AssemblyInformationalVersion("0.3.12")] [assembly: AssemblyProduct("CookingBellTimer")] [assembly: AssemblyTitle("CookingBellTimer")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.3.12.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : 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(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 CookingBellTimer { internal static class BellAudio { internal static AudioClip? Bell; private static AudioSource? _source; private static bool _paused; private static bool _playedForCurrentItem; internal static bool PlayedForCurrentItem => _playedForCurrentItem; internal static void Initialize(MonoBehaviour host) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown GameObject val = new GameObject("CookingBellTimer_Audio"); Object.DontDestroyOnLoad((Object)val); _source = val.AddComponent(); _source.spatialBlend = 0f; _source.dopplerLevel = 0f; _source.bypassReverbZones = true; _source.playOnAwake = false; _source.loop = false; host.StartCoroutine(LoadBell()); } private static IEnumerator LoadBell() { string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "sounds", "ding.ogg"); if (!File.Exists(text)) { Plugin.Log.LogError((object)("Missing bell sound: " + text)); yield break; } UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(new Uri(text).AbsoluteUri, (AudioType)14); try { yield return req.SendWebRequest(); if ((int)req.result != 1) { Plugin.Log.LogError((object)("Failed loading bell: " + req.error)); yield break; } Bell = DownloadHandlerAudioClip.GetContent(req); Plugin.Log.LogInfo((object)$"Loaded bell ({Bell.length:0.00}s)"); } finally { ((IDisposable)req)?.Dispose(); } } internal static void PlayOnce() { if ((Object)(object)_source != (Object)null && (Object)(object)Bell != (Object)null && !_playedForCurrentItem) { _source.Stop(); _source.clip = Bell; _source.loop = false; _source.volume = Plugin.BellVolume.Value; _source.time = 0f; _source.Play(); _paused = false; _playedForCurrentItem = true; Plugin.Log.LogDebug((object)"Bell triggered."); } } internal static void Pause() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if (!((Object)_source == (Object)null) && _source.isPlaying) { _source.Pause(); _paused = true; } } internal static void Resume() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if (!((Object)_source == (Object)null) && _paused) { _source.UnPause(); _paused = false; } } internal static void Tick() { } internal static void ResetForNewItem() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)_source != (Object)null) { _source.Stop(); _source.clip = null; } _paused = false; _playedForCurrentItem = false; } internal static void StopForBurnt() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)_source != (Object)null) { _source.Stop(); } _paused = false; } } internal static class CookingHook { public static void Postfix(object __instance, float prev, float next, bool asServer) { try { if (!(next <= prev) && RuntimeTargets.WasCookedByLocalPlayer(__instance)) { CookingTracker.Track(__instance); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Cooking hook failed: " + ex.Message)); } } } internal static class CookingOverlay { private const float MinCook = 1f; private const float MaxCook = 1.5f; private const float Marker = 1.45f; private static float _displayMultiplier = 1f; private static float _burnProgress; private static float _lastUpdate = -999f; private static bool _visible; private static bool _burning; private static Texture2D? _pixel; private static GUIStyle? _titleStyle; private static GUIStyle? _markerStyle; private static GUIStyle? _burningStyle; internal static void Initialize() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0013: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0057: 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_0063: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown _pixel = new Texture2D(1, 1); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); GUIStyle val = new GUIStyle { alignment = (TextAnchor)4, fontSize = 20, fontStyle = (FontStyle)1 }; val.normal.textColor = Color.white; _titleStyle = val; GUIStyle val2 = new GUIStyle { alignment = (TextAnchor)1, fontSize = 12, fontStyle = (FontStyle)1 }; val2.normal.textColor = Color.white; _markerStyle = val2; GUIStyle val3 = new GUIStyle { alignment = (TextAnchor)4, fontSize = 22, fontStyle = (FontStyle)1 }; val3.normal.textColor = new Color(1f, 0.86f, 0.12f, 1f); _burningStyle = val3; } internal static void ReportCook(float displayedMultiplier, bool burning, float burnProgress) { _displayMultiplier = Mathf.Max(0f, displayedMultiplier); _burning = burning; _burnProgress = Mathf.Clamp01(burnProgress); _lastUpdate = Time.unscaledTime; _visible = true; } internal static void HideImmediately() { _visible = false; _displayMultiplier = 1f; _burning = false; _burnProgress = 0f; _lastUpdate = -999f; } internal static void Tick() { if (_visible && Time.unscaledTime - _lastUpdate > Plugin.OverlayHideDelay.Value) { _visible = false; } } internal static void Draw() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (_visible && !((Object)_pixel == (Object)null) && _titleStyle != null && _markerStyle != null && _burningStyle != null) { float value = Plugin.OverlayWidth.Value; float value2 = Plugin.OverlayHeight.Value; float num = ((float)Screen.width - value) * 0.5f; float num2 = (float)Screen.height - Plugin.OverlayBottomOffset.Value - value2; Rect rect = new Rect(num - 3f, num2 - 3f, value + 6f, value2 + 6f); Rect val = default(Rect); ((Rect)(ref val))..ctor(num, num2, value, value2); DrawRect(rect, new Color(0f, 0f, 0f, 0.92f)); if (_burning) { Color val2 = new Color(0.34f, 0.16f, 0.055f, 0.98f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.015f, 0.008f, 0.004f, 0.99f); Color color = Color.Lerp(val2, val3, _burnProgress); DrawRect(val, color); GUI.Label(new Rect(num, num2 - 34f, value, 30f), $"BURNING {_displayMultiplier:0.00}x", _burningStyle); } else { DrawRect(val, new Color(0.08f, 0.08f, 0.08f, 0.94f)); float num3 = Mathf.InverseLerp(1f, 1.5f, Mathf.Clamp(_displayMultiplier, 1f, 1.5f)); DrawRect(new Rect(num, num2, value * num3, value2), GetCookingGradient(_displayMultiplier)); DrawMarker(1.45f, val, "1.45x"); GUI.Label(new Rect(num, num2 - 32f, value, 28f), $"COOKING {_displayMultiplier:0.00}x", _titleStyle); } } } private static Color GetCookingGradient(float multiplier) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) //IL_0094: 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_00a6: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(0.18f, 0.82f, 0.28f, 0.98f); Color val2 = default(Color); ((Color)(ref val2))..ctor(1f, 0.9f, 0.12f, 0.98f); Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 0.52f, 0.08f, 0.98f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.95f, 0.12f, 0.08f, 0.98f); if (multiplier <= 1.25f) { return Color.Lerp(val, val2, Mathf.InverseLerp(1f, 1.25f, multiplier)); } if (multiplier <= 1.4f) { return Color.Lerp(val2, val3, Mathf.InverseLerp(1.25f, 1.4f, multiplier)); } return Color.Lerp(val3, val4, Mathf.InverseLerp(1.4f, 1.5f, multiplier)); } private static void DrawMarker(float value, Rect bar, string label) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.InverseLerp(1f, 1.5f, value); float num2 = ((Rect)(ref bar)).x + ((Rect)(ref bar)).width * num; DrawRect(new Rect(num2 - 1.5f, ((Rect)(ref bar)).y - 4f, 3f, ((Rect)(ref bar)).height + 8f), Color.white); GUI.Label(new Rect(num2 - 38f, ((Rect)(ref bar)).y + ((Rect)(ref bar)).height + 4f, 76f, 20f), label, _markerStyle); } private static void DrawRect(Rect rect, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)_pixel); GUI.color = color2; } } internal static class CookingTracker { private static WeakReference? _trackedItem; private static CooknessAccessor? _accessor; private static DisplayedMultiplierAccessor? _displayAccessor; private static object? _currentIdentity; private const float RawPerfect = 1f; private static float _lastRawCookness = 0f; private static float _lastDisplayedMultiplier = 1f; private static float _lastCookCallTime = -999f; private static bool _sessionActive; internal static void Track(object item) { if (item != null) { if (_currentIdentity == null || _currentIdentity != item) { _currentIdentity = item; _trackedItem = new WeakReference(item); _accessor = CooknessAccessor.Resolve(item.GetType()); _displayAccessor = DisplayedMultiplierAccessor.Resolve(item.GetType()); _sessionActive = false; _lastRawCookness = 0f; _lastDisplayedMultiplier = 1f; BellAudio.ResetForNewItem(); } if (_accessor != null) { _sessionActive = true; _lastCookCallTime = Time.unscaledTime; float rawCookness = _accessor.Read(item); Sample(item, rawCookness); } } } internal static void Tick() { if (_sessionActive && Time.unscaledTime - _lastCookCallTime > 0.3f) { _sessionActive = false; BellAudio.Pause(); } else { if (!_sessionActive || _trackedItem == null || !_trackedItem.IsAlive || _accessor == null) { return; } object target = _trackedItem.Target; if (target != null) { Object val = (Object)((target is Object) ? target : null); if (val == null || !(val == (Object)null)) { float rawCookness = _accessor.Read(target); Sample(target, rawCookness); } } } } private static void Sample(object item, float rawCookness) { rawCookness = Mathf.Max(0f, rawCookness); bool flag = rawCookness > 1.0005f; float displayedMultiplier = GetDisplayedMultiplier(item, rawCookness, flag); if (rawCookness > 5E-05f) { CookingOverlay.ReportCook(displayedMultiplier, flag, GetBurnProgress(rawCookness)); } if (!flag && !BellAudio.PlayedForCurrentItem && _lastDisplayedMultiplier < Plugin.BellThreshold.Value && displayedMultiplier >= Plugin.BellThreshold.Value) { BellAudio.PlayOnce(); } else if (BellAudio.PlayedForCurrentItem) { BellAudio.Resume(); } _lastRawCookness = rawCookness; _lastDisplayedMultiplier = displayedMultiplier; } private static float GetDisplayedMultiplier(object item, float rawCookness, bool burning) { if (_displayAccessor != null && _displayAccessor.TryRead(item, out var value) && value >= 0f && value <= 2f) { return value; } if (!burning) { return 1f + Mathf.Clamp01(rawCookness) * 0.5f; } float num = Mathf.Max(0f, rawCookness - 1f); return Mathf.Max(0f, 1.5f - num * 0.5f); } private static float GetBurnProgress(float rawCookness) { if (rawCookness <= 1f) { return 0f; } return Mathf.Clamp01(rawCookness - 1f); } } internal sealed class CooknessAccessor { internal readonly Type TargetType; private readonly PropertyInfo? _cooknessProperty; private readonly FieldInfo? _syncField; private readonly PropertyInfo? _syncValueProperty; private CooknessAccessor(Type type, PropertyInfo property) { TargetType = type; _cooknessProperty = property; } private CooknessAccessor(Type type, FieldInfo field, PropertyInfo valueProperty) { TargetType = type; _syncField = field; _syncValueProperty = valueProperty; } internal static CooknessAccessor? Resolve(Type type) { PropertyInfo property = type.GetProperty("Cookness", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead && IsNumeric(property.PropertyType)) { Plugin.Log.LogInfo((object)("Using exact public cookness property: " + type.Name + ".Cookness")); return new CooknessAccessor(type, property); } FieldInfo field = type.GetField("_cookness", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { PropertyInfo property2 = field.FieldType.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null && property2.CanRead && IsNumeric(property2.PropertyType)) { Plugin.Log.LogWarning((object)"Public Cookness property missing; falling back to _cookness.Value"); return new CooknessAccessor(type, field, property2); } } Plugin.Log.LogError((object)("Could not resolve Cookness on " + type.FullName)); return null; } internal float Read(object target) { try { object obj = null; if (_cooknessProperty != null) { obj = _cooknessProperty.GetValue(target); } else if (_syncField != null && _syncValueProperty != null) { object value = _syncField.GetValue(target); if (value != null) { obj = _syncValueProperty.GetValue(value); } } if (obj is float result) { return result; } if (obj is double num) { return (float)num; } if (obj is int num2) { return num2; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Cookness read failed: " + ex.Message)); } return 1f; } private static bool IsNumeric(Type type) { if (!(type == typeof(float)) && !(type == typeof(double))) { return type == typeof(int); } return true; } } internal sealed class DisplayedMultiplierAccessor { internal readonly Type TargetType; private readonly PropertyInfo? _property; private readonly FieldInfo? _field; private readonly MethodInfo? _method; private DisplayedMultiplierAccessor(Type type, PropertyInfo property) { TargetType = type; _property = property; } private DisplayedMultiplierAccessor(Type type, FieldInfo field) { TargetType = type; _field = field; } private DisplayedMultiplierAccessor(Type type, MethodInfo method) { TargetType = type; _method = method; } internal static DisplayedMultiplierAccessor? Resolve(Type type) { string[] array = new string[6] { "CookingMultiplier", "CookMultiplier", "CookedMultiplier", "CookingValueMultiplier", "CookValueMultiplier", "CookWorthMultiplier" }; foreach (string name in array) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead && IsNumeric(property.PropertyType)) { Plugin.Log.LogInfo((object)("Using direct displayed cooking multiplier property: " + type.Name + "." + property.Name)); return new DisplayedMultiplierAccessor(type, property); } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && IsNumeric(field.FieldType)) { Plugin.Log.LogInfo((object)("Using direct displayed cooking multiplier field: " + type.Name + "." + field.Name)); return new DisplayedMultiplierAccessor(type, field); } } array = new string[3] { "GetCookingMultiplier", "GetCookMultiplier", "GetCookedMultiplier" }; foreach (string name2 in array) { MethodInfo method = type.GetMethod(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null && IsNumeric(method.ReturnType)) { Plugin.Log.LogInfo((object)("Using direct displayed cooking multiplier method: " + type.Name + "." + method.Name + "()")); return new DisplayedMultiplierAccessor(type, method); } } Plugin.Log.LogInfo((object)"No direct displayed cooking multiplier member found; using cookness mapping fallback."); return null; } internal bool TryRead(object target, out float value) { value = 0f; try { object obj = null; if (_property != null) { obj = _property.GetValue(target); } else if (_field != null) { obj = _field.GetValue(target); } else if (_method != null) { obj = _method.Invoke(target, null); } if (obj is float num) { value = num; return true; } if (obj is double num2) { value = (float)num2; return true; } if (obj is int num3) { value = num3; return true; } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Direct multiplier read failed; fallback mapping used: " + ex.Message)); } return false; } private static bool IsNumeric(Type t) { if (!(t == typeof(float)) && !(t == typeof(double))) { return t == typeof(int); } return true; } } [BepInPlugin("ponyfisher.howtofish.cookingbelltimer", "Cooking Bell Timer", "0.3.12")] [BepInProcess("How to Fish.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "ponyfisher.howtofish.cookingbelltimer"; public const string Name = "Cooking Bell Timer"; public const string Version = "0.3.12"; internal static Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry BellThreshold; internal static ConfigEntry BellVolume; internal static ConfigEntry OverlayEnabled; internal static ConfigEntry OverlayWidth; internal static ConfigEntry OverlayHeight; internal static ConfigEntry OverlayBottomOffset; internal static ConfigEntry OverlayHideDelay; private Harmony _harmony; private void Awake() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BellThreshold = ((BaseUnityPlugin)this).Config.Bind("Timing", "BellThreshold", 1.48f, "Displayed cookness multiplier where the bell plays once."); BellVolume = ((BaseUnityPlugin)this).Config.Bind("Audio", "BellVolume", 0.27f, new ConfigDescription("Bell volume. Default is 0.27, which is 30% of the previous 0.90 playback level.", (AcceptableValueBase)new AcceptableValueRange(0f, 1f), Array.Empty())); OverlayEnabled = ((BaseUnityPlugin)this).Config.Bind("Overlay", "Enabled", true, "Show the horizontal cooking progress bar."); OverlayWidth = ((BaseUnityPlugin)this).Config.Bind("Overlay", "Width", 560f, new ConfigDescription("Cooking bar width in pixels.", (AcceptableValueBase)new AcceptableValueRange(280f, 1100f), Array.Empty())); OverlayHeight = ((BaseUnityPlugin)this).Config.Bind("Overlay", "Height", 32f, new ConfigDescription("Cooking bar height in pixels.", (AcceptableValueBase)new AcceptableValueRange(16f, 70f), Array.Empty())); OverlayBottomOffset = ((BaseUnityPlugin)this).Config.Bind("Overlay", "BottomOffset", 235f, new ConfigDescription("Distance from bottom of screen.", (AcceptableValueBase)new AcceptableValueRange(30f, 600f), Array.Empty())); OverlayHideDelay = ((BaseUnityPlugin)this).Config.Bind("Overlay", "HideDelay", 0.9f, new ConfigDescription("Seconds before the bar hides after cooking stops.", (AcceptableValueBase)new AcceptableValueRange(0.2f, 4f), Array.Empty())); BellAudio.Initialize((MonoBehaviour)this); CookingOverlay.Initialize(); _harmony = new Harmony("ponyfisher.howtofish.cookingbelltimer"); MethodInfo methodInfo = RuntimeTargets.ResolveCooknessChangedMethod(); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CookingHook), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched synchronized cooking update: " + methodInfo.DeclaringType?.FullName + "." + methodInfo.Name)); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find Item.OnCooknessChange."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Cooking Bell Timer 0.3.12 loaded."); } private void Update() { CookingTracker.Tick(); CookingOverlay.Tick(); BellAudio.Tick(); } private void OnGUI() { if (OverlayEnabled.Value) { CookingOverlay.Draw(); } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } } internal static class RuntimeTargets { internal static Type? ItemType; private static PropertyInfo? _lastHolderProperty; private static PropertyInfo? _localPlayerProperty; private static FieldInfo? _localPlayerField; internal static MethodInfo? ResolveCooknessChangedMethod() { ItemType = AccessTools.TypeByName("Item"); if (ItemType == null) { return null; } _lastHolderProperty = AccessTools.Property(ItemType, "LastHolder"); Type type = AccessTools.TypeByName("Player"); if (type != null) { _localPlayerProperty = type.GetProperty("LocalPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _localPlayerField = type.GetField("LocalPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if (_lastHolderProperty == null) { Plugin.Log.LogError((object)"Could not resolve Item.LastHolder."); } if (_localPlayerProperty == null && _localPlayerField == null) { Plugin.Log.LogError((object)"Could not resolve Player.LocalPlayer."); } else { Plugin.Log.LogInfo((object)"Resolved local player identity for per-player cooking timers."); } return AccessTools.Method(ItemType, "OnCooknessChange", new Type[3] { typeof(float), typeof(float), typeof(bool) }, (Type[])null); } internal static bool WasCookedByLocalPlayer(object item) { if (item == null || _lastHolderProperty == null || (_localPlayerProperty == null && _localPlayerField == null)) { return false; } object value = _lastHolderProperty.GetValue(item); object obj = _localPlayerProperty?.GetValue(null) ?? _localPlayerField?.GetValue(null); if (value != null && obj != null) { return value == obj; } return false; } } }