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 RemainingValueTracker v0.1.1
plugins/RemainingValueTracker/RemainingValueTracker.dll
Decompiled a day agousing 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<ValuableObject, bool> DiscoveredRef = AccessTools.FieldRefAccess<ValuableObject, bool>("discovered"); private static readonly FieldRef<ValuableObject, bool> DollarValueSetRef = AccessTools.FieldRefAccess<ValuableObject, bool>("dollarValueSet"); private static readonly FieldRef<ValuableObject, float> DollarValueOriginalRef = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueOriginal"); private ConfigEntry<bool> _enableMod; private ConfigEntry<TrackingMode> _trackingMode; private ConfigEntry<float> _triggerPercent; private ConfigEntry<float> _scanInterval; private ConfigEntry<KeyboardShortcut> _revealHotkey; private ConfigEntry<bool> _showMessage; private ConfigEntry<float> _messageDuration; private ConfigEntry<string> _messageText; private ConfigEntry<bool> _debugLogs; private readonly List<ValuableObject> _roundValuables = new List<ValuableObject>(); private readonly Dictionary<int, float> _initialValues = new Dictionary<int, float>(); 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<bool>("General", "Enable Mod", true, "Master switch for Remaining Value Tracker."); _trackingMode = ((BaseUnityPlugin)this).Config.Bind<TrackingMode>("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<float>("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<float>(1f, 100f), Array.Empty<object>())); _scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Scan Interval", 0.5f, new ConfigDescription("Seconds between tracker checks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())); _revealHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "Reveal Hotkey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Press this key to reveal all remaining valuables immediately, as if the configured threshold was reached."); _showMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show Message", true, "Show a top-center message when remaining valuables are revealed."); _messageDuration = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Message Duration", 4f, new ConfigDescription("Seconds to keep the reveal message visible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>())); _messageText = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "Message Text", "All remaining valuables discovered", "Message shown when the tracker reveals the remaining valuables."); _debugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("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<ValuableObject>(false); if (array == null || array.Length == 0) { return false; } List<ValuableObject> 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<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32760; CanvasScaler obj2 = _messageOverlay.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 0.5f; _messageCanvasGroup = _messageOverlay.AddComponent<CanvasGroup>(); _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<TextMeshProUGUI>(); ((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<TextMeshProUGUI>(); 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; } } } }