using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; 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 TMPro; using UnityEngine; 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("RemainingValueTracker")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+2ecebdac645edc5ee1df86f6ccd60ee8e75c3a72")] [assembly: AssemblyProduct("RemainingValueTracker")] [assembly: AssemblyTitle("RemainingValueTracker")] [assembly: AssemblyVersion("0.1.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 RemainingValueTracker { [BepInPlugin("DarkSpider90.RemainingValueTracker", "Remaining Value Tracker", "0.1.1")] public sealed class Plugin : BaseUnityPlugin { private enum TrackingMode { Value, Count } private readonly struct TrackerProgress { internal static readonly TrackerProgress Empty = new TrackerProgress(0f, 0f); internal float Discovered { get; } internal float Total { get; } internal float Percent { get { if (!(Total <= 0f)) { return Discovered / Total * 100f; } return 0f; } } internal bool HasData => Total > 0f; internal TrackerProgress(float discovered, float total) { Discovered = discovered; Total = total; } } internal const string PluginGuid = "DarkSpider90.RemainingValueTracker"; internal const string PluginName = "Remaining Value Tracker"; internal const string PluginVersion = "0.1.1"; private const float DefaultScanInterval = 0.5f; private static readonly Color MessageColor = new Color(0.8f, 1f, 0.35f); private static readonly Color MessageFlashColor = new Color(1f, 1f, 0.2f); private static readonly Color MessageShadowColor = new Color(0f, 0f, 0f, 0.75f); private static readonly FieldRef DiscoveredRef = AccessTools.FieldRefAccess("discovered"); private static readonly FieldRef DollarValueSetRef = AccessTools.FieldRefAccess("dollarValueSet"); private static readonly FieldRef DollarValueOriginalRef = AccessTools.FieldRefAccess("dollarValueOriginal"); private ConfigEntry _enableMod; private ConfigEntry _trackingMode; private ConfigEntry _triggerPercent; private ConfigEntry _scanInterval; private ConfigEntry _revealHotkey; private ConfigEntry _showMessage; private ConfigEntry _messageDuration; private ConfigEntry _messageText; private ConfigEntry _debugLogs; private readonly List _roundValuables = new List(); private readonly Dictionary _initialValues = new Dictionary(); private int _levelInstanceId; private bool _snapshotReady; private bool _revealed; private float _nextScanTime; private Coroutine _messageCoroutine; private GameObject _messageOverlay; private CanvasGroup _messageCanvasGroup; private TextMeshProUGUI _messageLabel; private TextMeshProUGUI _messageShadow; private bool _isQuitting; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _enableMod = ((BaseUnityPlugin)this).Config.Bind("General", "Enable Mod", true, "Master switch for Remaining Value Tracker."); _trackingMode = ((BaseUnityPlugin)this).Config.Bind("General", "Tracking Mode", TrackingMode.Value, "Value reveals remaining valuables after the configured percent of total value is discovered. Count uses item count instead."); _triggerPercent = ((BaseUnityPlugin)this).Config.Bind("General", "Trigger Percent", 85f, new ConfigDescription("Percent of the round's valuables that must be discovered before all remaining valuables are revealed.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); _scanInterval = ((BaseUnityPlugin)this).Config.Bind("General", "Scan Interval", 0.5f, new ConfigDescription("Seconds between tracker checks.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); _revealHotkey = ((BaseUnityPlugin)this).Config.Bind("Controls", "Reveal Hotkey", new KeyboardShortcut((KeyCode)291, Array.Empty()), "Press this key to reveal all remaining valuables immediately, as if the configured threshold was reached."); _showMessage = ((BaseUnityPlugin)this).Config.Bind("UI", "Show Message", true, "Show a top-center message when remaining valuables are revealed."); _messageDuration = ((BaseUnityPlugin)this).Config.Bind("UI", "Message Duration", 4f, new ConfigDescription("Seconds to keep the reveal message visible.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 15f), Array.Empty())); _messageText = ((BaseUnityPlugin)this).Config.Bind("UI", "Message Text", "All remaining valuables discovered", "Message shown when the tracker reveals the remaining valuables."); _debugLogs = ((BaseUnityPlugin)this).Config.Bind("Diagnostics", "Debug Logs", false, "Print tracker snapshot and reveal details to the BepInEx log."); Log.LogInfo((object)"Remaining Value Tracker v0.1.1 loaded for R.E.P.O. v0.4.0."); } private void OnApplicationQuit() { _isQuitting = true; CleanupMessageOverlay(); } private void OnDestroy() { _isQuitting = true; CleanupMessageOverlay(); } private void Update() { if (_isQuitting || !_enableMod.Value) { return; } if (!LevelIsReady()) { ResetRound(); return; } int instanceID = ((Object)LevelGenerator.Instance).GetInstanceID(); if (_levelInstanceId != instanceID) { ResetRound(instanceID); } if (TryRevealByHotkey() || _revealed || Time.time < _nextScanTime) { return; } _nextScanTime = Time.time + Mathf.Max(0.1f, _scanInterval.Value); if (!_snapshotReady && !TryBuildSnapshot()) { return; } TrackerProgress trackerProgress = CalculateProgress(); if (trackerProgress.HasData) { if (_debugLogs.Value) { Log.LogInfo((object)$"Progress: {trackerProgress.Percent:0.##}% by {_trackingMode.Value} ({trackerProgress.Discovered:0.##}/{trackerProgress.Total:0.##})."); } float num = Mathf.Clamp(_triggerPercent.Value, 1f, 100f); if (trackerProgress.Percent >= num) { Log.LogInfo((object)$"Reveal threshold reached: {trackerProgress.Percent:0.##}% >= {num:0.##}%."); RevealRemaining(); } } } private bool TryRevealByHotkey() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!_revealed) { KeyboardShortcut value = _revealHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { if (!_snapshotReady && !TryBuildSnapshot()) { Log.LogWarning((object)"Reveal hotkey was pressed, but valuables are not ready to scan yet."); return false; } Log.LogInfo((object)"Reveal hotkey pressed."); RevealRemaining(); return true; } } return false; } private static bool LevelIsReady() { try { return (Object)(object)RunManager.instance != (Object)null && (Object)(object)LevelGenerator.Instance != (Object)null && LevelGenerator.Instance.Generated && (Object)(object)ValuableDirector.instance != (Object)null && (Object)(object)Map.Instance != (Object)null && SemiFunc.RunIsLevel(); } catch (Exception) { return false; } } private bool TryBuildSnapshot() { ValuableObject[] array = Object.FindObjectsOfType(false); if (array == null || array.Length == 0) { return false; } List list = array.Where((ValuableObject valuable) => (Object)(object)valuable != (Object)null && ((Behaviour)valuable).isActiveAndEnabled).Distinct().ToList(); if (list.Count == 0 || list.Any((ValuableObject valuable) => !DollarValueSetRef.Invoke(valuable))) { return false; } _roundValuables.Clear(); _roundValuables.AddRange(list); _initialValues.Clear(); foreach (ValuableObject roundValuable in _roundValuables) { _initialValues[((Object)roundValuable).GetInstanceID()] = Mathf.Max(0f, DollarValueOriginalRef.Invoke(roundValuable)); } _snapshotReady = true; if (_debugLogs.Value) { float num = _initialValues.Values.Sum(); Log.LogInfo((object)$"Snapshot ready: {_roundValuables.Count} valuables, total value {num:0}."); } return true; } private TrackerProgress CalculateProgress() { if (_roundValuables.Count == 0) { return TrackerProgress.Empty; } float num = 0f; float num2 = 0f; foreach (ValuableObject roundValuable in _roundValuables) { if ((Object)(object)roundValuable == (Object)null) { continue; } float value; if (_trackingMode.Value == TrackingMode.Count) { num2 += 1f; if (DiscoveredRef.Invoke(roundValuable)) { num += 1f; } } else if (_initialValues.TryGetValue(((Object)roundValuable).GetInstanceID(), out value)) { num2 += value; if (DiscoveredRef.Invoke(roundValuable)) { num += value; } } } if (num2 <= 0f) { return TrackerProgress.Empty; } return new TrackerProgress(num, num2); } private void RevealRemaining() { _revealed = true; int num = 0; foreach (ValuableObject roundValuable in _roundValuables) { if (!((Object)(object)roundValuable == (Object)null) && !DiscoveredRef.Invoke(roundValuable)) { try { roundValuable.Discover((State)0); num++; } catch (Exception ex) { Log.LogWarning((object)("Could not reveal " + ((Object)roundValuable).name + ": " + ex.Message)); } } } if (_showMessage.Value) { ShowRevealMessage(); } Log.LogInfo((object)$"Revealed {num} remaining valuables."); } private void ShowRevealMessage() { if (!_isQuitting) { if (_messageCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_messageCoroutine); } _messageCoroutine = ((MonoBehaviour)this).StartCoroutine(ShowRevealMessageRoutine()); } } private IEnumerator ShowRevealMessageRoutine() { EnsureMessageOverlay(); string value = _messageText.Value; float duration = Mathf.Clamp(_messageDuration.Value, 0.5f, 15f); float endTime = Time.time + duration; float fadeIn = Mathf.Min(0.2f, duration * 0.25f); float fadeOut = Mathf.Min(0.35f, duration * 0.3f); SetOverlayText(value); _messageOverlay.SetActive(true); Log.LogInfo((object)$"Showing reveal message for {duration:0.##}s."); while (Time.time < endTime) { float num = duration - (endTime - Time.time); float num2 = endTime - Time.time; float alpha = 1f; if (fadeIn > 0f && num < fadeIn) { alpha = Mathf.Clamp01(num / fadeIn); } else if (fadeOut > 0f && num2 < fadeOut) { alpha = Mathf.Clamp01(num2 / fadeOut); } _messageCanvasGroup.alpha = alpha; yield return null; } _messageCanvasGroup.alpha = 0f; _messageOverlay.SetActive(false); _messageCoroutine = null; } private void EnsureMessageOverlay() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_messageOverlay != (Object)null)) { _messageOverlay = new GameObject("RemainingValueTracker Message Overlay"); Object.DontDestroyOnLoad((Object)(object)_messageOverlay); Canvas obj = _messageOverlay.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32760; CanvasScaler obj2 = _messageOverlay.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 0.5f; _messageCanvasGroup = _messageOverlay.AddComponent(); _messageCanvasGroup.blocksRaycasts = false; _messageCanvasGroup.interactable = false; _messageShadow = CreateOverlayText("Message Shadow", MessageShadowColor, new Vector2(2f, -2f)); _messageLabel = CreateOverlayText("Message", MessageColor, Vector2.zero); _messageOverlay.SetActive(false); } } private TextMeshProUGUI CreateOverlayText(string name, Color color, Vector2 offset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(_messageOverlay.transform, false); TextMeshProUGUI val2 = val.AddComponent(); ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((Graphic)val2).color = color; ((TMP_Text)val2).fontSize = 36f; ((TMP_Text)val2).enableAutoSizing = true; ((TMP_Text)val2).fontSizeMin = 18f; ((TMP_Text)val2).fontSizeMax = 38f; ((TMP_Text)val2).enableWordWrapping = true; TMP_FontAsset val3 = FindExistingFont(); if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val2).font = val3; } RectTransform rectTransform = ((TMP_Text)val2).rectTransform; rectTransform.anchorMin = new Vector2(0.5f, 1f); rectTransform.anchorMax = new Vector2(0.5f, 1f); rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.anchoredPosition = new Vector2(offset.x, -95f + offset.y); rectTransform.sizeDelta = new Vector2(1200f, 96f); return val2; } private static TMP_FontAsset FindExistingFont() { TextMeshProUGUI val = Object.FindObjectOfType(); if (!((Object)(object)val != (Object)null)) { return null; } return ((TMP_Text)val).font; } private void SetOverlayText(string message) { ((TMP_Text)_messageLabel).text = message; ((TMP_Text)_messageShadow).text = message; } private void ResetRound(int levelInstanceId = 0) { StopMessageCoroutine(); _levelInstanceId = levelInstanceId; _snapshotReady = false; _revealed = false; _nextScanTime = 0f; _roundValuables.Clear(); _initialValues.Clear(); } private void StopMessageCoroutine() { if (_messageCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_messageCoroutine); _messageCoroutine = null; } } private void CleanupMessageOverlay() { StopMessageCoroutine(); if (!((Object)(object)_messageOverlay == (Object)null)) { Object.Destroy((Object)(object)_messageOverlay); _messageOverlay = null; _messageCanvasGroup = null; _messageLabel = null; _messageShadow = null; } } } }