using System; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using FishNet; using FishNet.Managing.Timing; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: AssemblyDescription("Shows the exact synchronized time remaining before the active boss leaves.")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCompany("evansvl")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace HowToFish.BossTimer; [BepInPlugin("community.howtofish.bosstimer", "Boss Timer", "0.1.4")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "community.howtofish.bosstimer"; public const string PluginName = "Boss Timer"; public const string PluginVersion = "0.1.4"; private const float LegacyTopOffset = 125f; private const float DefaultTopOffset = 175f; private ConfigEntry _enabled; private ConfigEntry _showLabel; private ConfigEntry _showTenths; private ConfigEntry _scale; private ConfigEntry _opacity; private ConfigEntry _topOffset; private GameObject _root; private RectTransform _panel; private CanvasGroup _canvasGroup; private TextMeshProUGUI _text; private bool _nativeStyleApplied; private BossUI _nativeBossUi; private CanvasGroup _nativeCountdownGroup; private void Awake() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown _enabled = ((BaseUnityPlugin)this).Config.Bind("HUD", "Enabled", true, "Show the boss departure countdown while a boss is active."); _showLabel = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowLabel", true, "Show 'BOSS LEAVES IN' before the remaining time."); _showTenths = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowTenths", true, "Show tenths of a second."); _scale = ((BaseUnityPlugin)this).Config.Bind("HUD", "Scale", 1f, new ConfigDescription("HUD scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.6f, 1.8f), new object[0])); _opacity = ((BaseUnityPlugin)this).Config.Bind("HUD", "Opacity", 1f, new ConfigDescription("HUD opacity.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1f), new object[0])); _topOffset = ((BaseUnityPlugin)this).Config.Bind("HUD", "TopOffset", 175f, new ConfigDescription("Distance from the top of the screen.", (AcceptableValueBase)(object)new AcceptableValueRange(60f, 350f), new object[0])); if (Mathf.Approximately(_topOffset.Value, 125f)) { _topOffset.Value = 175f; } CreateHud(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded. Countdown reads BossManager's synchronized leave tick and never changes gameplay state."); } private void Update() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!_enabled.Value || !IsGameplayHudVisible() || !TryGetRemainingSeconds(out var seconds)) { SetVisible(visible: false); return; } ApplyNativeStyleWhenAvailable(); ApplyLiveSettings(); ((TMP_Text)_text).text = (_showLabel.Value ? "BOSS LEAVES IN " : string.Empty) + FormatRemaining(seconds); ((Graphic)_text).color = CountdownColor(seconds, _opacity.Value); float nativeCountdownAlpha = GetNativeCountdownAlpha(); _canvasGroup.alpha = ((nativeCountdownAlpha > 0.001f) ? Mathf.MoveTowards(_canvasGroup.alpha, 0f, Time.unscaledDeltaTime * 2f) : 1f); SetVisible(_canvasGroup.alpha > 0.001f); } private static bool IsGameplayHudVisible() { if (MainMenuManager.IsInMenu || PauseManager.IsPaused) { return false; } try { return PlayerUI.BossCanvasActive; } catch { return false; } } private static bool TryGetRemainingSeconds(out double seconds) { seconds = 0.0; if (MainMenuManager.IsInMenu) { return false; } Creature boss = BossManager.Boss; if ((Object)(object)boss == (Object)null || boss.IsDead) { return false; } TimeManager timeManager = InstanceFinder.TimeManager; if ((Object)(object)timeManager == (Object)null || timeManager.TickRate == 0) { return false; } uint bossTotalTimeInTicks = BossManager.BossTotalTimeInTicks; if (bossTotalTimeInTicks == 0) { return false; } uint num = BossManager.BossLeavesTick - timeManager.Tick; if (num > bossTotalTimeInTicks) { return false; } seconds = (double)num / (double)(int)timeManager.TickRate; return true; } private string FormatRemaining(double seconds) { if (_showTenths.Value) { double num = Math.Ceiling(Math.Max(0.0, seconds) * 10.0) / 10.0; int num2 = (int)(num / 60.0); double num3 = num - (double)num2 * 60.0; return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00.0}", num2, num3); } int num4 = (int)Math.Ceiling(Math.Max(0.0, seconds)); return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00}", num4 / 60, num4 % 60); } private void CreateHud() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_008b: 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_00d8: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) _root = new GameObject("BossTimerHUD", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler) }); Object.DontDestroyOnLoad((Object)(object)_root); Canvas component = _root.GetComponent(); component.renderMode = (RenderMode)0; component.sortingOrder = 32761; CanvasScaler component2 = _root.GetComponent(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); component2.screenMatchMode = (ScreenMatchMode)0; component2.matchWidthOrHeight = 0.5f; GameObject val = new GameObject("Anchor", new Type[2] { typeof(RectTransform), typeof(CanvasGroup) }); val.transform.SetParent(_root.transform, false); _panel = val.GetComponent(); _canvasGroup = val.GetComponent(); RectTransform panel = _panel; Vector2 anchorMin = (_panel.anchorMax = new Vector2(0.5f, 1f)); panel.anchorMin = anchorMin; _panel.pivot = new Vector2(0.5f, 1f); _panel.sizeDelta = new Vector2(700f, 64f); GameObject val3 = new GameObject("Countdown", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI) }); val3.transform.SetParent((Transform)(object)_panel, false); _text = val3.GetComponent(); RectTransform rectTransform = ((TMP_Text)_text).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; ((TMP_Text)_text).fontSize = 31f; ((TMP_Text)_text).alignment = (TextAlignmentOptions)258; ((TMP_Text)_text).enableWordWrapping = false; ((Graphic)_text).raycastTarget = false; ((TMP_Text)_text).overflowMode = (TextOverflowModes)0; ((TMP_Text)_text).outlineColor = new Color32((byte)20, (byte)18, (byte)18, byte.MaxValue); ((TMP_Text)_text).outlineWidth = 0.18f; _root.SetActive(false); } private float GetNativeCountdownAlpha() { if ((Object)(object)_nativeBossUi == (Object)null || (Object)(object)_nativeCountdownGroup == (Object)null) { FindNativeCountdownGroup(); } if ((Object)(object)_nativeCountdownGroup == (Object)null || !((Component)_nativeCountdownGroup).gameObject.activeInHierarchy) { return 0f; } return Mathf.Clamp01(_nativeCountdownGroup.alpha); } private void FindNativeCountdownGroup() { _nativeBossUi = null; _nativeCountdownGroup = null; FieldInfo field = typeof(BossUI).GetField("_countdownGroup", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return; } BossUI[] array = Resources.FindObjectsOfTypeAll(); BossUI[] array2 = array; foreach (BossUI val in array2) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { object? value = field.GetValue(val); CanvasGroup val2 = (CanvasGroup)((value is CanvasGroup) ? value : null); if (!((Object)(object)val2 == (Object)null)) { _nativeBossUi = val; _nativeCountdownGroup = val2; break; } } } } private void ApplyNativeStyleWhenAvailable() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (_nativeStyleApplied) { return; } TextMeshProUGUI val = FindNativeCountdownText(); if ((Object)(object)val == (Object)null) { val = FindVersionText(); } if (!((Object)(object)val == (Object)null) && !((Object)(object)((TMP_Text)val).font == (Object)null)) { ((TMP_Text)_text).font = ((TMP_Text)val).font; if ((Object)(object)((TMP_Text)val).fontSharedMaterial != (Object)null) { ((TMP_Text)_text).fontSharedMaterial = ((TMP_Text)val).fontSharedMaterial; } ((TMP_Text)_text).characterSpacing = ((TMP_Text)val).characterSpacing; ((TMP_Text)_text).outlineColor = new Color32((byte)20, (byte)18, (byte)18, byte.MaxValue); ((TMP_Text)_text).outlineWidth = 0.18f; _nativeStyleApplied = true; } } private static TextMeshProUGUI FindNativeCountdownText() { BossUI[] array = Resources.FindObjectsOfTypeAll(); FieldInfo field = typeof(BossUI).GetField("_timeCountdownText", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return null; } BossUI[] array2 = array; foreach (BossUI val in array2) { if (!((Object)(object)val == (Object)null)) { object? value = field.GetValue(val); TextMeshProUGUI val2 = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } private static TextMeshProUGUI FindVersionText() { TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll(); TextMeshProUGUI[] array2 = array; foreach (TextMeshProUGUI val in array2) { if ((Object)(object)val != (Object)null && ((TMP_Text)val).text != null && ((TMP_Text)val).text.IndexOf("Version", StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } return null; } private void ApplyLiveSettings() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) ((Transform)_panel).localScale = Vector3.one * _scale.Value; _panel.anchoredPosition = new Vector2(0f, 0f - _topOffset.Value); } private static Color CountdownColor(double seconds, float opacity) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (seconds <= 5.0) { return new Color(1f, 0.24f, 0.13f, opacity); } if (seconds <= 10.0) { return new Color(1f, 0.53f, 0.08f, opacity); } return new Color(1f, 1f, 1f, opacity); } private void SetVisible(bool visible) { if ((Object)(object)_root != (Object)null && _root.activeSelf != visible) { _root.SetActive(visible); } } private void OnDestroy() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } } }