using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Assets.Scripts.Actors.Player;
using Assets.Scripts.Inventory__Items__Pickups.Chests;
using Assets.Scripts.Inventory__Items__Pickups.Stats;
using Assets.Scripts.Menu.Shop;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("UsefullInfoUI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UsefullInfoUI")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("18eb221b-ea9f-4bc0-add2-adbebf2000b0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 MegabonkRunInfo
{
internal enum RunInfoKey
{
Shrines,
Chests,
Vendors,
Microwaves,
MoaiOnly,
MoaiAndGreed,
Challenge,
Magnet,
Cursed
}
internal static class UIConfig
{
private static ConfigFile _cfg;
private static ConfigEntry<string> _readme;
private static ConfigEntry<string> _defaultStatsCsv;
private static ConfigEntry<string> _detailedStatsCsv;
private static ConfigEntry<string> _defaultRunCsv;
private static ConfigEntry<string> _detailedRunCsv;
private static ConfigEntry<float> _runInfoScale;
private static ConfigEntry<float> _playerStatsScale;
private static readonly StatsKey[] FALLBACK_STATS_DEFAULT = new StatsKey[5]
{
StatsKey.Damage,
StatsKey.AttackSpeed,
StatsKey.Luck,
StatsKey.Difficulty,
StatsKey.XpGain
};
private static readonly StatsKey[] FALLBACK_STATS_DETAILED = new StatsKey[12]
{
StatsKey.Damage,
StatsKey.CritChance,
StatsKey.CritDamage,
StatsKey.AttackSpeed,
StatsKey.Lifesteal,
StatsKey.Projectiles,
StatsKey.ExtraJumps,
StatsKey.Luck,
StatsKey.Difficulty,
StatsKey.MoveSpeed,
StatsKey.XpGain,
StatsKey.GoldGain
};
private static readonly RunInfoKey[] FALLBACK_RUN_DEFAULT = new RunInfoKey[4]
{
RunInfoKey.Shrines,
RunInfoKey.Chests,
RunInfoKey.Vendors,
RunInfoKey.MoaiOnly
};
private static readonly RunInfoKey[] FALLBACK_RUN_DETAILED = new RunInfoKey[8]
{
RunInfoKey.Shrines,
RunInfoKey.Chests,
RunInfoKey.Vendors,
RunInfoKey.Microwaves,
RunInfoKey.MoaiAndGreed,
RunInfoKey.Challenge,
RunInfoKey.Magnet,
RunInfoKey.Cursed
};
public static void Init()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Expected O, but got Unknown
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Expected O, but got Unknown
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Expected O, but got Unknown
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Expected O, but got Unknown
_cfg = new ConfigFile(Path.Combine(PathsBridge.UserDataDir, "UsefulInfoUI.cfg"), true);
ConfigDescription val = new ConfigDescription("One config controls everything (F1 cycles Default → Detailed → Hidden). Press Ctrl+R to hot-reload the config.", (AcceptableValueBase)null, Array.Empty<object>());
_readme = _cfg.Bind<string>("UsefulInfoUI", "Readme", "See description above", val);
ConfigDescription val2 = new ConfigDescription("Useful Info UI shows a compact overlay with Run Info on the left (Shrines, Chests, Vendors, etc.) and Player Stats on the right (Damage, Crit, Attack Speed, Luck, XP/Gold gain).\n\nShortcuts:\n • F1 – Toggle overlay state (Default → Detailed → Hidden)\n • Ctrl+R – Hot reload the config from disk\n • Ctrl+Up – Increase both Run Info and Player Stats scale\n • Ctrl+Down – Decrease both Run Info and Player Stats scale\n\nRun Info variables (case-insensitive):\n • Shrines – Charge shrines (common + legendary)\n • Chests – Normal + free chests\n • Vendors – Shady Guy counts by rarity (common/rare/epic/legendary)\n • Microwaves – Microwave counts by rarity (common/rare/epic/legendary)\n • MoaiOnly – Only Moai shrine count\n • MoaiAndGreed – Moai and Greed counts together\n • Challenge – Challenge shrine count\n • Magnet – Magnet shrine count\n • Cursed – Cursed shrine count", (AcceptableValueBase)null, Array.Empty<object>());
_defaultRunCsv = _cfg.Bind<string>("UsefulInfoUI", "DefaultRunInfoOrder", "Shrines,Chests,Vendors,MoaiOnly", val2);
_detailedRunCsv = _cfg.Bind<string>("UsefulInfoUI", "DetailedRunInfoOrder", "Shrines,Chests,Vendors,Microwaves,MoaiAndGreed,Challenge,Magnet,Cursed", new ConfigDescription("DETAILED state - Run Info rows", (AcceptableValueBase)null, Array.Empty<object>()));
_runInfoScale = _cfg.Bind<float>("UsefulInfoUI", "RunInfoScale", 1f, new ConfigDescription("Run Info scale (Ctrl+Up/Down)", (AcceptableValueBase)null, Array.Empty<object>()));
ConfigDescription val3 = new ConfigDescription("Player Stats variables (case-insensitive):\n • Preset-colored: Damage, CritChance, CritDamage, AttackSpeed, Lifesteal, Projectiles, ExtraJumps, Luck, Difficulty, MoveSpeed, XpGain, GoldGain\n • Full list:\n MaxHealth, HealthRegen, Shield, Thorns, Armor, Evasion, Lifesteal, CritChance, CritDamage,\n DamageReductionMultiplier, DamageCooldownMultiplier, SizeMultiplier, DurationMultiplier, DamageMultiplier,\n EffectDurationMultiplier, AttackSpeed, Projectiles, ProjectileSpeedMultiplier, EliteDamageMultiplier,\n KnockbackMultiplier, MoveSpeedMultiplier, JumpHeight, PickupRange, Luck, GoldIncreaseMultiplier,\n XpIncreaseMultiplier, Difficulty, EliteSpawnIncrease, BurnChance, FreezeChance, PowerupBoostMultiplier,\n PowerupChance, WeaponBurstCooldown, ProjectileBounces, ExtraJumps, Overheal, HealingMultiplier, SilverIncreaseMultiplier", (AcceptableValueBase)null, Array.Empty<object>());
_defaultStatsCsv = _cfg.Bind<string>("UsefulInfoUI", "DefaultStatsOrder", "Damage,AttackSpeed,Luck,Difficulty,XpGain", val3);
_detailedStatsCsv = _cfg.Bind<string>("UsefulInfoUI", "DetailedStatsOrder", "Damage,CritChance,CritDamage,AttackSpeed,Lifesteal,Projectiles,ExtraJumps,Luck,Difficulty,MoveSpeed,XpGain,GoldGain", new ConfigDescription("DETAILED state - Player Stats order", (AcceptableValueBase)null, Array.Empty<object>()));
_playerStatsScale = _cfg.Bind<float>("UsefulInfoUI", "PlayerStatsScale", 1f, new ConfigDescription("Player Stats scale (Ctrl+Up/Down)", (AcceptableValueBase)null, Array.Empty<object>()));
}
public static void ReloadFromDisk()
{
try
{
ConfigFile cfg = _cfg;
if (cfg != null)
{
cfg.Reload();
}
LoggerBridge.Info("[UsefulInfoUI] Config reloaded from disk.");
}
catch (Exception ex)
{
LoggerBridge.Warn("[UsefulInfoUI] Failed to reload config: " + ex.Message);
}
}
public static StatsKey[] GetPlayerStatsOrder(int state)
{
StatsKey[] array = ParseStats(((state == 2) ? Get(_detailedStatsCsv) : Get(_defaultStatsCsv)) ?? string.Empty);
if (array.Length != 0)
{
return array;
}
if (state != 2)
{
return FALLBACK_STATS_DEFAULT;
}
return FALLBACK_STATS_DETAILED;
}
public static RunInfoKey[] GetRunInfoOrder(int state)
{
RunInfoKey[] array = ParseRun(((state == 2) ? Get(_detailedRunCsv) : Get(_defaultRunCsv)) ?? string.Empty);
if (array.Length != 0)
{
return array;
}
if (state != 2)
{
return FALLBACK_RUN_DEFAULT;
}
return FALLBACK_RUN_DETAILED;
}
private static string Get(object entry)
{
return (entry as ConfigEntry<string>)?.Value;
}
private static StatsKey[] ParseStats(string csv)
{
if (string.IsNullOrWhiteSpace(csv))
{
return Array.Empty<StatsKey>();
}
List<StatsKey> list = new List<StatsKey>();
foreach (string item in from s in csv.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries)
select s.Trim())
{
if (StatsCatalog.TryResolveKey(item, out var key))
{
if (!list.Contains(key))
{
list.Add(key);
}
}
else
{
LoggerBridge.Warn("[UsefulInfoUI] Unknown Player Stat key: '" + item + "'. Ignored.");
}
}
return list.ToArray();
}
private static RunInfoKey[] ParseRun(string csv)
{
if (string.IsNullOrWhiteSpace(csv))
{
return Array.Empty<RunInfoKey>();
}
List<RunInfoKey> list = new List<RunInfoKey>();
foreach (string item in from s in csv.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries)
select s.Trim())
{
if (Enum.TryParse<RunInfoKey>(item, ignoreCase: true, out var result))
{
if (!list.Contains(result))
{
list.Add(result);
}
}
else
{
LoggerBridge.Warn("[UsefulInfoUI] Unknown Run Info key: '" + item + "'. Ignored.");
}
}
return list.ToArray();
}
public static float GetRunInfoScale()
{
return _runInfoScale?.Value ?? 1f;
}
public static float GetPlayerStatsScale()
{
return _playerStatsScale?.Value ?? 1f;
}
public static void SetRunInfoScale(float v, bool save)
{
if (_runInfoScale != null)
{
_runInfoScale.Value = v;
}
if (save)
{
ConfigFile cfg = _cfg;
if (cfg != null)
{
cfg.Save();
}
}
}
public static void SetPlayerStatsScale(float v, bool save)
{
if (_playerStatsScale != null)
{
_playerStatsScale.Value = v;
}
if (save)
{
ConfigFile cfg = _cfg;
if (cfg != null)
{
cfg.Save();
}
}
}
}
public sealed class UsefulInfoUICore
{
private TextMeshProUGUI _overlayText;
private Text _overlayFallback;
private GameObject _overlayObj;
private TextMeshProUGUI _playerStatsText;
private GameObject _playerStatsObj;
private GameObject _hud;
private int _toggleState = 1;
private int _commonShrineCount;
private int _legendaryShrineCount;
private int _normalChestCount;
private int _freeChestCount;
private int _moaiShrineCount;
private int _commonVendorCount;
private int _rareVendorCount;
private int _epicVendorCount;
private int _legendaryVendorCount;
private int _commonMicrowaveCount;
private int _rareMicrowaveCount;
private int _epicMicrowaveCount;
private int _legendaryMicrowaveCount;
private int _magnetShrineCount;
private int _cursedShrineCount;
private int _challengeShrineCount;
private int _greedShrineCount;
private const float WORLD_POLL_INTERVAL = 0.5f;
private const float STATS_POLL_INTERVAL = 0.25f;
private float _nextWorldPoll;
private float _nextStatsPoll;
private bool _countsDirty;
private bool _toggleDirty;
private bool _overlayBuiltOnce;
private Harmony _harmony;
private float _runInfoScale = 1f;
private float _playerStatsScale = 1f;
private const float SCALE_STEP = 0.05f;
private const float SCALE_MIN = 0.1f;
private const float SCALE_MAX = 5f;
public static UsefulInfoUICore Instance { get; private set; }
public event Action OnRunInfoChanged;
public void Init()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
Instance = this;
UIConfig.Init();
OnRunInfoChanged += UpdateRunInfo;
try
{
_harmony = new Harmony("Maskoliver.UsefulInfoUI");
_harmony.PatchAll();
LoggerBridge.Info("Harmony patches applied.");
}
catch (Exception ex)
{
LoggerBridge.Warn("Harmony patching failed: " + ex.Message);
}
_runInfoScale = Mathf.Clamp(UIConfig.GetRunInfoScale(), 0.1f, 5f);
_playerStatsScale = Mathf.Clamp(UIConfig.GetPlayerStatsScale(), 0.1f, 5f);
LoggerBridge.Info("Useful Info UI initialized!");
}
public void OnSceneLoaded(int buildIndex, string sceneName)
{
_overlayText = null;
_overlayFallback = null;
_overlayObj = null;
_playerStatsText = null;
_playerStatsObj = null;
_hud = null;
_toggleState = 1;
_commonShrineCount = (_legendaryShrineCount = (_normalChestCount = (_freeChestCount = (_moaiShrineCount = 0))));
_commonVendorCount = (_rareVendorCount = (_epicVendorCount = (_legendaryVendorCount = 0)));
_commonMicrowaveCount = (_rareMicrowaveCount = (_epicMicrowaveCount = (_legendaryMicrowaveCount = 0)));
_magnetShrineCount = (_cursedShrineCount = (_challengeShrineCount = (_greedShrineCount = 0)));
_countsDirty = true;
_toggleDirty = true;
_overlayBuiltOnce = false;
_nextWorldPoll = 0f;
_nextStatsPoll = 0f;
}
public void UpdateLoop()
{
HandleToggleKey();
HandleScaleKeys();
HandleHotReloadKey();
if ((Object)(object)_overlayObj == (Object)null && (Object)(object)GetHud() != (Object)null)
{
CreateOverlayUI();
}
if ((Object)(object)_playerStatsObj == (Object)null && (Object)(object)GetHud() != (Object)null)
{
CreatePlayerStatsUI();
}
InvokeRunInfoChanged();
}
public void InvokeRunInfoChanged()
{
this.OnRunInfoChanged?.Invoke();
}
private static string Z(int v)
{
if (v != 0)
{
return v.ToString();
}
return "-";
}
private void UpdateRunInfo()
{
float unscaledTime = Time.unscaledTime;
bool flag = _countsDirty || _toggleDirty || !_overlayBuiltOnce || unscaledTime >= _nextWorldPoll;
bool flag2 = _toggleDirty || !_overlayBuiltOnce || unscaledTime >= _nextStatsPoll;
if (flag || flag2)
{
UpdateRunInfo(flag, flag2);
if (flag)
{
_countsDirty = false;
_nextWorldPoll = unscaledTime + 0.5f;
_overlayBuiltOnce = true;
}
if (flag2)
{
_nextStatsPoll = unscaledTime + 0.25f;
}
_toggleDirty = false;
}
}
private void UpdateRunInfo(bool recountWorld, bool updateStats)
{
//IL_0570: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_overlayText == (Object)null && (Object)(object)_overlayFallback == (Object)null && (Object)(object)_playerStatsText == (Object)null)
{
return;
}
bool flag = false;
if (recountWorld)
{
Il2CppArrayBase<ChargeShrine> source = Object.FindObjectsByType<ChargeShrine>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableChest> source2 = Object.FindObjectsByType<InteractableChest>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShrineMoai> source3 = Object.FindObjectsByType<InteractableShrineMoai>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShadyGuy> source4 = Object.FindObjectsByType<InteractableShadyGuy>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShrineMagnet> source5 = Object.FindObjectsByType<InteractableShrineMagnet>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShrineCursed> source6 = Object.FindObjectsByType<InteractableShrineCursed>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShrineChallenge> source7 = Object.FindObjectsByType<InteractableShrineChallenge>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableShrineGreed> source8 = Object.FindObjectsByType<InteractableShrineGreed>((FindObjectsSortMode)0);
Il2CppArrayBase<InteractableMicrowave> source9 = Object.FindObjectsByType<InteractableMicrowave>((FindObjectsSortMode)0);
int value = ((IEnumerable<ChargeShrine>)source).Count((ChargeShrine x) => !x.completed && !x.isGolden);
int value2 = ((IEnumerable<ChargeShrine>)source).Count((ChargeShrine x) => !x.completed && x.isGolden);
int value3 = ((IEnumerable<InteractableChest>)source2).Count((InteractableChest x) => !((Il2CppObjectBase)x).WasCollected && (int)x.chestType == 0);
int value4 = ((IEnumerable<InteractableChest>)source2).Count((InteractableChest x) => !((Il2CppObjectBase)x).WasCollected && (int)x.chestType == 2);
int value5 = ((IEnumerable<InteractableShrineMoai>)source3).Count((InteractableShrineMoai x) => !x.done);
int value6 = ((IEnumerable<InteractableShadyGuy>)source4).Count((InteractableShadyGuy x) => !x.done && (int)x.rarity == 0);
int value7 = ((IEnumerable<InteractableShadyGuy>)source4).Count((InteractableShadyGuy x) => !x.done && (int)x.rarity == 1);
int value8 = ((IEnumerable<InteractableShadyGuy>)source4).Count((InteractableShadyGuy x) => !x.done && (int)x.rarity == 2);
int value9 = ((IEnumerable<InteractableShadyGuy>)source4).Count((InteractableShadyGuy x) => !x.done && (int)x.rarity == 3);
int value10 = ((IEnumerable<InteractableMicrowave>)source9).Count((InteractableMicrowave x) => x.usesLeft > 0 && (int)x.rarity == 0);
int value11 = ((IEnumerable<InteractableMicrowave>)source9).Count((InteractableMicrowave x) => x.usesLeft > 0 && (int)x.rarity == 1);
int value12 = ((IEnumerable<InteractableMicrowave>)source9).Count((InteractableMicrowave x) => x.usesLeft > 0 && (int)x.rarity == 2);
int value13 = ((IEnumerable<InteractableMicrowave>)source9).Count((InteractableMicrowave x) => x.usesLeft > 0 && (int)x.rarity == 3);
int value14 = ((IEnumerable<InteractableShrineMagnet>)source5).Count((InteractableShrineMagnet x) => !x.done);
int value15 = ((IEnumerable<InteractableShrineCursed>)source6).Count((InteractableShrineCursed x) => !x.done);
int value16 = ((IEnumerable<InteractableShrineChallenge>)source7).Count((InteractableShrineChallenge x) => !x.done);
int value17 = ((IEnumerable<InteractableShrineGreed>)source8).Count((InteractableShrineGreed x) => !x.done);
flag |= UpdateIfChanged(ref _commonShrineCount, value);
flag |= UpdateIfChanged(ref _legendaryShrineCount, value2);
flag |= UpdateIfChanged(ref _normalChestCount, value3);
flag |= UpdateIfChanged(ref _freeChestCount, value4);
flag |= UpdateIfChanged(ref _moaiShrineCount, value5);
flag |= UpdateIfChanged(ref _commonVendorCount, value6);
flag |= UpdateIfChanged(ref _rareVendorCount, value7);
flag |= UpdateIfChanged(ref _epicVendorCount, value8);
flag |= UpdateIfChanged(ref _legendaryVendorCount, value9);
flag |= UpdateIfChanged(ref _commonMicrowaveCount, value10);
flag |= UpdateIfChanged(ref _rareMicrowaveCount, value11);
flag |= UpdateIfChanged(ref _epicMicrowaveCount, value12);
flag |= UpdateIfChanged(ref _legendaryMicrowaveCount, value13);
flag |= UpdateIfChanged(ref _magnetShrineCount, value14);
flag |= UpdateIfChanged(ref _cursedShrineCount, value15);
flag |= UpdateIfChanged(ref _challengeShrineCount, value16);
flag |= UpdateIfChanged(ref _greedShrineCount, value17);
}
if (_toggleState == 0)
{
SetOverlayText("");
SyncStatsVisibility();
return;
}
if (((Object)(object)_overlayText != (Object)null || (Object)(object)_overlayFallback != (Object)null) && (flag || _toggleDirty || !_overlayBuiltOnce))
{
RunInfoKey[] runInfoOrder = UIConfig.GetRunInfoOrder(_toggleState);
List<string> list = new List<string>(runInfoOrder.Length);
RunInfoKey[] array = runInfoOrder;
foreach (RunInfoKey key in array)
{
string text = BuildRunInfoRow(key);
if (!string.IsNullOrEmpty(text))
{
list.Add(text);
}
}
SetOverlayText(string.Join("\n", list));
}
if (updateStats && (Object)(object)_playerStatsText != (Object)null)
{
MyPlayer instance = MyPlayer.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
PlayerInventory inventory = instance.inventory;
obj = ((inventory != null) ? inventory.playerStats : null);
}
PlayerStatsNew val = (PlayerStatsNew)obj;
List<string> list2 = new List<string>();
if (val != null)
{
StatsKey[] playerStatsOrder = UIConfig.GetPlayerStatsOrder(_toggleState);
Dictionary<StatsKey, string> dictionary = StatPalette.ForOrder(playerStatsOrder.Where(StatsCatalog.NeedsDynamicColor).ToList());
StatsKey[] array2 = playerStatsOrder;
foreach (StatsKey key2 in array2)
{
if (StatsCatalog.All.TryGetValue(key2, out var value18))
{
float stat = val.GetStat(value18.Stat);
string value19 = StatsCatalog.FormatValue(value18, stat);
string value20;
string value21 = ((!StatsCatalog.NeedsDynamicColor(key2)) ? value18.ColorHex : (dictionary.TryGetValue(key2, out value20) ? value20 : "#FFFFFF"));
list2.Add($"<color={"#FFFFFF"}>{value18.Label}:</color> <color={value21}>{value19}</color>");
}
}
}
((TMP_Text)_playerStatsText).text = string.Join("\n", list2);
}
SyncStatsVisibility();
}
private string BuildRunInfoRow(RunInfoKey key)
{
return key switch
{
RunInfoKey.Shrines => $"<color=white>Shrine :</color><pos=60%> <font-weight=\"200\"><color=#C0C0C0>{Z(_commonShrineCount)}</color></font-weight> <font-weight=\"700\"><color=#FFA500>{Z(_legendaryShrineCount)}</color></font-weight>",
RunInfoKey.Chests => $"<color=white>Chest :</color><pos=60%> <font-weight=\"200\"><color=#C0C0C0>{Z(_normalChestCount)}</color></font-weight> <font-weight=\"700\"><color=#FFA500>{Z(_freeChestCount)}</color></font-weight>",
RunInfoKey.Vendors => $"<color=white>Vendor :</color><pos=60%> <font-weight=\"200\"><color=#C0C0C0>{Z(_commonVendorCount)}</color></font-weight> <color=blue>{Z(_rareVendorCount)}</color> <color=#FF00FF>{Z(_epicVendorCount)}</color> <font-weight=\"700\"><color=#FFA500>{Z(_legendaryVendorCount)}</color></font-weight>",
RunInfoKey.Microwaves => $"<color=white>Microwave :</color><pos=60%> <font-weight=\"200\"><color=#C0C0C0>{Z(_commonMicrowaveCount)}</color></font-weight> <color=blue>{Z(_rareMicrowaveCount)}</color> <color=#FF00FF>{Z(_epicMicrowaveCount)}</color> <font-weight=\"700\"><color=#FFA500>{Z(_legendaryMicrowaveCount)}</color></font-weight>",
RunInfoKey.MoaiOnly => "<color=white>Moai :</color><pos=60%> <color=white>" + Z(_moaiShrineCount) + "</color>",
RunInfoKey.MoaiAndGreed => $"<color=white>Moai&Greed :</color><pos=60%> <color=white>{Z(_moaiShrineCount)} </color> <color=#C0C0C0>{Z(_greedShrineCount)}</color>",
RunInfoKey.Challenge => "<color=white>Challange</color><pos=60%> <color=white>" + Z(_challengeShrineCount) + "</color>",
RunInfoKey.Magnet => "<color=white>Magnet :</color><pos=60%> <color=white>" + Z(_magnetShrineCount) + "</color>",
RunInfoKey.Cursed => "<color=white>Cursed :</color><pos=60%> <color=white>" + Z(_cursedShrineCount) + "</color>",
_ => string.Empty,
};
}
private void CreateOverlayUI()
{
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_005f: 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)
GameObject hud = GetHud();
if (!((Object)(object)hud == (Object)null))
{
_overlayObj = new GameObject("RunInfo");
_overlayObj.transform.SetParent(hud.transform, false);
try
{
_overlayText = _overlayObj.AddComponent<TextMeshProUGUI>();
((TMP_Text)_overlayText).fontSize = 20f;
((Graphic)_overlayText).color = Color.white;
((TMP_Text)_overlayText).alignment = (TextAlignmentOptions)257;
((TMP_Text)_overlayText).textWrappingMode = (TextWrappingModes)0;
((Graphic)_overlayText).raycastTarget = false;
ConfigureAnchors(((TMP_Text)_overlayText).rectTransform, new Vector2(30f, 0f));
LoggerBridge.Info("RunInfo UI created (TMPro)");
}
catch (Exception ex)
{
LoggerBridge.Warn("TMPro failed: " + ex.Message + " - Using UI.Text fallback");
_overlayFallback = _overlayObj.AddComponent<Text>();
_overlayFallback.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
_overlayFallback.fontSize = 20;
((Graphic)_overlayFallback).color = Color.white;
_overlayFallback.alignment = (TextAnchor)0;
((Graphic)_overlayFallback).raycastTarget = false;
ConfigureAnchors(((Graphic)_overlayFallback).rectTransform, new Vector2(30f, 0f));
}
_overlayObj.SetActive(_toggleState != 0);
ApplyRunInfoScale();
UpdateRunInfo();
}
}
private void CreatePlayerStatsUI()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_005f: 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)
GameObject hud = GetHud();
if (!((Object)(object)hud == (Object)null))
{
_playerStatsObj = new GameObject("PlayerStatsInfo");
_playerStatsObj.transform.SetParent(hud.transform, false);
try
{
_playerStatsText = _playerStatsObj.AddComponent<TextMeshProUGUI>();
((TMP_Text)_playerStatsText).fontSize = 20f;
((Graphic)_playerStatsText).color = Color.white;
((TMP_Text)_playerStatsText).alignment = (TextAlignmentOptions)260;
((TMP_Text)_playerStatsText).textWrappingMode = (TextWrappingModes)0;
((Graphic)_playerStatsText).raycastTarget = false;
ConfigureAnchorsRight(((TMP_Text)_playerStatsText).rectTransform, new Vector2(-30f, 0f));
LoggerBridge.Info("Player Stats UI created (TMPro)");
}
catch (Exception ex)
{
LoggerBridge.Warn("Player TMPro failed: " + ex.Message);
_playerStatsText = null;
}
if ((Object)(object)_playerStatsObj != (Object)null)
{
_playerStatsObj.SetActive(_toggleState != 0);
}
ApplyPlayerStatsScale();
UpdateRunInfo();
}
}
private void HandleToggleKey()
{
if (!Input.GetKeyDown((KeyCode)282))
{
return;
}
switch (_toggleState)
{
case 1:
_toggleState = 2;
break;
case 2:
_toggleState = 0;
break;
default:
_toggleState = 1;
break;
}
if ((Object)(object)_overlayObj != (Object)null)
{
_overlayObj.SetActive(_toggleState != 0);
if (_toggleState != 0)
{
UpdateRunInfo();
}
else
{
SetOverlayText("");
}
}
if ((Object)(object)_playerStatsObj != (Object)null)
{
_playerStatsObj.SetActive(_toggleState != 0);
}
string text = ((_toggleState == 0) ? "hidden" : ((_toggleState == 1) ? "default" : "detailed"));
LoggerBridge.Info("Overlay toggled to " + text + " (F1)");
_toggleDirty = true;
}
private void HandleHotReloadKey()
{
if ((Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) && Input.GetKeyDown((KeyCode)114))
{
try
{
UIConfig.ReloadFromDisk();
_toggleDirty = true;
_nextStatsPoll = 0f;
_overlayBuiltOnce = false;
UpdateRunInfo();
_runInfoScale = Mathf.Clamp(UIConfig.GetRunInfoScale(), 0.1f, 5f);
_playerStatsScale = Mathf.Clamp(UIConfig.GetPlayerStatsScale(), 0.1f, 5f);
ApplyRunInfoScale();
ApplyPlayerStatsScale();
LoggerBridge.Info("[UsefulInfoUI] Hot reload applied (Ctrl+R).");
}
catch (Exception ex)
{
LoggerBridge.Warn("[UsefulInfoUI] Hot reload failed: " + ex.Message);
}
}
}
private GameObject GetHud()
{
if ((Object)(object)_hud == (Object)null)
{
_hud = GameObject.Find("HUD");
}
return _hud;
}
private static void ConfigureAnchors(RectTransform rt, Vector2 anchored)
{
//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
rt.anchorMax = new Vector2(0f, 0.5f);
rt.anchorMin = new Vector2(0f, 0.5f);
rt.pivot = new Vector2(0f, 0.5f);
rt.anchoredPosition = anchored;
}
private static void ConfigureAnchorsRight(RectTransform rt, Vector2 anchored)
{
//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
rt.anchorMax = new Vector2(1f, 0.5f);
rt.anchorMin = new Vector2(1f, 0.5f);
rt.pivot = new Vector2(1f, 0.5f);
rt.anchoredPosition = anchored;
}
private void SetOverlayText(string value)
{
if ((Object)(object)_overlayText != (Object)null)
{
((TMP_Text)_overlayText).text = value;
}
else if ((Object)(object)_overlayFallback != (Object)null)
{
_overlayFallback.text = value;
}
}
private void SyncStatsVisibility()
{
if ((Object)(object)_playerStatsObj != (Object)null)
{
_playerStatsObj.SetActive(_toggleState != 0);
}
}
private static bool UpdateIfChanged(ref int cache, int value)
{
if (cache != value)
{
cache = value;
return true;
}
return false;
}
internal void _MarkCountsDirty()
{
_countsDirty = true;
_nextWorldPoll = 0f;
}
private static bool IsCtrl()
{
if (!Input.GetKey((KeyCode)306))
{
return Input.GetKey((KeyCode)305);
}
return true;
}
private void HandleScaleKeys()
{
if (IsCtrl())
{
if (Input.GetKeyDown((KeyCode)273))
{
_runInfoScale = Mathf.Clamp(_runInfoScale + 0.05f, 0.1f, 5f);
_playerStatsScale = Mathf.Clamp(_playerStatsScale + 0.05f, 0.1f, 5f);
LoggerBridge.Info($"[UsefulInfoUI] Scales -> RunInfo={_runInfoScale:0.00}, PlayerStats={_playerStatsScale:0.00}");
ApplyRunInfoScale();
ApplyPlayerStatsScale();
UIConfig.SetRunInfoScale(_runInfoScale, save: true);
UIConfig.SetPlayerStatsScale(_playerStatsScale, save: true);
}
if (Input.GetKeyDown((KeyCode)274))
{
_runInfoScale = Mathf.Clamp(_runInfoScale - 0.05f, 0.1f, 5f);
_playerStatsScale = Mathf.Clamp(_playerStatsScale - 0.05f, 0.1f, 5f);
LoggerBridge.Info($"[UsefulInfoUI] Scales -> RunInfo={_runInfoScale:0.00}, PlayerStats={_playerStatsScale:0.00}");
ApplyRunInfoScale();
ApplyPlayerStatsScale();
UIConfig.SetRunInfoScale(_runInfoScale, save: true);
UIConfig.SetPlayerStatsScale(_playerStatsScale, save: true);
}
}
}
private void ApplyRunInfoScale()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_overlayObj != (Object)null)
{
Vector3 val = default(Vector3);
((Vector3)(ref val))..ctor(_runInfoScale, _runInfoScale, 1f);
if (_overlayObj.transform.localScale != val)
{
_overlayObj.transform.localScale = val;
}
}
}
private void ApplyPlayerStatsScale()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_playerStatsObj != (Object)null)
{
Vector3 val = default(Vector3);
((Vector3)(ref val))..ctor(_playerStatsScale, _playerStatsScale, 1f);
if (_playerStatsObj.transform.localScale != val)
{
_playerStatsObj.transform.localScale = val;
}
}
}
}
[HarmonyPatch]
internal static class InteractableDirtyPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(BaseInteractable), "Start")]
private static void BI_Start_Postfix()
{
UsefulInfoUICore.Instance?._MarkCountsDirty();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BaseInteractable), "OnDestroy")]
private static void BI_OnDestroy_Postfix()
{
UsefulInfoUICore.Instance?._MarkCountsDirty();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BaseInteractable), "RefreshInteractable")]
private static void BI_Refresh_Postfix()
{
UsefulInfoUICore.Instance?._MarkCountsDirty();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BaseInteractable), "Interact")]
private static void BI_Interact_Postfix()
{
UsefulInfoUICore.Instance?._MarkCountsDirty();
}
}
internal static class Hex
{
public const string Label = "#FFFFFF";
public const string Damage = "#FFB200";
public const string CritChance = "#FF2E63";
public const string CritDamage = "#FF006E";
public const string AttackSpeed = "#00B8D9";
public const string Lifesteal = "#2ECC71";
public const string Projectiles = "#9B5DE5";
public const string ExtraJumps = "#F15BB5";
public const string Luck = "#34D399";
public const string Difficulty = "#FF8C00";
public const string MoveSpeed = "#E9C46A";
public const string Xp = "#06D6A0";
public const string Gold = "#FFD700";
}
internal enum StatsKey
{
Damage,
AttackSpeed,
Luck,
Difficulty,
MoveSpeed,
XpGain,
GoldGain,
CritChance,
CritDamage,
Lifesteal,
Projectiles,
ExtraJumps,
MaxHealth,
HealthRegen,
Shield,
Thorns,
Armor,
Evasion,
DamageReductionMultiplier,
DamageCooldownMultiplier,
SizeMultiplier,
DurationMultiplier,
DamageMultiplier,
EffectDurationMultiplier,
ProjectileSpeedMultiplier,
EliteDamageMultiplier,
KnockbackMultiplier,
MoveSpeedMultiplier,
JumpHeight,
PickupRange,
GoldIncreaseMultiplier,
XpIncreaseMultiplier,
EliteSpawnIncrease,
BurnChance,
FreezeChance,
PowerupBoostMultiplier,
PowerupChance,
WeaponBurstCooldown,
ProjectileBounces,
Overheal,
HealingMultiplier,
SilverIncreaseMultiplier
}
internal enum StatFormat
{
MultiplierX,
Percent01,
Percent01_F1,
Integer,
Float1,
Float2
}
internal sealed class StatDef
{
public readonly StatsKey Key;
public readonly string Label;
public readonly EStat Stat;
public readonly StatFormat Format;
public readonly string ColorHex;
public StatDef(StatsKey key, string label, EStat stat, StatFormat fmt, string colorHex)
{
//IL_0015: 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)
Key = key;
Label = label;
Stat = stat;
Format = fmt;
ColorHex = colorHex;
}
}
internal static class StatPalette
{
private const double GR = 0.6180339887498949;
private const float SAT = 0.78f;
private const float VAL = 0.95f;
private static readonly Dictionary<string, Dictionary<StatsKey, string>> _cache = new Dictionary<string, Dictionary<StatsKey, string>>(StringComparer.Ordinal);
public static Dictionary<StatsKey, string> ForOrder(IReadOnlyList<StatsKey> order)
{
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
if (order == null || order.Count == 0)
{
return new Dictionary<StatsKey, string>();
}
string text = string.Join(",", order.Select((StatsKey k) => k.ToString()));
if (_cache.TryGetValue(text, out var value))
{
return value;
}
double num = Hash01(text);
Dictionary<StatsKey, string> dictionary = new Dictionary<StatsKey, string>(order.Count);
for (int i = 0; i < order.Count; i++)
{
num = (num + 0.6180339887498949) % 1.0;
string value2 = ToHtmlRGB(HSV((float)num, 0.78f, 0.95f));
dictionary[order[i]] = value2;
}
_cache[text] = dictionary;
return dictionary;
}
private static Color HSV(float h, float s, float v)
{
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
h = Mathf.Repeat(h, 1f);
s = Mathf.Clamp01(s);
v = Mathf.Clamp01(v);
float num = v * s;
float num2 = num * (1f - Mathf.Abs(h * 6f % 2f - 1f));
float num3 = v - num;
float num4 = 0f;
float num5 = 0f;
float num6 = 0f;
float num7 = h * 6f;
if (num7 < 1f)
{
num4 = num;
num5 = num2;
}
else if (num7 < 2f)
{
num4 = num2;
num5 = num;
}
else if (num7 < 3f)
{
num5 = num;
num6 = num2;
}
else if (num7 < 4f)
{
num5 = num2;
num6 = num;
}
else if (num7 < 5f)
{
num4 = num2;
num6 = num;
}
else
{
num4 = num;
num6 = num2;
}
return new Color(num4 + num3, num5 + num3, num6 + num3, 1f);
}
private static string ToHtmlRGB(Color c)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
int value = Mathf.Clamp(Mathf.RoundToInt(c.r * 255f), 0, 255);
int value2 = Mathf.Clamp(Mathf.RoundToInt(c.g * 255f), 0, 255);
int value3 = Mathf.Clamp(Mathf.RoundToInt(c.b * 255f), 0, 255);
return $"#{value:X2}{value2:X2}{value3:X2}";
}
private static double Hash01(string s)
{
uint num = 2166136261u;
foreach (char c in s)
{
num ^= c;
num *= 16777619;
}
return (double)(num % 100000) / 100000.0;
}
}
internal static class StatsCatalog
{
private static readonly Dictionary<string, StatsKey> _aliasToKey = new Dictionary<string, StatsKey>(StringComparer.OrdinalIgnoreCase)
{
["Damage"] = StatsKey.Damage,
["AttackSpeed"] = StatsKey.AttackSpeed,
["Luck"] = StatsKey.Luck,
["Difficulty"] = StatsKey.Difficulty,
["MoveSpeed"] = StatsKey.MoveSpeed,
["XpGain"] = StatsKey.XpGain,
["GoldGain"] = StatsKey.GoldGain,
["CritChance"] = StatsKey.CritChance,
["CritDamage"] = StatsKey.CritDamage,
["Lifesteal"] = StatsKey.Lifesteal,
["Projectiles"] = StatsKey.Projectiles,
["ExtraJumps"] = StatsKey.ExtraJumps,
["MaxHealth"] = StatsKey.MaxHealth,
["HealthRegen"] = StatsKey.HealthRegen,
["Shield"] = StatsKey.Shield,
["Thorns"] = StatsKey.Thorns,
["Armor"] = StatsKey.Armor,
["Evasion"] = StatsKey.Evasion,
["DamageReductionMultiplier"] = StatsKey.DamageReductionMultiplier,
["DamageCooldownMultiplier"] = StatsKey.DamageCooldownMultiplier,
["SizeMultiplier"] = StatsKey.SizeMultiplier,
["DurationMultiplier"] = StatsKey.DurationMultiplier,
["DamageMultiplier"] = StatsKey.DamageMultiplier,
["EffectDurationMultiplier"] = StatsKey.EffectDurationMultiplier,
["ProjectileSpeedMultiplier"] = StatsKey.ProjectileSpeedMultiplier,
["EliteDamageMultiplier"] = StatsKey.EliteDamageMultiplier,
["KnockbackMultiplier"] = StatsKey.KnockbackMultiplier,
["MoveSpeedMultiplier"] = StatsKey.MoveSpeedMultiplier,
["JumpHeight"] = StatsKey.JumpHeight,
["PickupRange"] = StatsKey.PickupRange,
["GoldIncreaseMultiplier"] = StatsKey.GoldIncreaseMultiplier,
["XpIncreaseMultiplier"] = StatsKey.XpIncreaseMultiplier,
["EliteSpawnIncrease"] = StatsKey.EliteSpawnIncrease,
["BurnChance"] = StatsKey.BurnChance,
["FreezeChance"] = StatsKey.FreezeChance,
["PowerupBoostMultiplier"] = StatsKey.PowerupBoostMultiplier,
["PowerupChance"] = StatsKey.PowerupChance,
["WeaponBurstCooldown"] = StatsKey.WeaponBurstCooldown,
["ProjectileBounces"] = StatsKey.ProjectileBounces,
["Overheal"] = StatsKey.Overheal,
["HealingMultiplier"] = StatsKey.HealingMultiplier,
["SilverIncreaseMultiplier"] = StatsKey.SilverIncreaseMultiplier
};
public static readonly IReadOnlyDictionary<StatsKey, StatDef> All = BuildDefs();
private static Dictionary<StatsKey, StatDef> BuildDefs()
{
string colorHex = "#FFFFFF";
string colorHex2 = "#FFB200";
string colorHex3 = "#FF2E63";
string colorHex4 = "#FF006E";
string colorHex5 = "#00B8D9";
string colorHex6 = "#2ECC71";
string colorHex7 = "#9B5DE5";
string colorHex8 = "#F15BB5";
string colorHex9 = "#34D399";
string colorHex10 = "#FF8C00";
string colorHex11 = "#E9C46A";
string colorHex12 = "#06D6A0";
string colorHex13 = "#FFD700";
return new Dictionary<StatsKey, StatDef>
{
[StatsKey.Damage] = new StatDef(StatsKey.Damage, "Damage", (EStat)12, StatFormat.MultiplierX, colorHex2),
[StatsKey.AttackSpeed] = new StatDef(StatsKey.AttackSpeed, "Attack Speed", (EStat)15, StatFormat.Percent01, colorHex5),
[StatsKey.Luck] = new StatDef(StatsKey.Luck, "Luck", (EStat)30, StatFormat.Percent01, colorHex9),
[StatsKey.Difficulty] = new StatDef(StatsKey.Difficulty, "Difficulty", (EStat)38, StatFormat.Percent01, colorHex10),
[StatsKey.MoveSpeed] = new StatDef(StatsKey.MoveSpeed, "Move Speed", (EStat)25, StatFormat.MultiplierX, colorHex11),
[StatsKey.XpGain] = new StatDef(StatsKey.XpGain, "XP Gain", (EStat)32, StatFormat.MultiplierX, colorHex12),
[StatsKey.GoldGain] = new StatDef(StatsKey.GoldGain, "Gold Gain", (EStat)31, StatFormat.MultiplierX, colorHex13),
[StatsKey.CritChance] = new StatDef(StatsKey.CritChance, "Crit Chance", (EStat)18, StatFormat.Percent01, colorHex3),
[StatsKey.CritDamage] = new StatDef(StatsKey.CritDamage, "Crit Damage", (EStat)19, StatFormat.MultiplierX, colorHex4),
[StatsKey.Lifesteal] = new StatDef(StatsKey.Lifesteal, "Lifesteal", (EStat)17, StatFormat.Percent01, colorHex6),
[StatsKey.Projectiles] = new StatDef(StatsKey.Projectiles, "Projectiles", (EStat)16, StatFormat.Float1, colorHex7),
[StatsKey.ExtraJumps] = new StatDef(StatsKey.ExtraJumps, "Extra Jumps", (EStat)46, StatFormat.Float1, colorHex8),
[StatsKey.MaxHealth] = new StatDef(StatsKey.MaxHealth, "Max Health", (EStat)0, StatFormat.Integer, colorHex),
[StatsKey.HealthRegen] = new StatDef(StatsKey.HealthRegen, "Health Regen", (EStat)1, StatFormat.Integer, colorHex),
[StatsKey.Shield] = new StatDef(StatsKey.Shield, "Shield", (EStat)2, StatFormat.Integer, colorHex),
[StatsKey.Thorns] = new StatDef(StatsKey.Thorns, "Thorns", (EStat)3, StatFormat.Integer, colorHex),
[StatsKey.Armor] = new StatDef(StatsKey.Armor, "Armor", (EStat)4, StatFormat.Percent01, colorHex),
[StatsKey.Evasion] = new StatDef(StatsKey.Evasion, "Evasion", (EStat)5, StatFormat.Percent01, colorHex),
[StatsKey.DamageReductionMultiplier] = new StatDef(StatsKey.DamageReductionMultiplier, "Damage Reduction", (EStat)7, StatFormat.Percent01, colorHex),
[StatsKey.DamageCooldownMultiplier] = new StatDef(StatsKey.DamageCooldownMultiplier, "Damage Cooldown", (EStat)8, StatFormat.MultiplierX, colorHex),
[StatsKey.SizeMultiplier] = new StatDef(StatsKey.SizeMultiplier, "Size", (EStat)9, StatFormat.MultiplierX, colorHex),
[StatsKey.DurationMultiplier] = new StatDef(StatsKey.DurationMultiplier, "Duration", (EStat)10, StatFormat.MultiplierX, colorHex),
[StatsKey.DamageMultiplier] = new StatDef(StatsKey.DamageMultiplier, "Damage", (EStat)12, StatFormat.MultiplierX, colorHex2),
[StatsKey.EffectDurationMultiplier] = new StatDef(StatsKey.EffectDurationMultiplier, "Effect Duration", (EStat)14, StatFormat.MultiplierX, colorHex),
[StatsKey.ProjectileSpeedMultiplier] = new StatDef(StatsKey.ProjectileSpeedMultiplier, "Projectile Speed", (EStat)11, StatFormat.MultiplierX, colorHex),
[StatsKey.EliteDamageMultiplier] = new StatDef(StatsKey.EliteDamageMultiplier, "Elite Damage", (EStat)23, StatFormat.MultiplierX, colorHex),
[StatsKey.KnockbackMultiplier] = new StatDef(StatsKey.KnockbackMultiplier, "Knockback", (EStat)24, StatFormat.MultiplierX, colorHex),
[StatsKey.MoveSpeedMultiplier] = new StatDef(StatsKey.MoveSpeedMultiplier, "Move Speed", (EStat)25, StatFormat.MultiplierX, colorHex11),
[StatsKey.JumpHeight] = new StatDef(StatsKey.JumpHeight, "Jump Height", (EStat)26, StatFormat.Integer, colorHex),
[StatsKey.PickupRange] = new StatDef(StatsKey.PickupRange, "Pickup Range", (EStat)29, StatFormat.Integer, colorHex),
[StatsKey.GoldIncreaseMultiplier] = new StatDef(StatsKey.GoldIncreaseMultiplier, "Gold Gain", (EStat)31, StatFormat.MultiplierX, colorHex13),
[StatsKey.XpIncreaseMultiplier] = new StatDef(StatsKey.XpIncreaseMultiplier, "XP Gain", (EStat)32, StatFormat.MultiplierX, colorHex12),
[StatsKey.EliteSpawnIncrease] = new StatDef(StatsKey.EliteSpawnIncrease, "Elite Spawn", (EStat)39, StatFormat.Percent01, colorHex),
[StatsKey.BurnChance] = new StatDef(StatsKey.BurnChance, "Burn Chance", (EStat)42, StatFormat.Percent01, colorHex),
[StatsKey.FreezeChance] = new StatDef(StatsKey.FreezeChance, "Freeze Chance", (EStat)43, StatFormat.Percent01, colorHex),
[StatsKey.PowerupBoostMultiplier] = new StatDef(StatsKey.PowerupBoostMultiplier, "Powerup Boost", (EStat)40, StatFormat.MultiplierX, colorHex),
[StatsKey.PowerupChance] = new StatDef(StatsKey.PowerupChance, "Powerup Chance", (EStat)41, StatFormat.Percent01, colorHex),
[StatsKey.WeaponBurstCooldown] = new StatDef(StatsKey.WeaponBurstCooldown, "Burst Cooldown", (EStat)44, StatFormat.Float2, colorHex),
[StatsKey.ProjectileBounces] = new StatDef(StatsKey.ProjectileBounces, "Proj. Bounces", (EStat)45, StatFormat.Integer, colorHex),
[StatsKey.Overheal] = new StatDef(StatsKey.Overheal, "Overheal", (EStat)47, StatFormat.Integer, colorHex),
[StatsKey.HealingMultiplier] = new StatDef(StatsKey.HealingMultiplier, "Healing", (EStat)48, StatFormat.MultiplierX, colorHex),
[StatsKey.SilverIncreaseMultiplier] = new StatDef(StatsKey.SilverIncreaseMultiplier, "Silver Gain", (EStat)49, StatFormat.MultiplierX, colorHex)
};
}
public static bool TryResolveKey(string s, out StatsKey key)
{
return _aliasToKey.TryGetValue(s, out key);
}
public static string FormatValue(StatDef def, float raw)
{
return def.Format switch
{
StatFormat.MultiplierX => $"{raw:F2}x",
StatFormat.Percent01 => $"{raw * 100f:0}%",
StatFormat.Percent01_F1 => $"{raw * 100f:0.0}%",
StatFormat.Integer => Mathf.RoundToInt(raw).ToString(),
StatFormat.Float1 => raw.ToString("0.0"),
StatFormat.Float2 => raw.ToString("0.00"),
_ => raw.ToString(),
};
}
public static bool NeedsDynamicColor(StatsKey key)
{
if ((uint)key <= 11u)
{
return false;
}
return true;
}
}
[BepInPlugin("com.maskoliver.usefulinfoui", "Useful Info UI", "1.1.5")]
public sealed class BepInEntry : BasePlugin
{
private sealed class UpdateDriver : MonoBehaviour
{
private int _lastSceneBuildIndex = -1;
public UpdateDriver(IntPtr ptr)
: base(ptr)
{
}
private void Start()
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
try
{
_core.Init();
Scene activeScene = SceneManager.GetActiveScene();
_lastSceneBuildIndex = ((Scene)(ref activeScene)).buildIndex;
_core.OnSceneLoaded(((Scene)(ref activeScene)).buildIndex, ((Scene)(ref activeScene)).name);
}
catch (Exception ex)
{
ManualLogSource sLog = SLog;
if (sLog != null)
{
sLog.LogError((object)ex);
}
}
}
private void Update()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
_core?.UpdateLoop();
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).buildIndex == _lastSceneBuildIndex)
{
return;
}
try
{
_core?.OnSceneLoaded(((Scene)(ref activeScene)).buildIndex, ((Scene)(ref activeScene)).name);
_lastSceneBuildIndex = ((Scene)(ref activeScene)).buildIndex;
}
catch (Exception ex)
{
ManualLogSource sLog = SLog;
if (sLog != null)
{
sLog.LogError((object)ex);
}
}
}
private void OnDestroy()
{
ManualLogSource sLog = SLog;
if (sLog != null)
{
sLog.LogInfo((object)"UsefulInfoUI_UpdateHost destroyed");
}
}
}
private Harmony _harmony;
internal static ManualLogSource SLog;
private static GameObject _host;
private static UsefulInfoUICore _core;
public override void Load()
{
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Expected O, but got Unknown
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Expected O, but got Unknown
SLog = Logger.CreateLogSource("UsefulInfoUI");
LoggerBridge.Info = delegate(string s)
{
SLog.LogInfo((object)s);
};
LoggerBridge.Warn = delegate(string s)
{
SLog.LogWarning((object)s);
};
LoggerBridge.Error = delegate(string s)
{
SLog.LogError((object)s);
};
ClassInjector.RegisterTypeInIl2Cpp<UpdateDriver>();
_core = new UsefulInfoUICore();
_host = new GameObject("UsefulInfoUI_UpdateHost");
Object.DontDestroyOnLoad((Object)(object)_host);
((Object)_host).hideFlags = (HideFlags)61;
_host.AddComponent<UpdateDriver>();
_harmony = new Harmony("Maskoliver.UsefulInfoUI");
_harmony.PatchAll();
SLog.LogInfo((object)"Useful Info UI (BepInEx) loaded.");
}
}
internal static class LoggerBridge
{
public static Action<string> Info = delegate
{
};
public static Action<string> Warn = delegate
{
};
public static Action<string> Error = delegate
{
};
}
internal static class PathsBridge
{
public static string UserDataDir => Paths.ConfigPath;
}
[HarmonyPatch(typeof(ChargeShrine), "Complete")]
public static class ChargeShrinePatch
{
[HarmonyPostfix]
public static void Postfix()
{
UsefulInfoUICore.Instance?.InvokeRunInfoChanged();
}
}
[HarmonyPatch(typeof(InteractableShrineMoai), "Interact")]
public static class MoaiPatch
{
[HarmonyPostfix]
public static void Postfix()
{
UsefulInfoUICore.Instance?.InvokeRunInfoChanged();
}
}
[HarmonyPatch(typeof(InteractableShadyGuy), "OnDestroy")]
public static class ShadyGuyPatch
{
[HarmonyPostfix]
public static void Postfix()
{
UsefulInfoUICore.Instance?.InvokeRunInfoChanged();
}
}
public static class ToggleImage
{
public static TextMeshProUGUI text;
public static bool isOn;
public static void Toggle()
{
isOn = !isOn;
if (isOn && (Object)(object)text != (Object)null)
{
((TMP_Text)text).text = "Press key";
}
}
}
}