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 DpsMeter v0.7.0
plugins\DpsMeter\DpsMeter.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DpsMeter.Net; using DpsMeter.Reporting; using DpsMeter.Tracking; using DpsMeter.Ui; using HarmonyLib; using RoR2; using RoR2.Projectile; using RoR2.Skills; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DpsMeter")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5c60c9238d496516bd58d7768f6795696c7de4aa")] [assembly: AssemblyProduct("DpsMeter")] [assembly: AssemblyTitle("DpsMeter")] [assembly: AssemblyVersion("1.0.0.0")] namespace DpsMeter { [BepInPlugin("noctilucentgames.dpsmeter", "DPS Meter", "0.7.0")] public sealed class DpsMeterPlugin : BaseUnityPlugin { public const string Guid = "noctilucentgames.dpsmeter"; public const string Name = "DPS Meter"; public const string Version = "0.7.0"; private readonly Harmony _harmony = new Harmony("noctilucentgames.dpsmeter"); internal static ManualLogSource Log; internal static readonly DamageTracker Tracker = new DamageTracker(); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; PluginConfig.Init(((BaseUnityPlugin)this).Config); ScopeStats.WindowSeconds = PluginConfig.WindowSeconds.Value; RoR2Application.isModded = true; GlobalEventManager.onServerDamageDealt += OnServerDamageDealt; Run.onRunStartGlobal += OnRunStart; BossGroup.onBossGroupStartServer += OnBossGroupStart; BossGroup.onBossGroupDefeatedServer += OnBossGroupEnd; Stage.onServerStageBegin += OnStageBegin; Run.onRunDestroyGlobal += OnRunEnd; Run.onClientGameOverGlobal += OnGameOver; SessionReport.Init(Log); RunExport.Init(Log); InventoryWatcher.Subscribe(); InflictorMap.Load(); try { _harmony.PatchAll(typeof(DelayBlastScope)); } catch (Exception ex) { Log.LogWarning((object)("DelayBlast patch failed, wisp/Shatterspleen stay unattributed: " + ex.Message)); } ((Component)this).gameObject.AddComponent<MeterNetwork>(); ((Component)this).gameObject.AddComponent<DpsPanel>(); ((Component)this).gameObject.AddComponent<DetailScreen>(); Log.LogInfo((object)$"inflictor map: {InflictorMap.Count} prefabs"); Log.LogInfo((object)"hooked onServerDamageDealt | F8 show/hide, F7 scope, F6 detail, F11 full screen, F9/F10 log dump"); } private void OnDestroy() { GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt; Run.onRunStartGlobal -= OnRunStart; BossGroup.onBossGroupStartServer -= OnBossGroupStart; BossGroup.onBossGroupDefeatedServer -= OnBossGroupEnd; Stage.onServerStageBegin -= OnStageBegin; Run.onRunDestroyGlobal -= OnRunEnd; Run.onClientGameOverGlobal -= OnGameOver; InventoryWatcher.Unsubscribe(); _harmony.UnpatchSelf(); } private void Update() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) RunExport.Tick(); if (Input.GetKeyDown(PluginConfig.DumpMobsKey.Value)) { Dump(DamageScope.Mobs); } else if (Input.GetKeyDown(PluginConfig.DumpBossKey.Value)) { Dump(DamageScope.TeleporterBoss); } } private static void OnBossGroupStart(BossGroup group) { bool flag = Tracker.IsEncounterContinuation(); Tracker.RegisterBossGroup(group); if (PluginConfig.ResetBossOnEncounter.Value && !flag) { Tracker.ResetScope(DamageScope.TeleporterBoss); } else if (flag) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)"boss group started as a continuation; keeping the numbers"); } } } private static void OnBossGroupEnd(BossGroup group) { Tracker.UnregisterBossGroup(group); if (PluginConfig.AutoReport.Value) { SessionReport.Write(Tracker, "Boss defeated on stage " + StageLabel()); } } private static void OnRunEnd(Run run) { if (PluginConfig.AutoReport.Value) { SessionReport.Write(Tracker, "Run ended on stage " + StageLabel()); } RunExport.RunDestroyed(); } private static void OnGameOver(Run run, RunReport report) { RunExport.RunOver(); } private static void OnStageBegin(Stage stage) { if (PluginConfig.AutoReport.Value) { SessionReport.Write(Tracker, "Stage " + StageLabel() + " - entering next stage"); } if (PluginConfig.ResetMobsOnStage.Value) { Tracker.ResetScope(DamageScope.Mobs); Tracker.ResetTakenTotals(); } } private static string StageLabel() { Run instance = Run.instance; string text = (((Object)(object)instance != (Object)null) ? (instance.stageClearCount + 1).ToString() : "?"); Stage instance2 = Stage.instance; string text2 = (((Object)(object)instance2 != (Object)null && (Object)(object)instance2.sceneDef != (Object)null) ? instance2.sceneDef.cachedName : null); if (!string.IsNullOrEmpty(text2)) { return text + " (" + text2 + ")"; } return text; } private static void OnRunStart(Run run) { Tracker.Clear(); MeterNetwork.ResetForNewRun(); InventoryWatcher.Clear(); SessionReport.BeginRun(); RunExport.BeginRun(); } private static void OnServerDamageDealt(DamageReport report) { if (NetworkServer.active) { Tracker.Record(report); } } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CcDps(ConCommandArgs args) { Dump((((ConCommandArgs)(ref args)).Count > 0 && ((ConCommandArgs)(ref args))[0].StartsWith("boss", StringComparison.OrdinalIgnoreCase)) ? DamageScope.TeleporterBoss : DamageScope.Mobs); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CcDpsReset(ConCommandArgs args) { Tracker.ResetAll(); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"reset"); } } internal static void Dump(DamageScope scope) { StringBuilder stringBuilder = new StringBuilder(); ReportBuilder.AppendScope(stringBuilder, Tracker, scope); ReportBuilder.AppendUnresolved(stringBuilder, Tracker); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } } public static class PluginConfig { public static ConfigEntry<KeyCode> ToggleKey; public static ConfigEntry<KeyCode> ScopeKey; public static ConfigEntry<KeyCode> DetailKey; public static ConfigEntry<KeyCode> ScreenKey; public static ConfigEntry<KeyCode> DumpMobsKey; public static ConfigEntry<KeyCode> DumpBossKey; public static ConfigEntry<bool> VisibleByDefault; public static ConfigEntry<bool> HideWithHud; public static ConfigEntry<bool> AutoScope; public static ConfigEntry<bool> ColorByMagnitude; public static ConfigEntry<bool> AvoidHudElements; public static ConfigEntry<int> NetMessageId; public static ConfigEntry<float> NetSendRate; public static ConfigEntry<bool> AutoReport; public static ConfigEntry<bool> ResetMobsOnStage; public static ConfigEntry<bool> ResetBossOnEncounter; public static ConfigEntry<float> WindowSeconds; public static ConfigEntry<float> PanelWidth; public static ConfigEntry<float> PanelMargin; public static ConfigEntry<int> MaxDetailRows; public static ConfigEntry<bool> AnchorRight; public static void Init(ConfigFile cfg) { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Expected O, but got Unknown ToggleKey = cfg.Bind<KeyCode>("Keys", "Toggle", (KeyCode)289, "Show or hide the meter."); ScopeKey = cfg.Bind<KeyCode>("Keys", "Scope", (KeyCode)288, "Switch between mobs and boss damage."); DetailKey = cfg.Bind<KeyCode>("Keys", "Detail", (KeyCode)287, "Expand or collapse the per-source breakdown."); ScreenKey = cfg.Bind<KeyCode>("Keys", "DetailScreen", (KeyCode)292, "Open the full-screen breakdown. While it is open the scope and detail keys switch mobs/boss and dealt/taken."); DumpMobsKey = cfg.Bind<KeyCode>("Keys", "DumpMobs", (KeyCode)290, "Write the mob breakdown to the log."); DumpBossKey = cfg.Bind<KeyCode>("Keys", "DumpBoss", (KeyCode)291, "Write the boss breakdown to the log."); VisibleByDefault = cfg.Bind<bool>("Display", "VisibleByDefault", true, "Show the meter as soon as a run starts."); AutoScope = cfg.Bind<bool>("Display", "AutoScope", true, "Switch to boss damage when a boss encounter starts, and back to mobs on a new stage. You can still switch manually at any time; the next transition takes over again."); ColorByMagnitude = cfg.Bind<bool>("Display", "ColorByMagnitude", true, "Tint numbers by magnitude - k green, M blue, B purple, T and beyond pink - so the scale registers before the text is read. Percentages are never tinted, since they are not magnitudes."); HideWithHud = cfg.Bind<bool>("Display", "HideWithHud", true, "Hide the meter whenever the game hides its own HUD - cutscenes, cinematics and stage transitions. Turn off to keep it on screen at all times."); AvoidHudElements = cfg.Bind<bool>("Display", "AvoidHudElements", true, "Sit below the run timer and objective strip instead of overlapping them. Measured each refresh, so it follows the objective panel as it grows and shrinks. Turn off to use PanelMargin as a fixed offset."); PanelWidth = cfg.Bind<float>("Display", "PanelWidth", 440f, new ConfigDescription("Panel width in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(220f, 900f), Array.Empty<object>())); PanelMargin = cfg.Bind<float>("Display", "PanelMargin", 12f, new ConfigDescription("Gap from the screen edge in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), Array.Empty<object>())); AnchorRight = cfg.Bind<bool>("Display", "AnchorRight", true, "Anchor to the right edge of the screen. False anchors left."); MaxDetailRows = cfg.Bind<int>("Display", "MaxDetailRows", 8, new ConfigDescription("Sources shown per player when expanded.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), Array.Empty<object>())); WindowSeconds = cfg.Bind<float>("Tracking", "WindowSeconds", 5f, new ConfigDescription("Length of the trailing window for the live DPS figure. Shorter reacts faster and reads spikier; longer is steadier but lags burst damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); NetMessageId = cfg.Bind<int>("Networking", "MessageId", 1495, new ConfigDescription("UNet message id used to broadcast the meter to clients. Ids are a flat shared space, so change this if it ever clashes with the game or another mod. Every player must use the same value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(200, 32000), Array.Empty<object>())); NetSendRate = cfg.Bind<float>("Networking", "SendRate", 3f, new ConfigDescription("Snapshots per second sent to clients. Higher is smoother and costs more bandwidth; the meter only refreshes a few times a second anyway.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); AutoReport = cfg.Bind<bool>("Tracking", "AutoReport", true, "Write a breakdown to BepInEx/DpsMeter/report-*.log before each stage and boss reset, so attribution problems can be reviewed after the fact."); ResetMobsOnStage = cfg.Bind<bool>("Tracking", "ResetMobsOnStage", true, "Clear mob damage when a new stage begins, so totals mean 'this stage'. False accumulates across the whole run."); ResetBossOnEncounter = cfg.Bind<bool>("Tracking", "ResetBossOnEncounter", true, "Clear boss damage when a boss encounter starts, so totals mean 'this fight'. False accumulates across every boss in the run."); } } } namespace DpsMeter.Ui { public sealed class DetailScreen : MonoBehaviour { private struct Row { public RectTransform Root; public HGTextMeshProUGUI[] Cells; public int CacheStyle; } private const int MaxRows = 34; private const float RowHeight = 24f; private const float HeaderHeight = 40f; private const float TabHeight = 26f; private const float ColHeadHeight = 22f; private const float FooterHeight = 26f; private const float ContentWidth = 1120f; private const float Pad = 18f; private static readonly Color Backdrop = new Color(0f, 0f, 0f, 0.74f); private static readonly Color Dim = new Color(0.48f, 0.53f, 0.6f); private static readonly Color Head = new Color(0.72f, 0.78f, 0.86f); private static readonly float[] ColFrac = new float[6] { 0f, 0.42f, 0.55f, 0.66f, 0.77f, 0.89f }; private bool _built; private ViewMode _mode; private int _scroll; private Canvas _canvas; private RectTransform _content; private Image _contentImg; private HGTextMeshProUGUI _title; private HGTextMeshProUGUI _tabs; private HGTextMeshProUGUI _footer; private HGTextMeshProUGUI[] _colHeads; private Row[] _rows; private int _activeRows; private float _nextRefresh; public static bool IsOpen { get; private set; } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(PluginConfig.ScreenKey.Value)) { Toggle(); } if (!IsOpen) { return; } if ((Object)(object)Run.instance == (Object)null) { Close(); return; } if (Input.GetKeyDown(PluginConfig.ScopeKey.Value)) { _mode = DamageScopeNames.Next(_mode); _scroll = 0; _nextRefresh = 0f; } float y = Input.mouseScrollDelta.y; if (Mathf.Abs(y) > 0.01f) { _scroll = Mathf.Max(0, _scroll - Mathf.RoundToInt(y) * 3); _nextRefresh = 0f; } if (!(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + 0.25f; Refresh(); } } private void Toggle() { if (IsOpen) { Close(); } else if (!((Object)(object)Run.instance == (Object)null)) { if (!_built) { Build(); } IsOpen = true; ((Behaviour)_canvas).enabled = true; _nextRefresh = 0f; Refresh(); } } private void Close() { IsOpen = false; if ((Object)(object)_canvas != (Object)null) { ((Behaviour)_canvas).enabled = false; } } private void Build() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) _built = true; GameObject val = new GameObject("DpsDetailCanvas"); val.transform.SetParent(((Component)this).transform, false); _canvas = val.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 55; CanvasScaler obj = val.AddComponent<CanvasScaler>(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); obj.matchWidthOrHeight = 1f; GameObject val2 = new GameObject("Backdrop", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(val.transform, false); RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; Vector2 val4 = (val3.offsetMin = (val3.offsetMax = Vector2.zero)); Image obj2 = val2.AddComponent<Image>(); ((Graphic)obj2).color = Backdrop; ((Graphic)obj2).raycastTarget = false; GameObject val6 = new GameObject("Content", new Type[1] { typeof(RectTransform) }); val6.transform.SetParent(val.transform, false); _content = (RectTransform)val6.transform; RectTransform content = _content; RectTransform content2 = _content; ((Vector2)(ref val4))..ctor(0.5f, 0.5f); content2.anchorMax = val4; content.anchorMin = val4; _content.pivot = new Vector2(0.5f, 0.5f); _content.sizeDelta = new Vector2(1120f, 400f); _contentImg = val6.AddComponent<Image>(); Image contentImg = _contentImg; ((Graphic)contentImg).color = ModePalette.ScreenBackground(ViewMode.Mobs); ((Graphic)contentImg).raycastTarget = false; _title = Text((Transform)(object)_content, "Title", 26f, ModePalette.Accent(ViewMode.Mobs), (TextAlignmentOptions)4097); Place(((TMP_Text)_title).rectTransform, 18f, -6f, 1084f, 40f); _tabs = Text((Transform)(object)_content, "Tabs", 15f, Dim, (TextAlignmentOptions)4097); Place(((TMP_Text)_tabs).rectTransform, 18f, -40f, 1084f, 26f); string[] array = new string[6] { "SOURCE", "DAMAGE", "SHARE", "HITS", "CRIT", "AVG HIT" }; _colHeads = (HGTextMeshProUGUI[])(object)new HGTextMeshProUGUI[array.Length]; for (int i = 0; i < array.Length; i++) { _colHeads[i] = Text((Transform)(object)_content, "H" + i, 12f, Dim, (TextAlignmentOptions)((i == 0) ? 4097 : 4100)); ((TMP_Text)_colHeads[i]).text = array[i]; PlaceCell(((TMP_Text)_colHeads[i]).rectTransform, i, -66f, 22f, 0f); } _rows = new Row[34]; for (int j = 0; j < 34; j++) { _rows[j] = MakeRow(j); } _footer = Text((Transform)(object)_content, "Footer", 13f, Dim, (TextAlignmentOptions)4100); RectTransform rectTransform = ((TMP_Text)_footer).rectTransform; ((Vector2)(ref val4))..ctor(1f, 0f); rectTransform.anchorMax = val4; rectTransform.anchorMin = val4; rectTransform.pivot = new Vector2(1f, 0f); rectTransform.anchoredPosition = new Vector2(-18f, 4f); rectTransform.sizeDelta = new Vector2(1084f, 26f); ((Behaviour)_canvas).enabled = false; } private Row MakeRow(int index) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0047: Expected O, but got Unknown //IL_005a: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("R" + index, new Type[1] { typeof(RectTransform) }); val.transform.SetParent((Transform)(object)_content, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0f, 1f); val2.sizeDelta = new Vector2(1120f, 24f); val.SetActive(false); HGTextMeshProUGUI[] array = (HGTextMeshProUGUI[])(object)new HGTextMeshProUGUI[6]; for (int i = 0; i < 6; i++) { array[i] = Text((Transform)(object)val2, "C" + i, 15f, Head, (TextAlignmentOptions)((i == 0) ? 4097 : 4100)); PlaceCell(((TMP_Text)array[i]).rectTransform, i, 0f, 24f, 0f); } return new Row { Root = val2, Cells = array, CacheStyle = -1 }; } private static void PlaceCell(RectTransform rt, int col, float y, float h, float indent) { float x = 18f + indent + ColFrac[col] * 1084f; float num = ((col == 0) ? (ColFrac[1] * 1084f - indent - 12f) : (((col == ColFrac.Length - 1) ? (1f - ColFrac[col]) : (ColFrac[col + 1] - ColFrac[col])) * 1084f - 10f)); Place(rt, x, y, Mathf.Max(30f, num), h); } private static HGTextMeshProUGUI Text(Transform parent, string name, float size, Color color, TextAlignmentOptions align) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); HGTextMeshProUGUI val2 = val.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)val2).fontSize = size; ((Graphic)val2).color = color; ((TMP_Text)val2).alignment = align; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)1; ((Graphic)val2).raycastTarget = false; if ((Object)(object)HGTextMeshProUGUI.defaultLanguageFont != (Object)null) { ((TMP_Text)val2).font = HGTextMeshProUGUI.defaultLanguageFont; } return val2; } private static void Place(RectTransform rt, float x, float y, float w, float h) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); rt.anchorMax = val; rt.anchorMin = val; rt.pivot = new Vector2(0f, 1f); rt.anchoredPosition = new Vector2(x, y); rt.sizeDelta = new Vector2(w, h); } private void Refresh() { //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) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) bool flag = _mode == ViewMode.Taken; Color val = ModePalette.Accent(_mode); ((Graphic)_title).color = val; ((Graphic)_contentImg).color = ModePalette.ScreenBackground(_mode); ((TMP_Text)_tabs).text = Tabs(_mode); ((TMP_Text)_footer).text = "F7 mobs / boss / taken · wheel scrolls · " + ((object)PluginConfig.ScreenKey.Value/*cast due to .constrained prefix*/).ToString() + " close"; SetHeads(flag); int num = (flag ? RefreshTaken(val) : RefreshDealt(val)); for (int i = num; i < _activeRows; i++) { ((Component)_rows[i].Root).gameObject.SetActive(false); } _activeRows = num; float num2 = 88f + (float)num * 24f + 26f + 8f; _content.sizeDelta = new Vector2(1120f, Mathf.Min(num2, 960f)); } private static string Tabs(ViewMode m) { string text = ((m == ViewMode.Mobs) ? "<b>[ Mobs ]</b>" : "Mobs"); string text2 = ((m == ViewMode.Boss) ? "<b>[ Boss ]</b>" : "Boss"); string text3 = ((m == ViewMode.Taken) ? "<b>[ Taken ]</b>" : "Taken"); return text + " " + text2 + " " + text3; } private void SetHeads(bool taken) { string[] array = ((!taken) ? new string[6] { "SOURCE", "DAMAGE", "SHARE", "HITS", "CRIT", "AVG HIT" } : new string[6] { "SOURCE", "DAMAGE", "", "COUNT", "CRIT", "WHEN" }); for (int i = 0; i < _colHeads.Length; i++) { ((TMP_Text)_colHeads[i]).text = array[i]; } } private int RefreshDealt(Color accent) { //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) int scopeIdx = (int)DamageScopeNames.ToScope(_mode); IReadOnlyList<MeterView.PlayerView> players = MeterNetwork.View.Players; int num = 0; float num2 = 0f; for (int i = 0; i < players.Count; i++) { MeterView.ScopeView scopeView = players[i].Scopes[scopeIdx]; num2 += scopeView.Total; if (scopeView.Total > 0f && scopeView.StageIndex > num) { num = scopeView.StageIndex; } } string text = "DAMAGE DEALT · " + DamageScopeNames.Display(_mode).ToUpperInvariant(); if (num > 0) { text = text + " [S" + num + "]"; } ((TMP_Text)_title).text = text; List<MeterView.PlayerView> list = new List<MeterView.PlayerView>(players.Count); for (int j = 0; j < players.Count; j++) { if (players[j].Scopes[scopeIdx].Total > 0f) { list.Add(players[j]); } } list.Sort((MeterView.PlayerView a, MeterView.PlayerView b) => b.Scopes[scopeIdx].Total.CompareTo(a.Scopes[scopeIdx].Total)); int num3 = 0; foreach (MeterView.PlayerView item in list) { if (num3 >= 34) { break; } MeterView.ScopeView scopeView2 = item.Scopes[scopeIdx]; int num4 = 0; int num5 = 0; for (int num6 = 0; num6 < scopeView2.Sources.Count; num6++) { num4 += scopeView2.Sources[num6].Hits; num5 += scopeView2.Sources[num6].Crits; } double v = ((num2 > 0f) ? ((double)(scopeView2.Total / num2) * 100.0) : 0.0); SetRow(ref _rows[num3], num3, 0, accent, PlayerName(item), Fmt.Compact(scopeView2.Total), Fmt.Percent(v, 0), Fmt.Num(num4), (num4 > 0) ? Fmt.Percent((double)num5 / (double)num4 * 100.0, 0) : "-", (num4 > 0) ? Fmt.Compact(scopeView2.Total / (float)num4) : "-"); num3++; CharacterBody body = PlayerLookup.FindBodyByNetId(item.NetId); foreach (SourceRow source in scopeView2.Sources) { if (num3 >= 34) { break; } double v2 = ((scopeView2.Total > 0f) ? ((double)(source.Damage / scopeView2.Total) * 100.0) : 0.0); SetRow(ref _rows[num3], num3, 1, Head, SourceNames.Label(source.Key, body), Fmt.Compact(source.Damage), Fmt.Percent(v2), Fmt.Num(source.Hits), (source.Hits > 0) ? Fmt.Percent(source.CritRate, 0) : "-", (source.Hits > 0) ? Fmt.Compact(source.AverageHit) : "-"); num3++; } if (num3 < 34) { SetRow(ref _rows[num3], num3, 2, Dim, "", "", "", "", "", ""); num3++; } } if (num3 == 0) { SetRow(ref _rows[num3], num3, 1, Dim, "no damage recorded yet", "", "", "", "", ""); num3++; } return num3; } private int RefreshTaken(Color accent) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList<MeterView.PlayerView> players = MeterNetwork.View.Players; MeterView.PlayerView playerView = null; for (int i = 0; i < players.Count; i++) { if (players[i].Taken.Count != 0) { if (playerView == null) { playerView = players[i]; } if (IsLocal(players[i].NetId)) { playerView = players[i]; break; } } } if (playerView == null) { ((TMP_Text)_title).text = "DAMAGE TAKEN"; SetRow(ref _rows[0], 0, 1, Dim, "nothing has hit you yet", "", "", "", "", ""); return 1; } ((TMP_Text)_title).text = "DAMAGE TAKEN · " + PlayerName(playerView).ToUpperInvariant(); List<IncomingEvent> taken = playerView.Taken; int num = Mathf.Max(0, taken.Count - 34); if (_scroll > num) { _scroll = num; } float num2 = (((Object)(object)Run.instance != (Object)null) ? Run.instance.GetRunStopwatch() : Time.time); int num3 = 0; int num4 = _scroll; while (num4 < taken.Count && num3 < 34) { IncomingEvent incomingEvent = taken[num4]; string text = SourceNames.Label(SourceKey.Pack(SourceKind.Attacker, incomingEvent.AttackerBody), null); string text2 = SourceNames.Label(incomingEvent.SourceKey, null); string c = ((text2 == text) ? text : (text + " · " + text2)); SetRow(ref _rows[num3], num3, 1, (num3 == 0 && _scroll == 0) ? accent : Head, c, Fmt.Compact(incomingEvent.Damage), "", (incomingEvent.Count > 1) ? ("×" + incomingEvent.Count) : "", incomingEvent.Crit ? "crit" : "", Ago(num2 - incomingEvent.Time)); num4++; num3++; } if (num3 == 0) { SetRow(ref _rows[0], 0, 1, Dim, "nothing has hit you yet", "", "", "", "", ""); num3 = 1; } return num3; } private static bool IsLocal(uint netId) { NetworkUser val = PlayerLookup.FindNetworkUser(netId); if ((Object)(object)val != (Object)null) { return ((NetworkBehaviour)val).isLocalPlayer; } return false; } private static string PlayerName(MeterView.PlayerView pv) { NetworkUser val = PlayerLookup.FindNetworkUser(pv.NetId); string text = (((Object)(object)val != (Object)null && !string.IsNullOrEmpty(val.userName)) ? val.userName : pv.Name); if (!string.IsNullOrEmpty(text)) { return text; } return "Player"; } private static string Ago(float seconds) { if (seconds < 0f) { seconds = 0f; } if (seconds < 60f) { return Mathf.FloorToInt(seconds) + "s"; } int num = Mathf.FloorToInt(seconds / 60f); return num + "m" + Mathf.FloorToInt(seconds - (float)num * 60f).ToString("00") + "s"; } private void SetRow(ref Row row, int index, int style, Color color, string c0, string c1, string c2, string c3, string c4, string c5) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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) if (!((Component)row.Root).gameObject.activeSelf) { ((Component)row.Root).gameObject.SetActive(true); } row.Root.anchoredPosition = new Vector2(0f, 0f - (88f + (float)index * 24f)); if (row.CacheStyle != style) { row.CacheStyle = style; bool num = style == 1; float fontSize = (num ? 14f : 16f); float num2 = (num ? 22f : 0f); for (int i = 0; i < 6; i++) { ((TMP_Text)row.Cells[i]).fontSize = fontSize; PlaceCell(((TMP_Text)row.Cells[i]).rectTransform, i, 0f, 24f, (i == 0) ? num2 : 0f); } } string[] array = new string[6] { c0, c1, c2, c3, c4, c5 }; for (int j = 0; j < 6; j++) { Color val = ((j == 0) ? color : ((style == 1) ? Head : color)); if (((Graphic)row.Cells[j]).color != val) { ((Graphic)row.Cells[j]).color = val; } if (((TMP_Text)row.Cells[j]).text != array[j]) { ((TMP_Text)row.Cells[j]).text = array[j]; } } } } public sealed class DpsPanel : MonoBehaviour { private struct Row { public RectTransform Root; public HGTextMeshProUGUI Left; public HGTextMeshProUGUI C1; public HGTextMeshProUGUI C2; public HGTextMeshProUGUI C3; public string CacheL; public string Cache1; public string Cache2; public string Cache3; public int CacheStyle; public Color CacheNameColor; public Color Cache1Color; public Color Cache2Color; public Color Cache3Color; } private const float RefreshInterval = 0.2f; private const int MaxRows = 40; private const float RowHeight = 22f; private const float HeaderHeight = 30f; private const float LabelRowHeight = 15f; private const float TopHeight = 45f; private const float FooterHeight = 18f; private const float Pad = 10f; private static Color AccentColor = ModePalette.Accent(ViewMode.Mobs); private static readonly Color[] TierColors = (Color[])(object)new Color[7] { new Color(0.9f, 0.92f, 0.95f), new Color(0.48f, 0.88f, 0.52f), new Color(0.42f, 0.72f, 1f), new Color(0.76f, 0.56f, 1f), new Color(1f, 0.48f, 0.8f), new Color(1f, 0.48f, 0.8f), new Color(1f, 0.48f, 0.8f) }; private static readonly Color NameColor = new Color(0.96f, 0.96f, 0.96f); private static readonly Color DetailColor = new Color(0.66f, 0.71f, 0.78f); private static readonly Color HintColor = new Color(0.45f, 0.5f, 0.58f); private bool _visible; private bool _expanded; private ViewMode _mode; private float _nextRefresh; private readonly List<MeterView.PlayerView> _sorted = new List<MeterView.PlayerView>(8); private int _sortScope; private IComparer<MeterView.PlayerView> _byScopeTotal; private int _lastStageId = int.MinValue; private int _lastClearCount = int.MinValue; private bool _switchedForEncounter; private int _styledScope = -1; private Canvas _canvas; private RectTransform _panel; private Image _bg; private Image _accentBar; private HGTextMeshProUGUI _header; private HGTextMeshProUGUI _hint; private HGTextMeshProUGUI _totalLabel; private HGTextMeshProUGUI _lab1; private HGTextMeshProUGUI _lab2; private HGTextMeshProUGUI _lab3; private Row[] _rows; private int _activeRows; private int CompareByScopeTotal(MeterView.PlayerView a, MeterView.PlayerView b) { int num = b.Scopes[_sortScope].Total.CompareTo(a.Scopes[_sortScope].Total); if (num == 0) { return a.NetId.CompareTo(b.NetId); } return num; } private void Awake() { _visible = PluginConfig.VisibleByDefault.Value; Build(); ApplyVisibility(); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(PluginConfig.ToggleKey.Value)) { _visible = !_visible; ApplyVisibility(); } if (Input.GetKeyDown(PluginConfig.ScopeKey.Value)) { _mode = DamageScopeNames.Next(_mode); } if (Input.GetKeyDown(PluginConfig.DetailKey.Value)) { _expanded = !_expanded; } bool flag = ShouldShow(); if ((Object)(object)_canvas != (Object)null && ((Behaviour)_canvas).enabled != flag) { ((Behaviour)_canvas).enabled = flag; } if (flag && !(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + 0.2f; Refresh(); } } private bool ShouldShow() { if (!_visible || (Object)(object)Run.instance == (Object)null) { return false; } if (DetailScreen.IsOpen) { return false; } if (PluginConfig.HideWithHud.Value && !HudVisibility.IsVisible()) { return false; } return true; } private void ApplyVisibility() { if ((Object)(object)_canvas != (Object)null) { ((Behaviour)_canvas).enabled = ShouldShow(); } } private void Build() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DpsMeterCanvas"); val.transform.SetParent(((Component)this).transform, false); _canvas = val.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 50; CanvasScaler obj = val.AddComponent<CanvasScaler>(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); obj.matchWidthOrHeight = 1f; float value = PluginConfig.PanelWidth.Value; float value2 = PluginConfig.PanelMargin.Value; bool value3 = PluginConfig.AnchorRight.Value; GameObject val2 = new GameObject("Panel", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(val.transform, false); _panel = (RectTransform)val2.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(value3 ? 1f : 0f, 1f); Vector2 val4 = (_panel.anchorMin = (_panel.anchorMax = val3)); _panel.pivot = val3; _panel.anchoredPosition = new Vector2(value3 ? (0f - value2) : value2, 0f - value2); _panel.sizeDelta = new Vector2(value, 30f); _bg = val2.AddComponent<Image>(); ((Graphic)_bg).color = ModePalette.Background(ViewMode.Mobs); ((Graphic)_bg).raycastTarget = false; GameObject val7 = new GameObject("AccentBar", new Type[1] { typeof(RectTransform) }); val7.transform.SetParent((Transform)(object)_panel, false); RectTransform val8 = (RectTransform)val7.transform; val8.anchorMin = new Vector2(0f, 0f); val8.anchorMax = new Vector2(0f, 1f); val8.pivot = new Vector2(0f, 0.5f); val8.offsetMin = new Vector2(0f, 0f); val8.offsetMax = new Vector2(4f, 0f); _accentBar = val7.AddComponent<Image>(); ((Graphic)_accentBar).color = ModePalette.Accent(ViewMode.Mobs); ((Graphic)_accentBar).raycastTarget = false; _header = MakeText((Transform)(object)_panel, "Header", 19f, AccentColor, (TextAlignmentOptions)4097); SetRect(((TMP_Text)_header).rectTransform, 10f, -4f, value - 20f, 30f); _hint = MakeText((Transform)(object)_panel, "Hint", 12f, HintColor, (TextAlignmentOptions)4100); RectTransform rectTransform = ((TMP_Text)_hint).rectTransform; ((Vector2)(ref val4))..ctor(1f, 0f); rectTransform.anchorMax = val4; rectTransform.anchorMin = val4; rectTransform.pivot = new Vector2(1f, 0f); rectTransform.anchoredPosition = new Vector2(-10f, 2f); rectTransform.sizeDelta = new Vector2(value - 20f, 18f); _totalLabel = MakeText((Transform)(object)_panel, "Total", 12f, HintColor, (TextAlignmentOptions)4097); SetRect(((TMP_Text)_totalLabel).rectTransform, 14f, -30f, value * 0.4f, 15f); _lab1 = MakeText((Transform)(object)_panel, "Lab1", 11f, HintColor, (TextAlignmentOptions)4100); _lab2 = MakeText((Transform)(object)_panel, "Lab2", 11f, HintColor, (TextAlignmentOptions)4100); _lab3 = MakeText((Transform)(object)_panel, "Lab3", 11f, HintColor, (TextAlignmentOptions)4100); ((TMP_Text)_lab1).text = "CUR"; ((TMP_Text)_lab2).text = "PEAK"; ((TMP_Text)_lab3).text = "AVG"; LayoutColumns(((TMP_Text)_lab1).rectTransform, ((TMP_Text)_lab2).rectTransform, ((TMP_Text)_lab3).rectTransform, value, -30f, 15f); _rows = new Row[40]; for (int i = 0; i < 40; i++) { _rows[i] = MakeRow(i); } } private Row MakeRow(int index) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0047: Expected O, but got Unknown //IL_005a: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Row" + index, new Type[1] { typeof(RectTransform) }); val.transform.SetParent((Transform)(object)_panel, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0f, 1f); val2.sizeDelta = new Vector2(PluginConfig.PanelWidth.Value, 22f); val.SetActive(false); return new Row { Root = val2, Left = MakeText((Transform)(object)val2, "L", 16f, NameColor, (TextAlignmentOptions)4097), C1 = MakeText((Transform)(object)val2, "C1", 16f, NameColor, (TextAlignmentOptions)4100), C2 = MakeText((Transform)(object)val2, "C2", 16f, NameColor, (TextAlignmentOptions)4100), C3 = MakeText((Transform)(object)val2, "C3", 16f, AccentColor, (TextAlignmentOptions)4100), CacheStyle = -1 }; } private static HGTextMeshProUGUI MakeText(Transform parent, string name, float size, Color color, TextAlignmentOptions align) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); HGTextMeshProUGUI val2 = val.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)val2).fontSize = size; ((Graphic)val2).color = color; ((TMP_Text)val2).alignment = align; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)1; ((Graphic)val2).raycastTarget = false; if ((Object)(object)HGTextMeshProUGUI.defaultLanguageFont != (Object)null) { ((TMP_Text)val2).font = HGTextMeshProUGUI.defaultLanguageFont; } return val2; } private static void LayoutColumns(RectTransform c1, RectTransform c2, RectTransform c3, float width, float y, float h) { float num = (width - 20f) * 0.2f; float num2 = width - 10f; SetRect(c3, num2 - num, y, num, h); SetRect(c2, num2 - num * 2f - 4f, y, num, h); SetRect(c1, num2 - num * 3f - 8f, y, num, h); } private static float NameColumnWidth(float width, float indent) { float num = (width - 20f) * 0.2f; return Mathf.Max(40f, width - num * 3f - 12f - indent - 10f); } private static void SetRect(RectTransform rt, float x, float y, float w, float h) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); rt.anchorMax = val; rt.anchorMin = val; rt.pivot = new Vector2(0f, 1f); rt.anchoredPosition = new Vector2(x, y); rt.sizeDelta = new Vector2(w, h); } private void Refresh() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_062f: Unknown result type (might be due to invalid IL or missing references) //IL_05a2: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Unknown result type (might be due to invalid IL or missing references) //IL_05bd: Unknown result type (might be due to invalid IL or missing references) //IL_05c2: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) float value = PluginConfig.PanelWidth.Value; Run.instance.GetRunStopwatch(); UpdateAutoScope(); ApplyScopeStyle(); IReadOnlyList<MeterView.PlayerView> players = MeterNetwork.View.Players; if (_mode == ViewMode.Taken) { int num = RefreshTaken(value); for (int i = num; i < _activeRows; i++) { ((Component)_rows[i].Root).gameObject.SetActive(false); } _activeRows = num; _panel.sizeDelta = new Vector2(value, 45f + (float)num * 22f + 18f + 4f); UpdateVerticalPosition(); return; } int num2 = (int)DamageScopeNames.ToScope(_mode); float num3 = 0f; float num4 = 0f; for (int j = 0; j < players.Count; j++) { num3 += players[j].Scopes[num2].Total; if (players[j].Scopes[num2].Duration > num4) { num4 = players[j].Scopes[num2].Duration; } } int num5 = 0; for (int k = 0; k < players.Count; k++) { MeterView.ScopeView scopeView = players[k].Scopes[num2]; if (scopeView.Total > 0f && scopeView.StageIndex > num5) { num5 = scopeView.StageIndex; } } string text = "DPS · " + DamageScopeNames.Display(_mode).ToUpperInvariant(); if (num5 > 0) { text = text + " [S" + num5 + "]"; } if (_mode == ViewMode.Boss && num4 > 0f) { text = text + " " + FormatClock(num4); } ((TMP_Text)_header).text = text; ((TMP_Text)_hint).text = (_expanded ? "F6 collapse" : "F6 expand") + " · F7 view · F8 hide · " + ((object)PluginConfig.ScreenKey.Value/*cast due to .constrained prefix*/).ToString() + " detail"; if (num3 > 0f) { ((TMP_Text)_totalLabel).text = "Σ " + CompactTinted(num3, detail: false, out var color); ((Graphic)_totalLabel).color = color; } else { ((TMP_Text)_totalLabel).text = ""; } ((TMP_Text)_lab1).text = "CUR"; ((TMP_Text)_lab2).text = "PEAK"; ((TMP_Text)_lab3).text = "AVG"; int num6 = 0; _sorted.Clear(); for (int l = 0; l < players.Count; l++) { if (players[l].Scopes[num2].Total > 0f) { _sorted.Add(players[l]); } } _sortScope = num2; if (_byScopeTotal == null) { _byScopeTotal = Comparer<MeterView.PlayerView>.Create(CompareByScopeTotal); } _sorted.Sort(_byScopeTotal); foreach (MeterView.PlayerView item in _sorted) { if (num6 >= 40) { break; } MeterView.ScopeView scopeView2 = item.Scopes[num2]; NetworkUser val = PlayerLookup.FindNetworkUser(item.NetId); string text2 = (((Object)(object)val != (Object)null && !string.IsNullOrEmpty(val.userName)) ? val.userName : item.Name); if (string.IsNullOrEmpty(text2)) { text2 = "Player"; } if (num3 > 0f && players.Count > 1) { text2 = text2 + " " + Fmt.Percent((double)(scopeView2.Total / num3) * 100.0, 0); } Color color2; string c = CompactTinted(scopeView2.Dps, detail: false, out color2); Color color3; string c2 = CompactTinted(scopeView2.PeakDps, detail: false, out color3); Color color4; string c3 = CompactTinted(scopeView2.AvgDps, detail: false, out color4); SetRow(ref _rows[num6], num6, 0, value, PlayerColor(item.NetId), text2, c, c2, c3, color2, color3, color4); num6++; if (!_expanded) { continue; } CharacterBody body = PlayerLookup.FindBodyByNetId(item.NetId); int num7 = 0; foreach (SourceRow source in scopeView2.Sources) { if (num6 >= 40 || num7 >= PluginConfig.MaxDetailRows.Value) { break; } double v = ((scopeView2.Total > 0f) ? ((double)(source.Damage / scopeView2.Total) * 100.0) : 0.0); Color color5; string c4 = CompactTinted(source.Damage, detail: true, out color5); SetRow(ref _rows[num6], num6, 1, value, DetailColor, SourceNames.Label(source.Key, body), "", Fmt.Percent(v), c4, DetailColor, DetailColor, color5); num6++; num7++; } } if (num6 == 0) { string left = (MeterNetwork.VersionMismatch ? "host has a different mod version" : ((MeterNetwork.IsRemote && !MeterNetwork.HasRemoteData) ? "waiting for host (needs the mod)" : "no damage recorded yet")); SetRow(ref _rows[num6], num6, 1, value, DetailColor, left, "", "", "", DetailColor, DetailColor, DetailColor); num6++; } for (int m = num6; m < _activeRows; m++) { ((Component)_rows[m].Root).gameObject.SetActive(false); } _activeRows = num6; _panel.sizeDelta = new Vector2(value, 45f + (float)num6 * 22f + 18f + 4f); UpdateVerticalPosition(); } private void UpdateAutoScope() { if (!PluginConfig.AutoScope.Value) { return; } int num = (((Object)(object)Stage.instance != (Object)null) ? ((Object)Stage.instance).GetInstanceID() : 0); int num2 = (((Object)(object)Run.instance != (Object)null) ? Run.instance.stageClearCount : (-1)); if (num != _lastStageId || num2 != _lastClearCount) { _lastStageId = num; _lastClearCount = num2; _mode = ViewMode.Mobs; _switchedForEncounter = false; ManualLogSource log = DpsMeterPlugin.Log; if (log != null) { log.LogDebug((object)"auto-scope: new stage, showing Mobs"); } } else { if (_mode == ViewMode.Taken) { return; } bool flag = IsBossEncounterActive(); if (flag && !_switchedForEncounter) { _mode = ViewMode.Boss; _switchedForEncounter = true; ManualLogSource log2 = DpsMeterPlugin.Log; if (log2 != null) { log2.LogDebug((object)("auto-scope: boss encounter, showing Boss " + $"(hostFlag={MeterNetwork.View.BossEncounterActive}, " + $"charging={TeleporterCharging()})")); } } else if (!flag && _switchedForEncounter) { _switchedForEncounter = false; ManualLogSource log3 = DpsMeterPlugin.Log; if (log3 != null) { log3.LogDebug((object)"auto-scope: boss encounter ended"); } } } } private static bool IsBossEncounterActive() { if (!MeterNetwork.View.BossEncounterActive) { return TeleporterCharging(); } return true; } private static bool TeleporterCharging() { TeleporterInteraction instance = TeleporterInteraction.instance; if ((Object)(object)instance != (Object)null) { return instance.isCharging; } return false; } private void ApplyScopeStyle() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0057: Unknown result type (might be due to invalid IL or missing references) if (_styledScope != (int)_mode) { _styledScope = (int)_mode; AccentColor = ModePalette.Accent(_mode); ((Graphic)_header).color = AccentColor; ((Graphic)_accentBar).color = AccentColor; ((Graphic)_bg).color = ModePalette.Background(_mode); for (int i = 0; i < _rows.Length; i++) { _rows[i].CacheStyle = -1; } } } private void UpdateVerticalPosition() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) float value = PluginConfig.PanelMargin.Value; float num = value; if (PluginConfig.AvoidHudElements.Value) { num = HudLayout.TopOffset(HudVisibility.Current, _canvas, value, 8f); } bool value2 = PluginConfig.AnchorRight.Value; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(value2 ? (0f - value) : value, 0f - num); if (_panel.anchoredPosition != val) { _panel.anchoredPosition = val; } } private int RefreshTaken(float width) { //IL_0020: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)_header).text = "DPS · TAKEN"; ((TMP_Text)_hint).text = "F7 view · F8 hide · " + ((object)PluginConfig.ScreenKey.Value/*cast due to .constrained prefix*/).ToString() + " detail"; ((TMP_Text)_totalLabel).text = ""; ((TMP_Text)_lab1).text = ""; ((TMP_Text)_lab2).text = ""; ((TMP_Text)_lab3).text = ""; IReadOnlyList<MeterView.PlayerView> players = MeterNetwork.View.Players; List<IncomingEvent> list = null; for (int i = 0; i < players.Count; i++) { if (players[i].Taken.Count != 0) { if (list == null) { list = players[i].Taken; } NetworkUser val = PlayerLookup.FindNetworkUser(players[i].NetId); if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).isLocalPlayer) { list = players[i].Taken; break; } } } if (list == null || list.Count == 0) { SetRow(ref _rows[0], 0, 1, width, DetailColor, "nothing has hit you yet", "", "", "", DetailColor, DetailColor, DetailColor); return 1; } int num = Mathf.Min(PluginConfig.MaxDetailRows.Value + 2, 40); int num2 = 0; int num3 = 0; while (num3 < list.Count && num2 < num) { IncomingEvent incomingEvent = list[num3]; string text = SourceNames.Label(SourceKey.Pack(SourceKind.Attacker, incomingEvent.AttackerBody), null); string text2 = SourceNames.Label(incomingEvent.SourceKey, null); string left = ((text2 == text) ? text : (text + " · " + text2)); Color color; string c = CompactTinted(incomingEvent.Damage, num2 != 0, out color); SetRow(ref _rows[num2], num2, (num2 != 0) ? 1 : 0, width, (num2 == 0) ? NameColor : DetailColor, left, "", (incomingEvent.Count > 1) ? ("×" + incomingEvent.Count) : "", c, DetailColor, DetailColor, color); num3++; num2++; } return num2; } private void SetRow(ref Row row, int index, int style, float width, Color nameColor, string left, string c1, string c2, string c3, Color col1, Color col2, Color col3) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if (!((Component)row.Root).gameObject.activeSelf) { ((Component)row.Root).gameObject.SetActive(true); } row.Root.anchoredPosition = new Vector2(0f, 0f - (45f + (float)index * 22f)); if (row.CacheStyle != style) { row.CacheStyle = style; bool num = style == 1; float fontSize = (num ? 14f : 16f); float num2 = (num ? 24f : 10f); ((TMP_Text)row.C1).fontSize = fontSize; ((TMP_Text)row.C2).fontSize = fontSize; ((TMP_Text)row.C3).fontSize = fontSize; ((TMP_Text)row.Left).fontSize = fontSize; SetRect(((TMP_Text)row.Left).rectTransform, num2, 0f, NameColumnWidth(width, num2), 22f); LayoutColumns(((TMP_Text)row.C1).rectTransform, ((TMP_Text)row.C2).rectTransform, ((TMP_Text)row.C3).rectTransform, width, 0f, 22f); Color val = default(Color); ((Color)(ref val))..ctor(-1f, -1f, -1f, -1f); row.CacheNameColor = val; row.Cache1Color = val; row.Cache2Color = val; row.Cache3Color = val; } if (row.CacheNameColor != nameColor) { row.CacheNameColor = nameColor; ((Graphic)row.Left).color = nameColor; } if (row.Cache1Color != col1) { row.Cache1Color = col1; ((Graphic)row.C1).color = col1; } if (row.Cache2Color != col2) { row.Cache2Color = col2; ((Graphic)row.C2).color = col2; } if (row.Cache3Color != col3) { row.Cache3Color = col3; ((Graphic)row.C3).color = col3; } if (row.CacheL != left) { row.CacheL = left; ((TMP_Text)row.Left).text = left; } if (row.Cache1 != c1) { row.Cache1 = c1; ((TMP_Text)row.C1).text = c1; } if (row.Cache2 != c2) { row.Cache2 = c2; ((TMP_Text)row.C2).text = c2; } if (row.Cache3 != c3) { row.Cache3 = c3; ((TMP_Text)row.C3).text = c3; } } private static Color PlayerColor(uint netId) { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) CharacterBody val = PlayerLookup.FindBodyByNetId(netId); if ((Object)(object)val == (Object)null) { return NameColor; } Color val2 = val.bodyColor; float num = 0.2126f * val2.r + 0.7152f * val2.g + 0.0722f * val2.b; if (num < 0.45f) { val2 = Color.Lerp(val2, Color.white, (0.45f - num) / 0.45f * 0.8f); } val2.a = 1f; return val2; } private static Color MagnitudeColor(int tier, bool detail) { //IL_0015: 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) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!PluginConfig.ColorByMagnitude.Value) { if (!detail) { return NameColor; } return DetailColor; } if (tier < 0) { tier = 0; } if (tier >= TierColors.Length) { tier = TierColors.Length - 1; } Color val = TierColors[tier]; if (!detail) { return val; } return Color.Lerp(val, DetailColor, 0.45f); } private static string CompactTinted(double v, bool detail, out Color color) { //IL_000b: 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) int tier; string result = Fmt.Compact(v, out tier); color = MagnitudeColor(tier, detail); return result; } private static string FormatClock(float seconds) { if (seconds < 0f) { seconds = 0f; } int num = Mathf.FloorToInt(seconds); return num / 60 + ":" + (num % 60).ToString("00"); } private void OnDestroy() { if ((Object)(object)_canvas != (Object)null) { Object.Destroy((Object)(object)((Component)_canvas).gameObject); } } } internal static class HudLayout { private static ObjectivePanelController _objectives; private static RunTimerUIController _timer; private const float MaxOffsetFraction = 0.4f; public static float TopOffset(HUD hud, Canvas canvas, float fallback, float gap) { if ((Object)(object)hud == (Object)null || (Object)(object)canvas == (Object)null) { return fallback; } Resolve(hud); float num = float.MaxValue; bool flag = false; if (Measure((RectTransform)(((Object)(object)_objectives != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), out var bottomScreenY)) { num = Mathf.Min(num, bottomScreenY); flag = true; } if (Measure((RectTransform)(((Object)(object)_timer != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null), out var bottomScreenY2)) { num = Mathf.Min(num, bottomScreenY2); flag = true; } if (!flag) { return fallback; } float scaleFactor = canvas.scaleFactor; if (scaleFactor <= 0f) { return fallback; } float num2 = ((float)Screen.height - num) / scaleFactor + gap; float num3 = (float)Screen.height * 0.4f / scaleFactor; if (float.IsNaN(num2) || num2 < fallback) { return fallback; } return Mathf.Min(num2, num3); } private static bool Measure(RectTransform rt, out float bottomScreenY) { bottomScreenY = 0f; if ((Object)(object)rt == (Object)null || !((Component)rt).gameObject.activeInHierarchy) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[4]; rt.GetWorldCorners(array); bottomScreenY = array[0].y; if (bottomScreenY > 0f) { return bottomScreenY <= (float)Screen.height; } return false; } private static void Resolve(HUD hud) { if ((Object)(object)_objectives == (Object)null) { _objectives = ((Component)hud).GetComponentInChildren<ObjectivePanelController>(true); } if ((Object)(object)_timer == (Object)null) { _timer = ((Component)hud).GetComponentInChildren<RunTimerUIController>(true); } } } internal static class HudVisibility { private static HUD _cached; public static HUD Current => Resolve(); public static bool IsVisible() { HUD val = Resolve(); if ((Object)(object)val == (Object)null) { return false; } if (!((Behaviour)val).isActiveAndEnabled) { return false; } Canvas mainContainerCanvas = val.mainContainerCanvas; if ((Object)(object)mainContainerCanvas != (Object)null && !((Behaviour)mainContainerCanvas).enabled) { return false; } GameObject mainContainer = val.mainContainer; if ((Object)(object)mainContainer != (Object)null && !mainContainer.activeInHierarchy) { return false; } return true; } private static HUD Resolve() { if ((Object)(object)_cached != (Object)null) { return _cached; } ReadOnlyCollection<HUD> readOnlyInstanceList = HUD.readOnlyInstanceList; if (readOnlyInstanceList == null) { return null; } for (int i = 0; i < readOnlyInstanceList.Count; i++) { HUD val = readOnlyInstanceList[i]; if (!((Object)(object)val == (Object)null) && val.localUserViewer != null) { _cached = val; return val; } } return null; } } internal static class ModePalette { private static readonly Color MobsAccent = new Color(0.42f, 0.72f, 1f); private static readonly Color BossAccent = new Color(1f, 0.42f, 0.38f); private static readonly Color TakenAccent = new Color(1f, 0.78f, 0.32f); private static readonly Color MobsBg = new Color(0.04f, 0.05f, 0.07f, 0.85f); private static readonly Color BossBg = new Color(0.1f, 0.04f, 0.05f, 0.88f); private static readonly Color TakenBg = new Color(0.09f, 0.07f, 0.03f, 0.88f); public static Color Accent(ViewMode m) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return (Color)(m switch { ViewMode.Boss => BossAccent, ViewMode.Mobs => MobsAccent, _ => TakenAccent, }); } public static Color Background(ViewMode m) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return (Color)(m switch { ViewMode.Boss => BossBg, ViewMode.Mobs => MobsBg, _ => TakenBg, }); } public static Color ScreenBackground(ViewMode m) { //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_0013: Unknown result type (might be due to invalid IL or missing references) Color result = Background(m); result.a = 0.97f; return result; } } } namespace DpsMeter.Tracking { public enum DamageScope { Mobs, TeleporterBoss } public enum ViewMode { Mobs, Boss, Taken } public static class DamageScopeNames { public static string Display(DamageScope s) { if (s != DamageScope.Mobs) { return "Boss"; } return "Mobs"; } public static string Display(ViewMode m) { return m switch { ViewMode.Boss => "Boss", ViewMode.Mobs => "Mobs", _ => "Taken", }; } public static ViewMode Next(ViewMode m) { return (ViewMode)((int)(m + 1) % 3); } public static DamageScope ToScope(ViewMode m) { if (m != ViewMode.Boss) { return DamageScope.Mobs; } return DamageScope.TeleporterBoss; } } public struct SourceAgg { public double Damage; public int Hits; public int Crits; public double AverageHit { get { if (Hits <= 0) { return 0.0; } return Damage / (double)Hits; } } public double CritRate { get { if (Hits <= 0) { return 0.0; } return (double)Crits / (double)Hits * 100.0; } } } public sealed class ScopeStats { public double Total; public double Peak; public int StageIndex; public Stage Scene; public float FirstHitTime = -1f; public float LastHitTime; public readonly Dictionary<int, SourceAgg> BySource = new Dictionary<int, SourceAgg>(32); public readonly RollingWindow Window = new RollingWindow(WindowSeconds); public static float WindowSeconds = 5f; public double ActiveDuration { get { if (!(FirstHitTime < 0f)) { return LastHitTime - FirstHitTime; } return 0.0; } } public double AverageDps { get { if (FirstHitTime < 0f) { return 0.0; } double num = LastHitTime - FirstHitTime; if (!(num > 0.25)) { return 0.0; } return Total / num; } } public void Add(int key, float amount, float now, int stage, bool crit) { if (FirstHitTime < 0f) { StageIndex = stage; Scene = Stage.instance; } Total += amount; BySource.TryGetValue(key, out var value); value.Damage += amount; value.Hits++; if (crit) { value.Crits++; } BySource[key] = value; Window.Add(now, amount); if (FirstHitTime < 0f) { FirstHitTime = now; } LastHitTime = now; } public void SamplePeak(float now) { double num = Window.PerSecond(now); if (num > Peak) { Peak = num; } } public void Reset() { Total = 0.0; Peak = 0.0; StageIndex = 0; Scene = null; FirstHitTime = -1f; LastHitTime = 0f; BySource.Clear(); Window.Reset(); } } public sealed class PlayerStats { public string DisplayName; public uint NetId; public readonly ScopeStats[] Scopes = new ScopeStats[2] { new ScopeStats(), new ScopeStats() }; public ScopeStats this[DamageScope s] => Scopes[(int)s]; public void ResetAll() { ScopeStats[] scopes = Scopes; for (int i = 0; i < scopes.Length; i++) { scopes[i].Reset(); } } } public sealed class DamageTracker { private readonly Dictionary<int, PlayerStats> _players = new Dictionary<int, PlayerStats>(8); private readonly Dictionary<int, IncomingLog> _taken = new Dictionary<int, IncomingLog>(8); public readonly Dictionary<string, double> UnresolvedByInflictor = new Dictionary<string, double>(16); private readonly List<BossGroup> _activeBossGroups = new List<BossGroup>(4); private static readonly Predicate<BossGroup> IsGone = (BossGroup g) => (Object)(object)g == (Object)null; private readonly Dictionary<(int inflictor, int colorCrit, ulong type, ulong ext, int src, float proc, uint mask), string> _labels = new Dictionary<(int, int, ulong, ulong, int, float, uint), string>(16); public IReadOnlyDictionary<int, PlayerStats> Players => _players; public IReadOnlyDictionary<int, IncomingLog> Taken => _taken; public double TrackedTotal { get; private set; } public double UnattributedTotal { get; private set; } public bool HasActiveBossGroups { get { _activeBossGroups.RemoveAll(IsGone); return _activeBossGroups.Count > 0; } } public void RegisterBossGroup(BossGroup group) { if (!((Object)(object)group == (Object)null) && !_activeBossGroups.Contains(group)) { _activeBossGroups.Add(group); } } public void UnregisterBossGroup(BossGroup group) { if ((Object)(object)group != (Object)null) { _activeBossGroups.Remove(group); } } public bool IsEncounterContinuation() { if (HasActiveBossGroups) { return true; } Stage instance = Stage.instance; if ((Object)(object)instance == (Object)null) { return false; } foreach (KeyValuePair<int, PlayerStats> player in _players) { ScopeStats scopeStats = player.Value[DamageScope.TeleporterBoss]; if (scopeStats.Total > 0.0 && (Object)(object)scopeStats.Scene == (Object)(object)instance) { return true; } } return false; } public void Record(DamageReport report) { if (report != null) { RecordDealt(report); RecordTaken(report); } } private void RecordTaken(DamageReport report) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected I4, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected I4, but got Unknown CharacterMaster victimMaster = report.victimMaster; if ((Object)(object)victimMaster == (Object)null || (Object)(object)victimMaster.playerCharacterMasterController == (Object)null || report.victimTeamIndex == report.attackerTeamIndex) { return; } float damageDealt = report.damageDealt; if (damageDealt <= 0f) { return; } DamageInfo damageInfo = report.damageInfo; int num = (int)report.attackerBodyIndex; int sourceKey; if ((int)report.dotType != -1 && (int)report.dotType >= 0) { sourceKey = SourceKey.Pack(SourceKind.Dot, (int)report.dotType); } else { int num2 = -1; if (damageInfo != null && (Object)(object)damageInfo.inflictor != (Object)null) { ProjectileController component = damageInfo.inflictor.GetComponent<ProjectileController>(); if ((Object)(object)component != (Object)null) { num2 = component.catalogIndex; } } sourceKey = ((num2 >= 0) ? SourceKey.Pack(SourceKind.Projectile, num2) : SourceKey.Pack(SourceKind.Attacker, num)); } int instanceID = ((Object)victimMaster).GetInstanceID(); if (!_taken.TryGetValue(instanceID, out var value)) { value = new IncomingLog(); _taken[instanceID] = value; } value.Add(num, sourceKey, damageDealt, Now(), damageInfo?.crit ?? false); } private void RecordDealt(DamageReport report) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected I4, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected I4, but got Unknown CharacterMaster val = report.attackerOwnerMaster ?? report.attackerMaster; PlayerCharacterMasterController val2 = (((Object)(object)val != (Object)null) ? val.playerCharacterMasterController : null); float damageDealt = report.damageDealt; if (damageDealt <= 0f) { return; } int key; if ((Object)(object)val2 == (Object)null) { val = BranderOf(report); val2 = (((Object)(object)val != (Object)null) ? val.playerCharacterMasterController : null); if ((Object)(object)val2 == (Object)null) { return; } key = SourceKey.Pack(SourceKind.Item, (int)Items.CausticPheromones.itemIndex); } else { if (report.victimTeamIndex == report.attackerTeamIndex) { return; } key = SourceResolver.Resolve(report); if ((Object)(object)report.attackerOwnerMaster != (Object)null && (Object)(object)report.attackerOwnerMaster != (Object)(object)report.attackerMaster) { key = SourceKey.Pack(SourceKind.Minion, (int)report.attackerBodyIndex); } } DamageScope s = ClassifyScope(report); float now = Now(); GetOrCreateIn(_players, val, val2)[s].Add(key, damageDealt, now, CurrentStage(), report.damageInfo != null && report.damageInfo.crit); TrackedTotal += damageDealt; SourceKind sourceKind = SourceKey.KindOf(key); if (sourceKind == SourceKind.Unattributed || sourceKind == SourceKind.GenericItem) { UnattributedTotal += damageDealt; RecordUnresolved(report, damageDealt); } } private static CharacterMaster BranderOf(DamageReport report) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) CharacterBody victimBody = report.victimBody; if ((Object)(object)victimBody == (Object)null || (Object)(object)report.attackerMaster == (Object)(object)report.victimMaster) { return null; } if (!victimBody.HasBuff(Buffs.MalignantAttractionActive)) { return null; } MalignantAttractionMarker component = ((Component)victimBody).GetComponent<MalignantAttractionMarker>(); if ((Object)(object)component == (Object)null || component.attackerTeamIndex == report.attackerTeamIndex) { return null; } return component.attackerMaster; } private static string Origin() { StackFrame[] frames = new StackTrace(2, fNeedFileInfo: false).GetFrames(); if (frames == null) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(64); int num = 0; StackFrame[] array = frames; foreach (StackFrame stackFrame in array) { Type type = stackFrame.GetMethod()?.DeclaringType; if (!(type == null) && !IsDamagePlumbing(type)) { stringBuilder.Append((num == 0) ? " via " : " < ").Append(type.Name).Append('.') .Append(stackFrame.GetMethod().Name); if (++num == 2) { break; } } } return stringBuilder.ToString(); } private static bool IsDamagePlumbing(Type t) { string text = t.Namespace ?? string.Empty; if (!text.StartsWith("DpsMeter", StringComparison.Ordinal) && !text.StartsWith("MonoMod", StringComparison.Ordinal) && !text.StartsWith("System", StringComparison.Ordinal) && !(t == typeof(HealthComponent)) && !(t == typeof(GlobalEventManager)) && !(t == typeof(BlastAttack)) && !(t == typeof(OverlapAttack))) { return t == typeof(BulletAttack); } return true; } private void RecordUnresolved(DamageReport report, float amount) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected I4, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_006c: Expected I4, but got Unknown //IL_006c: Expected I4, but got Unknown DamageInfo damageInfo = report.damageInfo; if (damageInfo != null) { GameObject inflictor = damageInfo.inflictor; (int, int, ulong, ulong, int, float, uint) key = (((Object)(object)inflictor != (Object)null) ? (((Object)inflictor).GetInstanceID(), (int)damageInfo.damageColorIndex, 0uL, 0uL, 0, 0f, 0u) : (0, damageInfo.damageColorIndex | (damageInfo.crit ? 65536 : 0), (ulong)damageInfo.damageType.damageType, (ulong)damageInfo.damageType.damageTypeExtended, (int)damageInfo.damageType.damageSource, damageInfo.procCoefficient, damageInfo.procChainMask.mask)); if (!_labels.TryGetValue(key, out var value)) { value = BuildUnresolvedLabel(damageInfo) + Origin(); _labels[key] = value; } UnresolvedByInflictor.TryGetValue(value, out var value2); UnresolvedByInflictor[value] = value2 + (double)amount; } } private static string BuildUnresolvedLabel(DamageInfo di) { GameObject inflictor = di.inflictor; if ((Object)(object)inflictor == (Object)null) { return "<null> [" + ((object)Unsafe.As<DamageColorIndex, DamageColorIndex>(ref di.damageColorIndex)/*cast due to .constrained prefix*/).ToString() + "]" + " dt=" + ((object)Unsafe.As<DamageType, DamageType>(ref di.damageType.damageType)/*cast due to .constrained prefix*/).ToString() + " src=" + ((object)Unsafe.As<DamageSource, DamageSource>(ref di.damageType.damageSource)/*cast due to .constrained prefix*/).ToString() + " proc=" + di.procCoefficient.ToString("0.##", CultureInfo.InvariantCulture) + " mask=" + di.procChainMask.mask.ToString(CultureInfo.InvariantCulture) + " ext=" + ((object)Unsafe.As<DamageTypeExtended, DamageTypeExtended>(ref di.damageType.damageTypeExtended)/*cast due to .constrained prefix*/).ToString() + (di.crit ? " crit" : ""); } string text = ((Object)inflictor).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num > 0) { text = text.Substring(0, num); } return text + " [" + ((object)Unsafe.As<DamageColorIndex, DamageColorIndex>(ref di.damageColorIndex)/*cast due to .constrained prefix*/).ToString() + "]"; } private static PlayerStats GetOrCreateIn(Dictionary<int, PlayerStats> map, CharacterMaster owner, PlayerCharacterMasterController pcmc) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)owner).GetInstanceID(); if (!map.TryGetValue(instanceID, out var value)) { value = (map[instanceID] = new PlayerStats { DisplayName = ResolveName(pcmc) }); } else if (string.IsNullOrEmpty(value.DisplayName)) { value.DisplayName = ResolveName(pcmc); } if (value.NetId == 0) { NetworkUser networkUser = pcmc.networkUser; if ((Object)(object)networkUser != (Object)null) { PlayerStats playerStats2 = value; NetworkInstanceId netId = ((NetworkBehaviour)networkUser).netId; playerStats2.NetId = ((NetworkInstanceId)(ref netId)).Value; } } return value; } private static string ResolveName(PlayerCharacterMasterController pcmc) { NetworkUser val = (((Object)(object)pcmc != (Object)null) ? pcmc.networkUser : null); if (!((Object)(object)val != (Object)null) || string.IsNullOrEmpty(val.userName)) { return "Player"; } return val.userName; } private static DamageScope ClassifyScope(DamageReport report) { if (!report.victimIsBoss) { return DamageScope.Mobs; } return DamageScope.TeleporterBoss; } public static int CurrentStage() { Run instance = Run.instance; if (!((Object)(object)instance != (Object)null)) { return 0; } return instance.stageClearCount + 1; } private static float Now() { Run instance = Run.instance; if (!((Object)(object)instance != (Object)null)) { return Time.time; } return instance.GetRunStopwatch(); } public void ResetScope(DamageScope scope) { foreach (KeyValuePair<int, PlayerStats> player in _players) { player.Value[scope].Reset(); } } public void ResetTakenTotals() { foreach (KeyValuePair<int, IncomingLog> item in _taken) { item.Value.ResetTotals(); } } public void ResetAll() { foreach (KeyValuePair<int, PlayerStats> player in _players) { player.Value.ResetAll(); } foreach (KeyValuePair<int, IncomingLog> item in _taken) { item.Value.Clear(); } ResetDiagnostics(); } public void Clear() { _players.Clear(); _taken.Clear(); _activeBossGroups.Clear(); ResetDiagnostics(); } private void ResetDiagnostics() { TrackedTotal = 0.0; UnattributedTotal = 0.0; UnresolvedByInflictor.Clear(); _labels.Clear(); } } [HarmonyPatch(typeof(DelayBlast), "Detonate")] internal static class DelayBlastScope { public static GameObject Current; private static void Prefix(DelayBlast __instance, out GameObject __state) { __state = Current; Current = ((Component)__instance).gameObject; } private static void Finalizer(GameObject __state) { Current = __state; } } public static class Fmt { private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; private static readonly string[] Suffixes = new string[6] { "", "k", "M", "B", "T", "Q" }; public static string Compact(double v) { int tier; return Compact(v, out tier); } public static string Compact(double v, out int tier) { tier = 0; if (double.IsNaN(v) || double.IsInfinity(v)) { return "-"; } if (v < 0.0) { return "-" + Compact(0.0 - v, out tier); } if (v < 1000.0) { return v.ToString("#,0", Inv); } double num = v; while (num >= 1000.0 && tier < Suffixes.Length - 1) { num /= 1000.0; tier++; } if (num >= 1000.0) { tier = Suffixes.Length; return v.ToString("0.###e+0", Inv); } int num2 = DecimalsFor(num); double num3 = Math.Round(num, num2, MidpointRounding.AwayFromZero); if (num3 >= 1000.0 && tier < Suffixes.Length - 1) { tier++; num = num3 / 1000.0; num2 = 2; } else { num = num3; int num4 = DecimalsFor(num); if (num4 != num2) { num2 = num4; num = Math.Round(num, num2, MidpointRounding.AwayFromZero); } } return num.ToString("0." + new string('0', num2), Inv) + Suffixes[tier]; } private static int DecimalsFor(double mantissa) { if (!(mantissa >= 100.0)) { if (!(mantissa >= 10.0)) { return 2; } return 1; } return 0; } public static string Num(double v, int decimals = 0) { if (double.IsNaN(v) || double.IsInfinity(v)) { return "-"; } return v.ToString("N" + decimals.ToString(Inv), Inv); } public static string Percent(double v, int decimals = 1) { if (double.IsNaN(v) || double.IsInfinity(v)) { return "-"; } return Num(v, decimals) + "%"; } } public struct IncomingEvent { public uint Id; public float Time; public int AttackerBody; public int SourceKey; public float Damage; public int Count; public bool Crit; } public sealed class IncomingLog { private const float CoalesceWindow = 4f; public const int Capacity = 128; private readonly IncomingEvent[] _events = new IncomingEvent[128]; private int _count; private int _head; private uint _nextId = 1u; public double Total; public readonly Dictionary<long, SourceAgg> BySource = new Dictionary<long, SourceAgg>(16); public int Count => _count; public uint LatestId => _nextId - 1; public static long TotalKey(int attackerBody, int sourceKey) { return ((long)attackerBody << 32) | (uint)sourceKey; } public static int AttackerOf(long key) { return (int)(key >> 32); } public static int SourceOf(long key) { return (int)(key & 0xFFFFFFFFu); } public IncomingEvent GetNewest(int offset) { int num = (_head - 1 - offset + 256) % 128; return _events[num]; } public void Add(int attackerBody, int sourceKey, float damage, float now, bool crit) { long key = TotalKey(attackerBody, sourceKey); BySource.TryGetValue(key, out var value); value.Damage += damage; value.Hits++; if (crit) { value.Crits++; } BySource[key] = value; Total += damage; if (_count > 0) { int num = (_head - 1 + 128) % 128; ref IncomingEvent reference = ref _events[num]; if (reference.AttackerBody == attackerBody && reference.SourceKey == sourceKey && now - reference.Time <= 4f) { reference.Damage += damage; reference.Count++; reference.Time = now; reference.Crit |= crit; return; } } _events[_head] = new IncomingEvent { Id = _nextId++, Time = now, AttackerBody = attackerBody, SourceKey = sourceKey, Damage = damage, Count = 1, Crit = crit }; _head = (_head + 1) % 128; if (_count < 128) { _count++; } } public void CopyNewest(List<IncomingEvent> into, int max) { into.Clear(); int num = ((_count < max) ? _count : max); for (int i = 0; i < num; i++) { into.Add(GetNewest(i)); } } public void Merge(IncomingEvent e) { for (int i = 0; i < _count; i++) { int num = (_head - 1 - i + 256) % 128; if (_events[num].Id == e.Id) { _events[num] = e; return; } if (_events[num].Id < e.Id) { break; } } _events[_head] = e; _head = (_head + 1) % 128; if (_count < 128) { _count++; } if (e.Id >= _nextId) { _nextId = e.Id + 1; } } public void ResetTotals() { Total = 0.0; BySource.Clear(); } public void Clear() { _count = 0; _head = 0; _nextId = 1u; ResetTotals(); } } public static class InflictorMap { private static Dictionary<string, string> _prefabToOwner; private static readonly Dictionary<int, int> _byProjectile = new Dictionary<int, int>(128); private static readonly Dictionary<string, int> _byName = new Dictionary<string, int>(128); private static readonly Dictionary<int, int> _byInstance = new Dictionary<int, int>(128); private const int MaxInstances = 4096; private const int Unresolved = int.MinValue; public static int Count => _prefabToOwner?.Count ?? 0; public static void Load() { if (_prefabToOwner != null) { return; } _prefabToOwner = new Dictionary<string, string>(2048, StringComparer.Ordinal); Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = null; string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith("inflictors.txt", StringComparison.Ordinal)) { text = text2; break; } } if (text == null) { return; } using Stream stream = executingAssembly.GetManifestResourceStream(text); using StreamReader streamReader = new StreamReader(stream); string text3; while ((text3 = streamReader.ReadLine()) != null) { int num = text3.IndexOf('='); if (num > 0 && num != text3.Length - 1) { _prefabToOwner[text3.Substring(0, num)] = text3.Substring(num + 1); } } } public static bool TryResolve(GameObject inflictor, GameObject attacker, out int key) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected I4, but got Unknown key = 0; if ((Object)(object)inflictor == (Object)null) { return false; } if (inflictor != attacker) { CharacterBody component = inflictor.GetComponent<CharacterBody>(); if ((Object)(object)component != (Object)null && (int)component.bodyIndex >= 0) { key = SourceKey.Pack(SourceKind.Minion, (int)component.bodyIndex); return true; } } if (_prefabToOwner == null) { return false; } ProjectileController component2 = inflictor.GetComponent<ProjectileController>(); if ((Object)(object)component2 != (Object)null) { int catalogIndex = component2.catalogIndex; if (_byProjectile.TryGetValue(catalogIndex, out var value)) { key = value; return value != int.MinValue; } int num = ResolveByName(((Object)inflictor).name); _byProjectile[catalogIndex] = num; key = num; return num != int.MinValue; } int instanceID = ((Object)inflictor).GetInstanceID(); if (!_byInstance.TryGetValue(instanceID, out var value2)) { string text = StripClone(((Object)inflictor).name); if (!_byName.TryGetValue(text, out value2)) { value2 = ResolveOwner(text); _byName[text] = value2; } if (_byInstance.Count >= 4096) { _byInstance.Clear(); } _byInstance[instanceID] = value2; } key = value2; return value2 != int.MinValue; } private static int ResolveByName(string rawName) { return ResolveOwner(StripClone(rawName)); } private static int ResolveOwner(string prefabName) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_001e: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected I4, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected I4, but got Unknown if (!_prefabToOwner.TryGetValue(prefabName, out var value)) { return int.MinValue; } ItemIndex val = ItemCatalog.FindItemIndex(value); if ((int)val != -1) { return SourceKey.Pack(SourceKind.Item, (int)val); } EquipmentIndex val2 = EquipmentCatalog.FindEquipmentIndex(value); if ((int)val2 != -1) { return SourceKey.Pack(SourceKind.Equipment, (int)val2); } return int.MinValue; } private static string StripClone(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num <= 0) { return name; } return name.Substring(0, num); } } public static class InventoryWatcher { private static readonly Dictionary<int, int[]> _lastStacks = new Dictionary<int, int[]>(8); private static readonly Dictionary<int, EquipmentIndex> _lastEquipment = new Dictionary<int, EquipmentIndex>(8); private static readonly StringBuilder Sb = new StringBuilder(128); public static void Subscribe() { Inventory.onInventoryChangedGlobal += OnChanged; } public static void Unsubscribe() { Inventory.onInventoryChangedGlobal -= OnChanged; } public static void Clear() { _lastStacks.Clear(); _lastEquipment.Clear(); } private static void OnChanged(Inventory inventory) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type