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 HeroStats v1.0.1
HeroStats.dll
Decompiled 2 hours agousing System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using RoR2; using RoR2.Stats; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace HeroStats; [BepInPlugin("com.proigryfedorov.herostats", "HeroStats", "1.0.1")] public class HeroStatsPlugin : BaseUnityPlugin { internal enum PanelAnchor { Coins, Objectives, Screen } public const string PluginGuid = "com.proigryfedorov.herostats"; public const string PluginName = "HeroStats"; public const string PluginVersion = "1.0.1"; internal static HeroStatsPlugin Instance; internal static ConfigEntry<bool> ShowPanel; internal static ConfigEntry<KeyCode> ToggleKey; internal static ConfigEntry<bool> English; internal static ConfigEntry<float> PositionX; internal static ConfigEntry<float> PositionY; internal static ConfigEntry<PanelAnchor> Anchor; internal static ConfigEntry<float> OffsetX; internal static ConfigEntry<float> OffsetY; internal static ConfigEntry<float> FontSize; internal static ConfigEntry<float> DpsWindow; internal static ConfigEntry<bool> IncludeMinions; internal static ConfigEntry<bool> StackTotals; private static readonly string[,] LineSettings = new string[17, 2] { { "Title", "Заголовок «Статистика»" }, { "Damage", "Урон" }, { "AttackSpeed", "Скорость атаки" }, { "Crit", "Шанс и множитель крита" }, { "Bleed", "Шанс кровотечения (только если больше 0)" }, { "Health", "Здоровье и щит" }, { "Regen", "Реген" }, { "Armor", "Броня и снижение урона" }, { "Speed", "Скорость передвижения" }, { "Jumps", "Прыжки" }, { "Level", "Уровень" }, { "Gold", "Золото (вместе с банком)" }, { "Luck", "Удача (только если не 0)" }, { "Kills", "Убийства" }, { "Dps", "DPS" }, { "MaxHit", "Максимальный урон одним ударом" }, { "ItemCounts", "Общее количество предметов" } }; private static readonly Dictionary<string, ConfigEntry<bool>> lines = new Dictionary<string, ConfigEntry<bool>>(); private readonly Queue<KeyValuePair<float, float>> recentDamage = new Queue<KeyValuePair<float, float>>(); private float recentDamageSum; internal float maxHit; private static readonly Dictionary<string, StackMode> NonLinearItems = new Dictionary<string, StackMode> { { "Bear", StackMode.Hyperbolic }, { "ExecuteLowHealthElite", StackMode.Hyperbolic }, { "StunChanceOnHit", StackMode.Hyperbolic }, { "AlienHead", StackMode.Exponential }, { "EquipmentMagazine", StackMode.Exponential }, { "AutoCastEquipment", StackMode.Exponential }, { "HalfAttackSpeedHalfCooldowns", StackMode.Exponential }, { "LunarDagger", StackMode.Compound } }; internal static bool Shown(string key) { if (lines.TryGetValue(key, out var value)) { return value.Value; } return true; } private void Awake() { //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Expected O, but got Unknown //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Expected O, but got Unknown //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Expected O, but got Unknown Instance = this; ShowPanel = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel", "Show", true, "Показывать панель статистики."); ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Panel", "ToggleKey", (KeyCode)283, "Клавиша, которая показывает/прячет панель."); English = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel", "English", false, "Подписи на английском вместо русского."); PositionX = ((BaseUnityPlugin)this).Config.Bind<float>("Panel", "PositionX", 0.01f, "При Anchor = Screen: положение верхнего левого угла панели по горизонтали (0 — левый край, 1 — правый)."); PositionY = ((BaseUnityPlugin)this).Config.Bind<float>("Panel", "PositionY", 0.62f, "При Anchor = Screen: положение верхнего левого угла по вертикали (0 — низ, 1 — верх)."); FontSize = ((BaseUnityPlugin)this).Config.Bind<float>("Panel", "FontSize", 18f, "Размер шрифта панели."); DpsWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "DpsWindow", 5f, "За сколько последних секунд считать DPS."); IncludeMinions = ((BaseUnityPlugin)this).Config.Bind<bool>("Stats", "IncludeMinions", false, "Учитывать урон дронов и других миньонов в DPS и максимальном ударе."); for (int i = 0; i < LineSettings.GetLength(0); i++) { lines[LineSettings[i, 0]] = ((BaseUnityPlugin)this).Config.Bind<bool>("Lines", LineSettings[i, 0], true, "Показывать в панели: " + LineSettings[i, 1] + "."); } lines["ItemTiers"] = ((BaseUnityPlugin)this).Config.Bind<bool>("Lines", "ItemTiers", false, "Показывать в панели количество предметов по каждой редкости (подробно)."); Anchor = ((BaseUnityPlugin)this).Config.Bind<PanelAnchor>("Panel", "Anchor", PanelAnchor.Coins, "К чему привязана панель: Coins — слева под золотом и лунными монетами; Objectives — справа под списком целей (зарядка телепорта и т.д.); Screen — по PositionX/PositionY."); OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Panel", "OffsetX", 0f, "Сдвиг панели от точки привязки вправо (отрицательное — влево)."); OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Panel", "OffsetY", 6f, "Сдвиг панели от точки привязки вниз (отрицательное — вверх)."); StackTotals = ((BaseUnityPlugin)this).Config.Bind<bool>("Tooltips", "StackTotals", true, "Показывать в подсказке полное описание с итоговыми числами за все стаки предмета."); Run.onRunStartGlobal += delegate { ResetRunStats(); GoldBank.Reset(); }; Stage.onStageStartGlobal += delegate { GoldBank.RegisterClientHandler(); }; GlobalEventManager.onClientDamageNotified += OnClientDamageNotified; Harmony val = new Harmony("com.proigryfedorov.herostats"); val.Patch((MethodBase)AccessTools.Method(typeof(HUD), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(HeroStatsPlugin), "HudAwakePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(ItemIcon), "SetItemIndex", new Type[1] { typeof(SetItemIndexArgs) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(HeroStatsPlugin), "ItemIconPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.PropertyGetter(typeof(TooltipProvider), "bodyText"), (HarmonyMethod)null, new HarmonyMethod(typeof(HeroStatsPlugin), "BodyTextPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); GoldBank.Patch(val); ((BaseUnityPlugin)this).Logger.LogInfo((object)"HeroStats 1.0.1 loaded"); } private void ResetRunStats() { recentDamage.Clear(); recentDamageSum = 0f; maxHit = 0f; } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(ToggleKey.Value)) { ShowPanel.Value = !ShowPanel.Value; } } private void OnClientDamageNotified(DamageDealtMessage msg) { if (msg == null || (Object)(object)msg.attacker == (Object)null || msg.damage <= 0f) { return; } CharacterMaster val = LocalMaster(); if (!((Object)(object)val == (Object)null) && IsMine(msg.attacker, val)) { float time = Time.time; recentDamage.Enqueue(new KeyValuePair<float, float>(time, msg.damage)); recentDamageSum += msg.damage; if (msg.damage > maxHit) { maxHit = msg.damage; } } } private static bool IsMine(GameObject attacker, CharacterMaster local) { CharacterBody component = attacker.GetComponent<CharacterBody>(); if ((Object)(object)component == (Object)null || (Object)(object)component.master == (Object)null) { return false; } if ((Object)(object)component.master == (Object)(object)local) { return true; } if (!IncludeMinions.Value) { return false; } MinionOwnership minionOwnership = component.master.minionOwnership; if ((Object)(object)minionOwnership != (Object)null) { return (Object)(object)minionOwnership.ownerMaster == (Object)(object)local; } return false; } internal float Dps() { float num = Mathf.Max(1f, DpsWindow.Value); float num2 = Time.time - num; while (recentDamage.Count > 0 && recentDamage.Peek().Key < num2) { recentDamageSum -= recentDamage.Dequeue().Value; } if (recentDamage.Count == 0) { recentDamageSum = 0f; } return recentDamageSum / num; } internal static CharacterMaster LocalMaster() { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser == null) { return null; } return firstLocalUser.cachedMaster; } internal static string Num(double value) { return StackText.Short(value, English.Value); } internal static string L(string ru, string en) { if (!English.Value) { return ru; } return en; } internal static string TierName(ItemTier tier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected I4, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected I4, but got Unknown switch ((int)tier) { case 0: return L("Обычные", "Common"); case 1: return L("Необычные", "Uncommon"); case 2: return L("Легендарные", "Legendary"); case 4: return L("Босс", "Boss"); case 3: return L("Лунные", "Lunar"); case 6: return L("Пустота: обычные", "Void common"); case 7: return L("Пустота: необычные", "Void uncommon"); case 8: return L("Пустота: легендарные", "Void legendary"); case 9: return L("Пустота: босс", "Void boss"); case 10: return L("Еда", "Food"); case 11: return L("Проклятые", "Cursed"); case 12: return L("Страницы", "Pages"); case 13: return L("Порча", "Hex"); case 5: return L("Без редкости", "No tier"); default: { ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier); string text = (((Object)(object)itemTierDef != (Object)null) ? ((Object)itemTierDef).name.Replace("TierDef", "").Replace("Def", "").Trim() : ""); if (text.Length <= 0) { return L("Особые", "Other") + " (" + (int)tier + ")"; } return text; } } } internal static Color TierColor(ItemTier tier) { //IL_0000: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier); if (!((Object)(object)itemTierDef != (Object)null)) { return Color.white; } return Color32.op_Implicit(ColorCatalog.GetColor(itemTierDef.colorIndex)); } internal static string Hex(Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ColorUtility.ToHtmlStringRGB(c); } private static void HudAwakePostfix(HUD __instance) { try { StatsPanel.Create(__instance); } catch (Exception ex) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("Не удалось создать панель статистики: " + ex)); } } } private static void ItemIconPostfix(ItemIcon __instance, int ___itemCount) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!StackTotals.Value || (Object)(object)__instance.tooltipProvider == (Object)null) { return; } ItemDef itemDef = ItemCatalog.GetItemDef(__instance.itemIndex); if (!((Object)(object)itemDef == (Object)null)) { TooltipProvider tooltipProvider = __instance.tooltipProvider; TooltipMark tooltipMark = ((Component)tooltipProvider).GetComponent<TooltipMark>(); if ((Object)(object)tooltipMark == (Object)null) { tooltipMark = ((Component)tooltipProvider).gameObject.AddComponent<TooltipMark>(); } string text = ((tooltipMark.ours != null && tooltipProvider.overrideBodyText == tooltipMark.ours) ? null : tooltipProvider.bodyText); tooltipMark.baseText = text ?? tooltipMark.baseText ?? ""; tooltipMark.item = itemDef; tooltipMark.count = ___itemCount; BuildTooltip(tooltipProvider, tooltipMark); } } private static float CurrentLuck() { CharacterMaster val = LocalMaster(); if (!((Object)(object)val != (Object)null)) { return 0f; } return val.luck; } private static void BuildTooltip(TooltipProvider tooltip, TooltipMark mark) { ItemDef item = mark.item; int count = mark.count; float num = CurrentLuck(); StringBuilder stringBuilder = new StringBuilder(mark.baseText); string text; if (((Object)item).name == "LowerPricedChests") { text = StackText.SaleStar(count, num, English.Value); } else if (count > 1 || num != 0f) { if (!NonLinearItems.TryGetValue(((Object)item).name, out var value)) { value = StackMode.Linear; } text = StackText.Totals(Language.GetString(item.descriptionToken), count, value, num, English.Value); } else { text = null; } if (text != null) { stringBuilder.Append("\n\n<b>").Append(L("Всего за ", "Total for ")).Append(count) .Append(L(" шт.", "")); if (num != 0f) { stringBuilder.Append(L(", удача ", ", luck ")).Append(num.ToString("+0;-0", CultureInfo.InvariantCulture)); } stringBuilder.Append(":</b>\n").Append(text); } mark.luck = num; mark.ours = stringBuilder.ToString(); tooltip.overrideBodyText = mark.ours; } private static void BodyTextPostfix(TooltipProvider __instance, ref string __result) { if (StackTotals.Value) { TooltipMark component = ((Component)__instance).GetComponent<TooltipMark>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.item == (Object)null) && !(__result != component.ours) && component.luck != CurrentLuck()) { BuildTooltip(__instance, component); __result = component.ours; } } } } internal static class GoldBank { private const uint MoneyCap = 2000000000u; private const uint RefillBelow = 1000000000u; private const short MsgBank = 18800; private static readonly Dictionary<CharacterMaster, double> bank = new Dictionary<CharacterMaster, double>(); private static double clientBank; private static bool adjusting; public static void Patch(Harmony harmony) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(typeof(GoldBank), "GiveMoneyPrefix", (Type[])null); harmony.Patch((MethodBase)AccessTools.Method(typeof(CharacterMaster), "GiveMoney", new Type[2] { typeof(uint), typeof(bool) }, (Type[])null), val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(CharacterMaster), "GiveMoneyWithOnLevelUpFreeUnlock", new Type[1] { typeof(uint) }, (Type[])null), val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.PropertySetter(typeof(CharacterMaster), "money"), (HarmonyMethod)null, new HarmonyMethod(typeof(GoldBank), "SetMoneyPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(MoneyText), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(GoldBank), "MoneyTextPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } public static void Reset() { bank.Clear(); clientBank = 0.0; RegisterClientHandler(); } public static void RegisterClientHandler() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown NetworkClient val = (((Object)(object)NetworkManager.singleton != (Object)null) ? NetworkManager.singleton.client : null); if (val != null) { val.RegisterHandler((short)18800, new NetworkMessageDelegate(OnClientBank)); } } public static double Total(CharacterMaster master) { if ((Object)(object)master == (Object)null) { return 0.0; } double value = 0.0; if (NetworkServer.active) { bank.TryGetValue(master, out value); } else if ((Object)(object)master == (Object)(object)HeroStatsPlugin.LocalMaster()) { value = clientBank; } return (double)master.money + value; } private static void GiveMoneyPrefix(CharacterMaster __instance, ref uint amount) { if (NetworkServer.active && !adjusting) { uint num = __instance.money; if (num > 2000000000) { AddBank(__instance, num - 2000000000); SetWallet(__instance, 2000000000u); num = 2000000000u; } ulong num2 = (ulong)num + (ulong)amount; if (num2 > 2000000000) { AddBank(__instance, num2 - 2000000000); amount = 2000000000 - num; } } } private static void SetMoneyPostfix(CharacterMaster __instance) { if (NetworkServer.active && !adjusting && bank.TryGetValue(__instance, out var value) && !(value < 1.0)) { uint money = __instance.money; if (money < 1000000000) { uint num = (uint)Math.Min(value, 2000000000 - money); SetWallet(__instance, money + num); AddBank(__instance, 0.0 - (double)num); } } } private static void SetWallet(CharacterMaster master, uint value) { adjusting = true; try { master.money = value; } finally { adjusting = false; } } private static void AddBank(CharacterMaster master, double delta) { bank.TryGetValue(master, out var value); value = Math.Max(0.0, value + delta); bank[master] = value; SendBank(master, value); } private static void SendBank(CharacterMaster master, double value) { PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController; NetworkUser val = (((Object)(object)playerCharacterMasterController != (Object)null) ? playerCharacterMasterController.networkUser : null); if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).connectionToClient != null) { BankMessage bankMessage = new BankMessage(); bankMessage.value = value; ((NetworkBehaviour)val).connectionToClient.Send((short)18800, (MessageBase)(object)bankMessage); } } private static void OnClientBank(NetworkMessage netMsg) { clientBank = netMsg.ReadMessage<BankMessage>().value; } private static void MoneyTextPostfix(MoneyText __instance) { if ((Object)(object)__instance.targetText == (Object)null) { return; } foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList) { if ((Object)(object)readOnlyInstance.moneyText != (Object)(object)__instance) { continue; } CharacterMaster targetMaster = readOnlyInstance.targetMaster; if (!((Object)(object)targetMaster == (Object)null)) { string text = HeroStatsPlugin.Num(Total(targetMaster)); if (((TMP_Text)__instance.targetText).text != text) { ((TMP_Text)__instance.targetText).text = text; } } break; } } } internal class TooltipMark : MonoBehaviour { public string baseText; public string ours; public ItemDef item; public int count; public float luck; } internal class BankMessage : MessageBase { public double value; public override void Serialize(NetworkWriter writer) { writer.Write(value); } public override void Deserialize(NetworkReader reader) { value = reader.ReadDouble(); } } internal class StatsPanel : MonoBehaviour { private HUD hud; private RectTransform rect; private Image background; private TextMeshProUGUI text; private float nextRefresh; private static readonly FieldInfo LunarCoinField = AccessTools.Field(typeof(HUD), "lunarCoinContainer"); private static readonly FieldInfo VoidCoinField = AccessTools.Field(typeof(HUD), "voidCoinContainer"); private readonly Vector3[] corners = (Vector3[])(object)new Vector3[4]; private ObjectivePanelController objectives; public static void Create(HUD hud) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown Transform val = (((Object)(object)hud.mainContainer != (Object)null) ? hud.mainContainer.transform : ((Component)hud).transform); GameObject val2 = new GameObject("HeroStatsPanel", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(val, false); StatsPanel statsPanel = val2.AddComponent<StatsPanel>(); statsPanel.hud = hud; statsPanel.Build(); } private void Place() { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //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_0137: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(HeroStatsPlugin.OffsetX.Value, 0f - HeroStatsPlugin.OffsetY.Value); switch (HeroStatsPlugin.Anchor.Value) { case HeroStatsPlugin.PanelAnchor.Objectives: { if (ObjectivesBottomRight(out var point)) { rect.pivot = new Vector2(1f, 1f); ((Transform)rect).position = point; RectTransform obj2 = rect; obj2.anchoredPosition += val; return; } break; } case HeroStatsPlugin.PanelAnchor.Coins: { RectTransform val2 = LowestCurrency(); if ((Object)(object)val2 != (Object)null) { val2.GetWorldCorners(corners); rect.pivot = new Vector2(0f, 1f); ((Transform)rect).position = corners[0]; RectTransform obj = rect; obj.anchoredPosition += val; return; } break; } } rect.pivot = new Vector2(0f, 1f); RectTransform obj3 = rect; Vector2 anchorMin = (rect.anchorMax = new Vector2(HeroStatsPlugin.PositionX.Value, HeroStatsPlugin.PositionY.Value)); obj3.anchorMin = anchorMin; rect.anchoredPosition = val; } private bool ObjectivesBottomRight(out Vector3 point) { //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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; if ((Object)(object)objectives == (Object)null) { objectives = ((Component)hud).GetComponentInChildren<ObjectivePanelController>(true); } if ((Object)(object)objectives == (Object)null || !((Component)objectives).gameObject.activeInHierarchy) { return false; } ((RectTransform)((Component)objectives).transform).GetWorldCorners(corners); float x = corners[3].x; float num = float.MaxValue; RectTransform objectiveTrackerContainer = objectives.objectiveTrackerContainer; if ((Object)(object)objectiveTrackerContainer != (Object)null) { for (int i = 0; i < ((Transform)objectiveTrackerContainer).childCount; i++) { Transform child = ((Transform)objectiveTrackerContainer).GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { val.GetWorldCorners(corners); num = Mathf.Min(num, corners[0].y); } } if (num == float.MaxValue) { objectiveTrackerContainer.GetWorldCorners(corners); num = corners[0].y; } } else { num = corners[3].y; } point = new Vector3(x, num, corners[3].z); return true; } private RectTransform LowestCurrency() { RectTransform result = null; float num = float.MaxValue; GameObject[] array = (GameObject[])(object)new GameObject[3] { ((Object)(object)hud.moneyText != (Object)null) ? ((Component)hud.moneyText).gameObject : null, (GameObject)((LunarCoinField != null) ? /*isinst with value type is only supported in some contexts*/: null), (GameObject)((VoidCoinField != null) ? /*isinst with value type is only supported in some contexts*/: null) }; GameObject[] array2 = array; foreach (GameObject val in array2) { if ((Object)(object)val == (Object)null || !val.activeInHierarchy) { continue; } Transform transform = val.transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (!((Object)(object)val2 == (Object)null)) { val2.GetWorldCorners(corners); if (corners[0].y < num) { num = corners[0].y; result = val2; } } } return result; } private void Build() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown rect = (RectTransform)((Component)this).transform; rect.pivot = new Vector2(0f, 1f); background = ((Component)this).gameObject.AddComponent<Image>(); ((Graphic)background).color = new Color(0f, 0f, 0f, 0.45f); ((Graphic)background).raycastTarget = false; VerticalLayoutGroup val = ((Component)this).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)val).padding = new RectOffset(12, 14, 8, 10); ((HorizontalOrVerticalLayoutGroup)val).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val).childControlHeight = true; ContentSizeFitter val2 = ((Component)this).gameObject.AddComponent<ContentSizeFitter>(); val2.horizontalFit = (FitMode)2; val2.verticalFit = (FitMode)2; GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent(((Component)this).transform, false); text = val3.AddComponent<TextMeshProUGUI>(); TextMeshProUGUI componentInChildren = ((Component)hud).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)text).font = ((TMP_Text)componentInChildren).font; } ((TMP_Text)text).richText = true; ((Graphic)text).raycastTarget = false; ((TMP_Text)text).enableWordWrapping = false; ((TMP_Text)text).alignment = (TextAlignmentOptions)257; } private void Update() { bool flag = HeroStatsPlugin.ShowPanel.Value && (Object)(object)hud.targetBodyObject != (Object)null; if (((Component)text).gameObject.activeSelf != flag) { ((Component)text).gameObject.SetActive(flag); ((Behaviour)background).enabled = flag; } if (flag && !(Time.unscaledTime < nextRefresh)) { nextRefresh = Time.unscaledTime + 0.25f; Place(); ((TMP_Text)text).fontSize = HeroStatsPlugin.FontSize.Value; CharacterBody component = hud.targetBodyObject.GetComponent<CharacterBody>(); if ((Object)(object)component != (Object)null) { ((TMP_Text)text).text = Compose(component); ((Behaviour)background).enabled = ((TMP_Text)text).text.Length > 0; } } } private static void Line(StringBuilder sb, string key, string label, string color, string value) { if (HeroStatsPlugin.Shown(key)) { sb.Append(label).Append(": <color=#").Append(color) .Append(">") .Append(value) .Append("</color>\n"); } } private static string Compose(CharacterBody body) { HeroStatsPlugin instance = HeroStatsPlugin.Instance; StringBuilder stringBuilder = new StringBuilder(); if (HeroStatsPlugin.Shown("Title")) { stringBuilder.Append("<b>").Append(HeroStatsPlugin.L("Статистика", "Stats")).Append("</b>\n"); } Line(stringBuilder, "Damage", HeroStatsPlugin.L("Урон", "Damage"), "f2c46b", HeroStatsPlugin.Num(body.damage)); Line(stringBuilder, "AttackSpeed", HeroStatsPlugin.L("Скорость атаки", "Attack speed"), "f2c46b", body.attackSpeed.ToString("0.##", CultureInfo.InvariantCulture)); Line(stringBuilder, "Crit", HeroStatsPlugin.L("Шанс крита", "Crit chance"), "f2c46b", body.crit.ToString("0.#", CultureInfo.InvariantCulture) + "% (x" + body.critMultiplier.ToString("0.##", CultureInfo.InvariantCulture) + ")"); if (body.bleedChance > 0f) { Line(stringBuilder, "Bleed", HeroStatsPlugin.L("Кровотечение", "Bleed chance"), "e8473a", body.bleedChance.ToString("0.#", CultureInfo.InvariantCulture) + "%"); } HealthComponent healthComponent = body.healthComponent; if ((Object)(object)healthComponent != (Object)null) { string text = HeroStatsPlugin.Num(healthComponent.health) + " / " + HeroStatsPlugin.Num(body.maxHealth); if (body.maxShield > 0f) { string text2 = text; text = text2 + " (+" + HeroStatsPlugin.Num(healthComponent.shield) + HeroStatsPlugin.L(" щит", " shield") + ")"; } Line(stringBuilder, "Health", HeroStatsPlugin.L("Здоровье", "Health"), "77d14a", text); } Line(stringBuilder, "Regen", HeroStatsPlugin.L("Реген", "Regen"), "77d14a", HeroStatsPlugin.Num(body.regen) + HeroStatsPlugin.L("/с", "/s")); float armor = body.armor; float num = ((armor >= 0f) ? (100f / (100f + armor)) : (2f - 100f / (100f - armor))); Line(stringBuilder, "Armor", HeroStatsPlugin.L("Броня", "Armor"), "77d14a", HeroStatsPlugin.Num(armor) + " | " + ((1f - num) * 100f).ToString("0.##", CultureInfo.InvariantCulture) + "%"); Line(stringBuilder, "Speed", HeroStatsPlugin.L("Скорость", "Speed"), "6fb4e8", body.moveSpeed.ToString("0.##", CultureInfo.InvariantCulture) + HeroStatsPlugin.L(" м/с", " m/s")); if ((Object)(object)body.characterMotor != (Object)null) { int num2 = Mathf.Max(0, body.maxJumpCount - body.characterMotor.jumpCount); Line(stringBuilder, "Jumps", HeroStatsPlugin.L("Прыжки", "Jumps"), "6fb4e8", num2 + " / " + body.maxJumpCount); } Line(stringBuilder, "Level", HeroStatsPlugin.L("Уровень", "Level"), "dddddd", ((int)body.level).ToString()); CharacterMaster master = body.master; if ((Object)(object)master != (Object)null) { Line(stringBuilder, "Gold", HeroStatsPlugin.L("Золото", "Gold"), "f2d24b", HeroStatsPlugin.Num(GoldBank.Total(master))); if (master.luck != 0f) { Line(stringBuilder, "Luck", HeroStatsPlugin.L("Удача", "Luck"), "6fe8c4", master.luck.ToString("0.##", CultureInfo.InvariantCulture)); } ulong num3 = 0uL; if ((Object)(object)master.playerStatsComponent != (Object)null && master.playerStatsComponent.currentStats != null) { num3 = master.playerStatsComponent.currentStats.GetStatValueULong(StatDef.totalKills); } Line(stringBuilder, "Kills", HeroStatsPlugin.L("Убийства", "Kills"), "f2925a", HeroStatsPlugin.Num(num3)); } Line(stringBuilder, "Dps", "DPS", "f2c46b", HeroStatsPlugin.Num(instance.Dps())); Line(stringBuilder, "MaxHit", HeroStatsPlugin.L("Макс. удар", "Max hit"), "ff6060", HeroStatsPlugin.Num(instance.maxHit)); if ((HeroStatsPlugin.Shown("ItemCounts") || HeroStatsPlugin.Shown("ItemTiers")) && (Object)(object)master != (Object)null && (Object)(object)master.inventory != (Object)null) { AppendItemCounts(stringBuilder, master.inventory); } return stringBuilder.ToString().TrimEnd('\n'); } private static void AppendItemCounts(StringBuilder sb, Inventory inv) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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_016b: Unknown result type (might be due to invalid IL or missing references) Dictionary<ItemTier, int> dictionary = new Dictionary<ItemTier, int>(); List<ItemTier> list = new List<ItemTier>(); int num = 0; foreach (ItemIndex item in inv.itemAcquisitionOrder) { ItemDef itemDef = ItemCatalog.GetItemDef(item); if ((Object)(object)itemDef == (Object)null || itemDef.hidden) { continue; } int itemCount = inv.GetItemCount(item); if (itemCount > 0) { if (!dictionary.ContainsKey(itemDef.tier)) { dictionary[itemDef.tier] = 0; list.Add(itemDef.tier); } dictionary[itemDef.tier] += itemCount; num += itemCount; } } if (num == 0) { return; } list.Sort(); if (HeroStatsPlugin.Shown("ItemCounts")) { sb.Append("<b>").Append(HeroStatsPlugin.L("Предметы", "Items")).Append(": ") .Append(HeroStatsPlugin.Num(num)) .Append("</b>\n"); } if (!HeroStatsPlugin.Shown("ItemTiers")) { return; } foreach (ItemTier item2 in list) { sb.Append(" <color=#").Append(HeroStatsPlugin.Hex(HeroStatsPlugin.TierColor(item2))).Append(">") .Append(HeroStatsPlugin.TierName(item2)) .Append(": ") .Append(HeroStatsPlugin.Num(dictionary[item2])) .Append("</color>\n"); } } } internal enum StackMode { Linear, Hyperbolic, Exponential, Compound } internal static class StackText { private static readonly Regex StackNote = new Regex("<style=cStack>(?<pre>[^(<]*)\\(\\s*(?<sign>[+\\-−])\\s*\\$?(?<per>\\d+(?:[.,]\\d+)?)(?<perPct>%?)[^)]*\\)(?<post>[^<]*)</style>", RegexOptions.Compiled); private static readonly Regex SentenceNote = new Regex("<style=cStack>(?<text>[^(<]*?)(?<num>\\d+(?:[.,]\\d+)?)%(?<rest>[^(<]*)</style>", RegexOptions.Compiled); private static readonly Regex NumberPattern = new Regex("[+\\-]?\\$?\\d+(?:[.,]\\d+)?%?", RegexOptions.Compiled); private static readonly Regex TagPattern = new Regex("<[^>]*>", RegexOptions.Compiled); private static readonly Regex DoubleDot = new Regex("\\.(</color>)\\.", RegexOptions.Compiled); private static readonly Regex IgnoresLuck = new Regex("Unaffected by luck|удачи не учитывается", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex ChanceBefore = new Regex("(вероятност\\w*|шанс\\w*|chance)( (в|с|of|a|из))? ?$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex ChanceAfter = new Regex("^ ?(вероятност|шанс|chance)", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex Spaces = new Regex("\\s+", RegexOptions.Compiled); private static readonly Regex PercentPattern = new Regex("\\d+(?:[.,]\\d+)?%", RegexOptions.Compiled); private static readonly Regex ReductionWord = new Regex("сниж|уменьш|reduc|decreas", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly string[] SuffixRu = new string[9] { "", " тыс.", " млн", " млрд", " трлн", " квадрлн", " квинтлн", " секстлн", " септлн" }; private static readonly string[] SuffixEn = new string[9] { "", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp" }; public static string Totals(string description, int count, StackMode mode, float luck, bool english) { if (string.IsNullOrEmpty(description) || count < 1) { return null; } bool flag = luck != 0f && !IgnoresLuck.IsMatch(description); StringBuilder stringBuilder = new StringBuilder(); int num = 0; bool found = false; foreach (Match item in StackNote.Matches(description)) { if (!TryParse(item.Groups["per"].Value, out var value)) { continue; } found = true; double sign = ((item.Groups["sign"].Value == "+") ? 1.0 : (-1.0)); bool flag2 = item.Groups["perPct"].Value == "%"; string text = description.Substring(num, item.Index - num); string text2 = TagPattern.Replace(text, (Match t) => new string(' ', t.Length)); MatchCollection matchCollection = NumberPattern.Matches(text2); if (matchCollection.Count > 0) { Match match2 = matchCollection[matchCollection.Count - 1]; string value2 = match2.Value; bool flag3 = value2.EndsWith("%"); TryParse(value2.Trim('+', '-', '$', '%'), out var value3); if (value2.StartsWith("-")) { value3 = 0.0 - value3; } string text3 = text2.Substring(0, match2.Index); string input = text3.Substring(text3.LastIndexOf('.') + 1); bool flag4 = ReductionWord.IsMatch(input); double num2 = Total(value3, value, sign, count, flag3, flag2, mode, flag4); string text4 = text.Substring(0, match2.Index); stringBuilder.Append(flag ? AnnotateChances(text4, luck, english) : text4); stringBuilder.Append(text, match2.Index, text.Length - match2.Index); stringBuilder.Append(item.Value); stringBuilder.Append(" <color=#ffffff>= "); if (value2.StartsWith("+") && num2 >= 0.0) { stringBuilder.Append('+'); } if (value2.Contains("$")) { stringBuilder.Append('$'); } stringBuilder.Append(FullNumber(num2, english)); stringBuilder.Append(flag3 ? "%" : UnitAfter(text2, match2.Index + match2.Length)); if (mode == StackMode.Compound && flag3) { stringBuilder.Append(" (x").Append(FullNumber(flag4 ? (1.0 - num2 / 100.0) : (1.0 + num2 / 100.0), english)).Append(')'); } stringBuilder.Append("</color>"); string text5 = TagPattern.Replace(description.Substring(item.Index + item.Length), ""); if (flag && flag3 && IsChance(text2.Substring(0, match2.Index), text2.Substring(match2.Index + match2.Length) + text5)) { AppendLuck(stringBuilder, num2, luck, english); } } else { stringBuilder.Append(flag ? AnnotateChances(text, luck, english) : text); stringBuilder.Append(item.Value); stringBuilder.Append(" <color=#ffffff>= ").Append(FullNumber(value * (double)count, english)); if (flag2) { stringBuilder.Append('%'); } stringBuilder.Append("</color>"); } num = item.Index + item.Length; } string text6 = description.Substring(num); stringBuilder.Append(flag ? AnnotateChances(text6, luck, english) : text6); if (flag && stringBuilder.ToString() != description) { found = true; } string input2 = SentenceNote.Replace(stringBuilder.ToString(), delegate(Match m) { if (!TryParse(m.Groups["num"].Value, out var value4)) { return m.Value; } found = true; return m.Value + " <color=#ffffff>= " + FullNumber(value4 * (double)(count - 1), english) + "%</color>"; }); if (!found) { return null; } return DoubleDot.Replace(input2, ".$1"); } private static bool IsChance(string before, string after) { if (!ChanceBefore.IsMatch(Spaces.Replace(before, " ").TrimEnd())) { return ChanceAfter.IsMatch(Spaces.Replace(after, " ")); } return true; } private static string AnnotateChances(string text, float luck, bool english) { string text2 = TagPattern.Replace(text, (Match t) => new string(' ', t.Length)); MatchCollection matchCollection = PercentPattern.Matches(text2); if (matchCollection.Count == 0) { return text; } StringBuilder stringBuilder = new StringBuilder(text); for (int num = matchCollection.Count - 1; num >= 0; num--) { Match match = matchCollection[num]; int num2 = match.Index + match.Length; if (IsChance(text2.Substring(0, match.Index), text2.Substring(num2))) { int num3 = num2; Match match2 = Regex.Match(text.Substring(num2), "^(</[^>]*>)+"); if (match2.Success) { num3 += match2.Length; } TryParse(match.Value.TrimEnd('%'), out var value); StringBuilder stringBuilder2 = new StringBuilder(); AppendLuck(stringBuilder2, value, luck, english); stringBuilder.Insert(num3, stringBuilder2.ToString()); } } return stringBuilder.ToString(); } private static string UnitAfter(string maskedRegion, int afterNumber) { string text = maskedRegion.Substring(afterNumber); string text2 = text.TrimStart(); int num = text2.IndexOfAny(new char[3] { ' ', '\u00a0', '\n' }); string text3 = ((num < 0) ? text2 : text2.Substring(0, num)); text3 = text3.TrimEnd(',', ';', ':'); if (text3.Length == 0 || text3.Length > 7 || char.IsDigit(text3[0])) { return ""; } return ((text.Length > 0 && char.IsWhiteSpace(text[0])) ? " " : "") + text3; } public static double LuckyChance(double percent, float luck) { double num = Math.Min(Math.Max(percent, 0.0), 100.0) / 100.0; int num2 = 1 + (int)Math.Ceiling(Math.Abs(luck)); double num3 = ((luck > 0f) ? (1.0 - Math.Pow(1.0 - num, num2)) : Math.Pow(num, num2)); return 100.0 * num3; } private static void AppendLuck(StringBuilder sb, double percent, float luck, bool english) { sb.Append(" <color=#6fe8c4>(").Append(english ? "with luck " : "с удачей ").Append(FullNumber(LuckyChance(percent, luck), english)) .Append("%)</color>"); } public static string SaleStar(int stars, float luck, bool english) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(english ? "First chest of a stage drops " : "Первый сундук на уровне даёт ").Append("<color=#ffffff>2</color>").Append(english ? " items." : " предмета."); if (stars < 2) { stringBuilder.Append(english ? "\nWith 2+ stars it can drop up to 5." : "\nС 2+ звёздами может дать до 5."); return stringBuilder.ToString(); } double num = ((stars >= 3) ? (100.0 * (1.0 - 1.0 / ((double)stars * 0.05 + 1.0))) : 0.0); double[] array = new double[3] { 30.0, 15.0, 1.0 }; double num2 = 1.0; double num3 = 2.0; for (int i = 0; i < array.Length; i++) { double num4 = LuckyChance(array[i] + num, luck) / 100.0; num2 *= num4; num3 += num2; stringBuilder.Append('\n').Append(english ? "Item " : "").Append(i + 3) .Append(english ? ": " : "-й предмет: ") .Append("<color=#ffffff>") .Append(FullNumber(num2 * 100.0, english)) .Append("%</color>"); } stringBuilder.Append('\n').Append(english ? "Expected items: " : "В среднем предметов: ").Append("<color=#ffffff>") .Append(FullNumber(num3, english)) .Append("</color>"); return stringBuilder.ToString(); } private static double Total(double baseValue, double per, double sign, int count, bool basePct, bool perPct, StackMode mode, bool reduction) { if (basePct && perPct && mode == StackMode.Compound) { if (!reduction) { return 100.0 * (Math.Pow(1.0 + per / 100.0, count) - 1.0); } return 100.0 * (1.0 - Math.Pow(1.0 - per / 100.0, count)); } if (perPct && !basePct) { if (!(sign < 0.0)) { return baseValue * (1.0 + per / 100.0 * (double)(count - 1)); } return baseValue * Math.Pow(1.0 - per / 100.0, count - 1); } if (basePct && perPct && mode == StackMode.Hyperbolic) { return 100.0 * (1.0 - 1.0 / (1.0 + per / 100.0 * (double)count)); } if (basePct && perPct && mode == StackMode.Exponential) { return 100.0 * (1.0 - (1.0 - baseValue / 100.0) * Math.Pow(1.0 - per / 100.0, count - 1)); } return baseValue + sign * per * (double)(count - 1); } public static string FullNumber(double value, bool english) { if (Math.Abs(value) >= 1000000000000000.0) { return Short(value, english); } NumberFormatInfo numberFormatInfo = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone(); numberFormatInfo.NumberGroupSeparator = (english ? "," : "\u00a0"); numberFormatInfo.NumberDecimalSeparator = (english ? "." : ","); bool flag = Math.Abs(value - Math.Round(value)) < 0.005; return value.ToString(flag ? "#,0" : "#,0.##", numberFormatInfo); } public static string Short(double value, bool english) { string[] array = (english ? SuffixEn : SuffixRu); double num = Math.Abs(value); int num2 = 0; while (num >= 1000.0 && num2 < array.Length - 1) { num /= 1000.0; num2++; } return ((double)Math.Sign(value) * num).ToString((num2 == 0) ? "0.##" : "0.00", CultureInfo.InvariantCulture) + array[num2]; } private static bool TryParse(string text, out double value) { return double.TryParse(text.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out value); } }