Decompiled source of Netstat v1.0.6
Netstat.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.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Globals; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using Netstat.Config; using Netstat.Grapher; using Netstat.Telemetry; using Netstat.UI; using Player; using SNetwork; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Netstat")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Netstat")] [assembly: AssemblyTitle("Netstat")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Netstat { public class CuteBehaviour : MonoBehaviour { public CuteBehaviour(IntPtr ptr) : base(ptr) { } } internal static class Logger { private static ManualLogSource _mLogSource; public static bool Ready => _mLogSource != null; public static void Setup() { _mLogSource = Logger.CreateLogSource("food.randomuser.gtfo.Netstat"); } public static void SetupFromInit(ManualLogSource logSource) { _mLogSource = logSource; } private static string Format(object data) { return data.ToString(); } public static void Debug(object msg) { if (ConfigMgr.Debug) { _mLogSource.LogInfo((object)(" [DEBUG] " + Format(msg))); } } public static void Debug(string fmt, params object[] args) { if (ConfigMgr.Debug) { _mLogSource.LogInfo((object)("[DEBUG] " + Format(string.Format(fmt, args)))); } else { _mLogSource.LogDebug((object)Format(string.Format(fmt, args))); } } public static void Info(object msg) { _mLogSource.LogInfo((object)Format(msg)); } public static void Info(string fmt, params object[] args) { _mLogSource.LogInfo((object)Format(string.Format(fmt, args))); } public static void Warn(object msg) { _mLogSource.LogWarning((object)Format(msg)); } public static void Warn(string fmt, params object[] args) { _mLogSource.LogWarning((object)Format(string.Format(fmt, args))); } public static void Error(object msg) { _mLogSource.LogError((object)Format(msg)); } public static void Error(string fmt, params object[] args) { _mLogSource.LogError((object)Format(string.Format(fmt, args))); } public static void Fatal(object msg) { _mLogSource.LogFatal((object)Format(msg)); } public static void Fatal(string fmt, params object[] args) { _mLogSource.LogFatal((object)Format(string.Format(fmt, args))); } } public static class NetstatAPI { public enum PingerTypeEnum { Chat, Marker } public static PingerTypeEnum PingerType => ConfigMgr.PingerType; public static float Ping { get { if (PingerType != 0) { return MarkerPinger.Ping; } return ChatPinger.Ping; } } public static float RawPing { get { if (PingerType != 0) { return MarkerPinger.RawPing; } return ChatPinger.RawPing; } } public static int PingMs => (int)(Ping * 1000f); public static int RawPingMs => (int)(RawPing * 1000f); public static float Jitter { get { if (PingerType != 0) { return MarkerPinger.Jitter; } return ChatPinger.Jitter; } } public static float RawJitter { get { if (PingerType != 0) { return MarkerPinger.RawJitter; } return ChatPinger.RawJitter; } } public static float JitterMs => (int)(Jitter * 1000f); public static float RawJitterMs => (int)(RawJitter * 1000f); public static bool IsPingerActive { get { if (PingerType != 0) { return MarkerPinger.IsMeasuring; } return true; } } public static bool IsDesynced { get { if (PingerType != 0) { return MarkerPinger.IsDesynced; } return ChatPinger.IsDesynced; } } public static ReadOnlySpan<ChannelStats> Channels => SteamP2P.Channels; public static uint BytesReceived => SteamP2P.BytesReceived; public static uint PacketsReceived => SteamP2P.PacketsReceived; public static uint BytesSent => SteamP2P.BytesSent; public static uint PacketsSent => SteamP2P.PacketsSent; public static int BytesQueuedForSend => SteamP2P.BytesQueuedForSend; public static int PacketsQueuedForSend => SteamP2P.PacketsQueuedForSend; public static TickStats GetTickStat(ulong steamId) { return TickTimer.GetTickStat(steamId); } } [BepInPlugin("food.randomuser.gtfo.Netstat", "Netstat", "1.0.6")] public class Plugin : BasePlugin { public const string NAME = "Netstat"; public const string GUID = "food.randomuser.gtfo.Netstat"; public const string VERSION = "1.0.6"; private GameObject _netstatObj; public event Action? OnManagersSetup; public override void Load() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00d3: Expected O, but got Unknown Logger.Setup(); Logger.Info("Netstat [food.randomuser.gtfo.Netstat @ 1.0.6]"); Harmony val = new Harmony("food.randomuser.gtfo.Netstat"); ConfigMgr.Init(); ClassInjector.RegisterTypeInIl2Cpp<UIManager>(); ClassInjector.RegisterTypeInIl2Cpp<StatGraph>(); ClassInjector.RegisterTypeInIl2Cpp<ChatPinger>(); ClassInjector.RegisterTypeInIl2Cpp<MarkerPinger>(); ClassInjector.RegisterTypeInIl2Cpp<SteamP2P>(); ClassInjector.RegisterTypeInIl2Cpp<TickTimer>(); ClassInjector.RegisterTypeInIl2Cpp<Plotter>(); ClassInjector.RegisterTypeInIl2Cpp<CuteBehaviour>(); OnManagersSetup += Initialize; Global.OnAllManagersSetup += Action.op_Implicit(this.OnManagersSetup); Logger.Info("Patching..."); RundownManager.OnExpeditionGameplayStarted += Action.op_Implicit((Action)MarkerPinger.Start); ApplyPatch<MarkerPinger>(val); ApplyPatch<ChatPinger>(val); ApplyPatch<SteamP2P>(val); RundownManager.OnExpeditionGameplayStarted += Action.op_Implicit((Action)TickTimer.Start); ApplyPatch<TickTimer>(val); Logger.Info("Finished Patching"); } private static void ApplyPatch<T>(Harmony h) { h.PatchAll(typeof(T)); } private void Initialize() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown _netstatObj = new GameObject("food.randomuser.gtfo.Netstat"); Object.DontDestroyOnLoad((Object)(object)_netstatObj); _netstatObj.AddComponent<ChatPinger>(); _netstatObj.AddComponent<MarkerPinger>(); _netstatObj.AddComponent<SteamP2P>(); _netstatObj.AddComponent<TickTimer>(); _netstatObj.AddComponent<UIManager>(); _netstatObj.AddComponent<CuteBehaviour>(); } public override bool Unload() { return true; } } public static class Util { private static readonly string[] _siAbbrs = new string[7] { "", "K", "M", "G", "T", "P", "E" }; public static Vector3 Extend(this Vector2 v, float z = 0f) { //IL_0000: 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_000d: Unknown result type (might be due to invalid IL or missing references) return new Vector3(v.x, v.y, z); } public static int TrueMod(int n, int m) { return (n % m + m) % m; } public static string Value2SIAbbrStr(float value, bool includeOneDecimalWhenValueLessThan10 = true) { bool flag = value < 1000f; int num = 0; while (value >= 1000f && num < _siAbbrs.Length - 1) { value /= 1000f; num++; } string text = ((!flag && includeOneDecimalWhenValueLessThan10 && value < 10f) ? "0.0" : "0"); return value.ToString(text) + _siAbbrs[num]; } } } namespace Netstat.UI { [Flags] public enum eNetstatData { Ping = 1, Rx = 2, Tx = 4, CTT = 8, STT = 0x10 } [Flags] public enum eNetstatGraph { Ping = 1, RxTx = 2, RxChan = 4, TxChan = 8, CSTT = 0x10 } public class StatConfigLib { public static readonly StatGraphConfig Ping = new StatGraphConfig { Sources = StatSourceLib.WPing, Unit = "ms", PlotMin = 0f, PlotMax = 500f, PlotAutoScale = true, PlotAutoScaleIncrement = 50f, AbbreviateWithSIPrefix = false, SampleRate = 2f, Precision = 0u }; public static readonly StatGraphConfig RxTx = new StatGraphConfig { Sources = StatSourceLib.WRxTx, Unit = "B/s", PlotMin = 0f, PlotMax = 1000f, PlotAutoScale = true, PlotAutoScaleIncrement = 500f, AbbreviateWithSIPrefix = true, SampleRate = 2f, Precision = 0u }; public static readonly StatGraphConfig RxChannelsShort = new StatGraphConfig { Sources = StatSourceLib.WRxChannelsShort, Unit = "B/s", PlotMin = 0f, PlotMax = 1000f, PlotAutoScale = true, PlotAutoScaleIncrement = 500f, AbbreviateWithSIPrefix = true, SampleRate = 2f, Precision = 0u }; public static readonly StatGraphConfig TxChannelsShort = new StatGraphConfig { Sources = StatSourceLib.WTxChannelsShort, Unit = "B/s", PlotMin = 0f, PlotMax = 1000f, PlotAutoScale = true, PlotAutoScaleIncrement = 500f, AbbreviateWithSIPrefix = true, SampleRate = 2f, Precision = 0u }; public static readonly StatGraphConfig CSTT = new StatGraphConfig { Sources = StatSourceLib.WCSTT, Unit = "ms", PlotMin = 0f, PlotMax = 200f, PlotAutoScale = true, PlotAutoScaleIncrement = 50f, AbbreviateWithSIPrefix = false, SampleRate = 2f, Precision = 0u }; public static eNetstatGraph Str2GraphType(string key) { return key switch { "ping" => eNetstatGraph.Ping, "rxtx" => eNetstatGraph.RxTx, "rxchan" => eNetstatGraph.RxChan, "txchan" => eNetstatGraph.TxChan, "cstt" => eNetstatGraph.CSTT, _ => (eNetstatGraph)0, }; } public static bool TryGet(string key, out StatGraphConfig conf) { return TryGet(Str2GraphType(key), out conf); } public static bool TryGet(eNetstatGraph type, out StatGraphConfig conf) { switch (type) { case eNetstatGraph.Ping: conf = Ping; break; case eNetstatGraph.RxTx: conf = RxTx; break; case eNetstatGraph.RxChan: conf = RxChannelsShort; break; case eNetstatGraph.TxChan: conf = TxChannelsShort; break; case eNetstatGraph.CSTT: conf = CSTT; break; default: conf = default(StatGraphConfig); return false; } return true; } } public class StatGraph : MonoBehaviour { public struct DataSource { public string Label; public Func<float> ValueProvider; public Color? Color; } private RectTransform? _rt; private bool _dirty; private DataSource[] _dataSources = Array.Empty<DataSource>(); private static readonly List<Color> PlotLineColors = new List<Color> { new Color(0.12f, 0.47f, 0.71f), new Color(1f, 0.5f, 0.05f), new Color(0.17f, 0.63f, 0.17f), new Color(0.84f, 0.15f, 0.16f), new Color(0.58f, 0.4f, 0.74f), new Color(0.55f, 0.34f, 0.29f) }; private Color32 _textColor = new Color32((byte)227, (byte)227, (byte)227, (byte)227); private readonly List<TextMeshProUGUI?> _labelTexts = new List<TextMeshProUGUI>(); private readonly List<TextMeshProUGUI?> _valueTexts = new List<TextMeshProUGUI>(); private TextMeshProUGUI? _graphMaxText; private TextMeshProUGUI? _graphMinText; private TextMeshProUGUI? _graphTimeText; private Plotter? _plot; private const float BlockHeight = 12f; private const float ElementSpacing = 4f; private float _sampleRate = 2f; private float _sampleInterval = 0.5f; private float _timeSinceLastSample; public RectTransform RT { get { if ((Object)(object)_rt == (Object)null) { _rt = ((Component)this).GetComponent<RectTransform>(); } return _rt; } } public Vector2 Size => RT.sizeDelta; public Vector2 PlotSize { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Plot.PlotSize; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Plot.PlotSize = value; } } public Plotter Plot => _plot ?? throw new NullReferenceException("StatGraph[" + ((Object)this).name + "] No plotter assigned."); private float DesiredClearance => (float)_dataSources.Length * 16f; public Color32 TextColor { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _textColor; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) _textColor = value; _dirty = true; } } public string Unit { get; set; } public uint Precision { get; set; } = 1u; public bool AbbreviateWithSIUnit { get; set; } public float SampleRate { get { return _sampleRate; } set { _sampleRate = value; _sampleInterval = 1f / _sampleRate; } } public StatGraph(IntPtr ptr) : base(ptr) { //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) Unit = ""; } public static StatGraph Create(Transform parent, Vector2 graphSize, StatGraphConfig config) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return Create(parent, config.Sources, config.Unit, graphSize, config.PlotMin, config.PlotMax, config.PlotAutoScale, config.PlotAutoScaleIncrement, config.ObjectName, config.AbbreviateWithSIPrefix, config.SampleRate, config.Precision); } public static StatGraph Create(Transform parent, DataSource[] sources, string unit, Vector2 plotSize, float min = 0f, float max = 1f, bool autoScale = true, float autoScaleInc = -1f, string objName = "", bool abbrValWithSI = false, float sampleRate = 2f, uint precision = 0u) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject((objName == "") ? ("StatGraph." + sources.Select((DataSource s) => s.Label).Aggregate((string str0, string str1) => str0 + "_" + str1)) : objName); RectTransform val2 = val.AddComponent<RectTransform>(); ((Transform)val2).SetParent(parent, false); StatGraph statGraph = val.AddComponent<StatGraph>(); statGraph._rt = val2; statGraph._dataSources = sources; statGraph.Unit = unit; statGraph.AbbreviateWithSIUnit = abbrValWithSI; statGraph.SampleRate = sampleRate; statGraph.Precision = precision; Plotter plotter = ((Component)statGraph).gameObject.AddComponent<Plotter>(); plotter.PlotSize = plotSize; plotter.SetAutoScale(autoScale); plotter.SetGraphMinMax(min, max); plotter.SetAutoScaleIncrement(autoScaleInc); plotter.AfterPopulateMesh += statGraph.DrawLegendIdentifiers; plotter.AfterPopulateMesh += statGraph.DrawMaxTick; statGraph._plot = plotter; val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(1f, 0f); val2.anchoredPosition3D = Vector3.zero; statGraph.Recreate(); if (TMPUtil.CreateTMPUGUI("GraphMax", (Transform?)(object)statGraph.RT, out TextMeshProUGUI tp)) { statGraph._graphMaxText = tp; } if (TMPUtil.CreateTMPUGUI("GraphMin", (Transform?)(object)statGraph.RT, out TextMeshProUGUI tp2)) { statGraph._graphMinText = tp2; } if (TMPUtil.CreateTMPUGUI("Time", (Transform?)(object)statGraph.RT, out TextMeshProUGUI tp3)) { statGraph._graphTimeText = tp3; } statGraph.Reconfigure(); return statGraph; } public void UpdateSources(DataSource[] sources) { if (sources.Length != _dataSources.Length) { _dataSources = sources; Recreate(); Reconfigure(); } else { _dataSources = sources; Reconfigure(); } } private void Recreate() { foreach (TextMeshProUGUI labelText in _labelTexts) { if ((Object)(object)labelText != (Object)null) { Object.Destroy((Object)(object)((Component)labelText).gameObject); } } foreach (TextMeshProUGUI valueText in _valueTexts) { if ((Object)(object)valueText != (Object)null) { Object.Destroy((Object)(object)((Component)valueText).gameObject); } } _labelTexts.Clear(); _valueTexts.Clear(); for (int i = 0; i < _dataSources.Length; i++) { if (TMPUtil.CreateTMPUGUI($"Label.C{i}", (Transform?)(object)RT, out TextMeshProUGUI tp)) { ((TMP_Text)tp).text = _dataSources[i].Label; _labelTexts.Add(tp); } if (TMPUtil.CreateTMPUGUI($"Value.C{i}", (Transform?)(object)RT, out TextMeshProUGUI tp2)) { _valueTexts.Add(tp2); } } } private void Reconfigure() { //IL_0080: 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_0085: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_0542: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_058a: Unknown result type (might be due to invalid IL or missing references) //IL_0591: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Unknown result type (might be due to invalid IL or missing references) //IL_060b: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_0661: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_0677: Unknown result type (might be due to invalid IL or missing references) //IL_0686: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_plot == (Object)null) { Logger.Error("StatGraph[" + ((Object)this).name + "] No plotter assigned."); return; } _plot.SetClearance(DesiredClearance); _plot.AllocateChannels(_dataSources.Length); for (int i = 0; i < _dataSources.Length; i++) { Color c = (Color)(((??)_dataSources[i].Color) ?? PlotLineColors[i]); _plot.SetColor(Plotter.PlotComponent.Line, c, i); } string fmt = "StatGraph[" + ((Object)this).name + "]->{0} UI reconfigure failed, is null."; Vector2 val2 = default(Vector2); Vector2 v = default(Vector2); Vector2 val4 = default(Vector2); Vector2 v2 = default(Vector2); for (int j = 0; j < _dataSources.Length; j++) { TextMeshProUGUI val = _labelTexts[j]; if ((Object)(object)val != (Object)null) { ((TMP_Text)val).SetText(_dataSources[j].Label, true); ((Vector2)(ref val2))..ctor(0f, 1f); ((TMP_Text)val).alignment = (TextAlignmentOptions)513; ((Graphic)val).color = Color.white; ((TMP_Text)val).faceColor = TextColor; ((TMP_Text)val).autoSizeTextContainer = false; ((TMP_Text)val).enableAutoSizing = true; ((TMP_Text)val).fontSizeMax = 20f; ((TMP_Text)val).fontSizeMin = 16f; RectTransform rectTransform = ((TMP_Text)val).rectTransform; rectTransform.anchorMax = val2; rectTransform.anchorMin = val2; rectTransform.pivot = new Vector2(0f, 0.5f); rectTransform.sizeDelta = new Vector2(_plot.Size.x - 12f - 4f, 12f); ((Vector2)(ref v))..ctor(16f, 0f - ((float)j * 16f + 4f + 6f)); rectTransform.anchoredPosition3D = v.Extend(); } else { Logger.Warn(fmt, $"C{j}:Label"); } TextMeshProUGUI val3 = _valueTexts[j]; if ((Object)(object)val3 != (Object)null) { ((Vector2)(ref val4))..ctor(1f, 1f); ((TMP_Text)val3).alignment = (TextAlignmentOptions)516; ((Graphic)val3).color = Color.white; ((TMP_Text)val3).faceColor = TextColor; ((TMP_Text)val3).autoSizeTextContainer = false; ((TMP_Text)val3).enableAutoSizing = true; ((TMP_Text)val3).fontSizeMax = 20f; ((TMP_Text)val3).fontSizeMin = 16f; RectTransform rectTransform2 = ((TMP_Text)val3).rectTransform; rectTransform2.anchorMax = val4; rectTransform2.anchorMin = val4; rectTransform2.pivot = new Vector2(1f, 0.5f); rectTransform2.sizeDelta = new Vector2(_plot.Size.x, 12f); ((Vector2)(ref v2))..ctor(-4f, 0f - ((float)j * 16f + 4f + 6f)); rectTransform2.anchoredPosition3D = v2.Extend(); } else { Logger.Warn(fmt, $"C{j}:Value"); } } if ((Object)(object)_graphTimeText != (Object)null) { Vector2 val5 = default(Vector2); ((Vector2)(ref val5))..ctor(0f, 0f); ((TMP_Text)_graphTimeText).alignment = (TextAlignmentOptions)1025; ((Graphic)_graphTimeText).color = Color.white; ((TMP_Text)_graphTimeText).faceColor = TextColor; ((TMP_Text)_graphTimeText).autoSizeTextContainer = false; ((TMP_Text)_graphTimeText).enableAutoSizing = true; ((TMP_Text)_graphTimeText).fontSizeMax = 20f; ((TMP_Text)_graphTimeText).fontSizeMin = 16f; RectTransform rectTransform3 = ((TMP_Text)_graphTimeText).rectTransform; rectTransform3.anchorMax = val5; rectTransform3.anchorMin = val5; rectTransform3.pivot = val5; rectTransform3.sizeDelta = new Vector2(_plot.Size.x, 12f); Vector2 val6 = new Vector2(0.5f, 0.5f) - val5; Vector2 v3 = ((Vector2)(ref val6)).normalized * 4f; rectTransform3.anchoredPosition3D = v3.Extend(); } else { Logger.Warn(fmt, "GraphTime"); } if ((Object)(object)_graphMaxText != (Object)null) { Vector2 val7 = default(Vector2); ((Vector2)(ref val7))..ctor(0f, 1f); Vector2 pivot = default(Vector2); ((Vector2)(ref pivot))..ctor(1f, 1f); ((TMP_Text)_graphMaxText).alignment = (TextAlignmentOptions)516; ((Graphic)_graphMaxText).color = Color.white; ((TMP_Text)_graphMaxText).faceColor = TextColor; ((TMP_Text)_graphMaxText).autoSizeTextContainer = false; ((TMP_Text)_graphMaxText).enableAutoSizing = true; ((TMP_Text)_graphMaxText).fontSizeMax = 20f; ((TMP_Text)_graphMaxText).fontSizeMin = 16f; RectTransform rectTransform4 = ((TMP_Text)_graphMaxText).rectTransform; rectTransform4.anchorMax = val7; rectTransform4.anchorMin = val7; rectTransform4.pivot = pivot; rectTransform4.sizeDelta = new Vector2(_plot.Size.x, 12f); Vector2 v4 = default(Vector2); ((Vector2)(ref v4))..ctor(-4f, 0f - (DesiredClearance - 6f)); rectTransform4.anchoredPosition3D = v4.Extend(); } else { Logger.Warn(fmt, "GraphMax"); } if ((Object)(object)_graphMinText != (Object)null) { Vector2 val8 = default(Vector2); ((Vector2)(ref val8))..ctor(0f, 0f); Vector2 pivot2 = default(Vector2); ((Vector2)(ref pivot2))..ctor(1f, 0f); ((TMP_Text)_graphMinText).alignment = (TextAlignmentOptions)1028; ((Graphic)_graphMinText).color = Color.white; ((TMP_Text)_graphMinText).faceColor = TextColor; ((TMP_Text)_graphMinText).autoSizeTextContainer = false; ((TMP_Text)_graphMinText).enableAutoSizing = true; ((TMP_Text)_graphMinText).fontSizeMax = 20f; ((TMP_Text)_graphMinText).fontSizeMin = 16f; RectTransform rectTransform5 = ((TMP_Text)_graphMinText).rectTransform; rectTransform5.anchorMax = val8; rectTransform5.anchorMin = val8; rectTransform5.pivot = pivot2; rectTransform5.sizeDelta = new Vector2(_plot.Size.x, 12f); Vector2 v5 = default(Vector2); ((Vector2)(ref v5))..ctor(-4f, 0f); rectTransform5.anchoredPosition3D = v5.Extend(); } else { Logger.Warn(fmt, "GraphMin"); } _dirty = false; } private void Update() { if ((Object)(object)_plot == (Object)null) { Logger.Error("StatGraph[" + ((Object)this).name + "] No plotter assigned."); return; } _timeSinceLastSample += Time.deltaTime; if (_timeSinceLastSample >= _sampleInterval) { for (int i = 0; i < _dataSources.Length; i++) { float value = _dataSources[i].ValueProvider(); _plot.PushSample(value, i); if ((Object)(object)_valueTexts[i] != (Object)null) { string text = (AbbreviateWithSIUnit ? Util.Value2SIAbbrStr(value) : value.ToString($"F{Precision}")); ((TMP_Text)_valueTexts[i]).text = text + Unit; } } _timeSinceLastSample = 0f; } TextMeshProUGUI? graphMinText = _graphMinText; if (graphMinText != null) { ((TMP_Text)graphMinText).SetText(AbbreviateWithSIUnit ? Util.Value2SIAbbrStr(_plot.MinY) : _plot.MinY.ToString($"F{Precision}"), true); } TextMeshProUGUI? graphMaxText = _graphMaxText; if (graphMaxText != null) { ((TMP_Text)graphMaxText).SetText(AbbreviateWithSIUnit ? Util.Value2SIAbbrStr(_plot.DisplayMaxY) : _plot.DisplayMaxY.ToString($"F{Precision}"), true); } TextMeshProUGUI? graphTimeText = _graphTimeText; if (graphTimeText != null) { ((TMP_Text)graphTimeText).SetText($"{(float)_plot.Capacity * _sampleInterval:F0}s", true); } if (_dirty) { Reconfigure(); } } private void DrawLegendIdentifiers(Graphic graphic, VertexHelper vh) { //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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) Rect pixelAdjustedRect = graphic.GetPixelAdjustedRect(); Vector2 val = default(Vector2); Rect r = default(Rect); for (int i = 0; i < _dataSources.Length; i++) { Color c = (Color)(((??)_dataSources[i].Color) ?? PlotLineColors[i]); float num = Mathf.Floor(6f); float num2 = (12f - num) / 2f; ((Vector2)(ref val))..ctor(((Rect)(ref pixelAdjustedRect)).xMin + 4f + num2, ((Rect)(ref pixelAdjustedRect)).yMax - (float)(i + 1) * 16f + num2); ((Rect)(ref r))..ctor(val, new Vector2(num, num)); Plotter.AddRect(vh, r, c); } } private void DrawMaxTick(Graphic graphic, VertexHelper vh) { //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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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) Rect pixelAdjustedRect = graphic.GetPixelAdjustedRect(); Rect r = default(Rect); ((Rect)(ref r))..ctor(((Rect)(ref pixelAdjustedRect)).xMin, ((Rect)(ref pixelAdjustedRect)).yMax - DesiredClearance, 4f, 1f); Plotter.AddRect(vh, r, (Color)(((??)_plot?.BorderColor) ?? new Color(1f, 1f, 1f, 0.35f))); } } public struct StatGraphConfig { public StatGraph.DataSource[] Sources; public string Unit; public float PlotMin; public float PlotMax; public bool PlotAutoScale; public float PlotAutoScaleIncrement; public string ObjectName; public uint Precision; public float SampleRate; public bool AbbreviateWithSIPrefix; public StatGraphConfig() { Sources = new StatGraph.DataSource[0]; Unit = ""; PlotMin = 0f; PlotMax = 1f; PlotAutoScale = true; PlotAutoScaleIncrement = -1f; ObjectName = ""; Precision = 0u; SampleRate = 2f; AbbreviateWithSIPrefix = false; } } public static class StatSourceLib { public static readonly StatGraph.DataSource Ping = new StatGraph.DataSource { Label = "Ping", ValueProvider = () => NetstatAPI.PingMs }; public static readonly StatGraph.DataSource Rx = new StatGraph.DataSource { Label = "Rx", ValueProvider = () => NetstatAPI.BytesReceived }; public static readonly StatGraph.DataSource Tx = new StatGraph.DataSource { Label = "Tx", ValueProvider = () => NetstatAPI.BytesSent }; public static readonly StatGraph.DataSource CTT = new StatGraph.DataSource { Label = "CTT", ValueProvider = () => ((Object)(object)SNet.LocalPlayer != (Object)null) ? (NetstatAPI.GetTickStat(SNet.LocalPlayer.Lookup).TickTime * 1000f) : 0f }; public static readonly StatGraph.DataSource STT = new StatGraph.DataSource { Label = "STT", ValueProvider = () => ((Object)(object)SNet.Master != (Object)null) ? (NetstatAPI.GetTickStat(SNet.Master.Lookup).TickTime * 1000f) : 0f }; public static readonly StatGraph.DataSource[] WPing = new StatGraph.DataSource[1] { new StatGraph.DataSource { Label = "Ping", ValueProvider = () => NetstatAPI.PingMs } }; public static readonly StatGraph.DataSource[] WRxTx = new StatGraph.DataSource[2] { new StatGraph.DataSource { Label = "Rx", ValueProvider = () => NetstatAPI.BytesReceived }, new StatGraph.DataSource { Label = "Tx", ValueProvider = () => NetstatAPI.BytesSent } }; public static readonly StatGraph.DataSource[] WRxChannels = Array.ConvertAll((SNet_ChannelType[])Enum.GetValues(typeof(SNet_ChannelType)), delegate(SNet_ChannelType value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) StatGraph.DataSource result4 = default(StatGraph.DataSource); result4.Label = "Tx " + SteamP2P.SNetChannelType2Str(value); result4.ValueProvider = () => NetstatAPI.Channels[(int)value].BytesSent; return result4; }); public static readonly StatGraph.DataSource[] WTxChannels = Array.ConvertAll((SNet_ChannelType[])Enum.GetValues(typeof(SNet_ChannelType)), delegate(SNet_ChannelType value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) StatGraph.DataSource result3 = default(StatGraph.DataSource); result3.Label = "Rx " + SteamP2P.SNetChannelType2Str(value); result3.ValueProvider = () => NetstatAPI.Channels[(int)value].BytesReceived; return result3; }); public static readonly StatGraph.DataSource[] WRxChannelsShort = Array.ConvertAll((SNet_ChannelType[])Enum.GetValues(typeof(SNet_ChannelType)), delegate(SNet_ChannelType value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) StatGraph.DataSource result2 = default(StatGraph.DataSource); result2.Label = "Tx " + SteamP2P.SNetChannelType2StrShort(value); result2.ValueProvider = () => NetstatAPI.Channels[(int)value].BytesSent; return result2; }); public static readonly StatGraph.DataSource[] WTxChannelsShort = Array.ConvertAll((SNet_ChannelType[])Enum.GetValues(typeof(SNet_ChannelType)), delegate(SNet_ChannelType value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) StatGraph.DataSource result = default(StatGraph.DataSource); result.Label = "Rx " + SteamP2P.SNetChannelType2StrShort(value); result.ValueProvider = () => NetstatAPI.Channels[(int)value].BytesReceived; return result; }); public static readonly StatGraph.DataSource[] WCSTT = new StatGraph.DataSource[2] { new StatGraph.DataSource { Label = "CTT", ValueProvider = () => ((Object)(object)SNet.LocalPlayer != (Object)null) ? (NetstatAPI.GetTickStat(SNet.LocalPlayer.Lookup).TickTime * 1000f) : 0f }, new StatGraph.DataSource { Label = "STT", ValueProvider = () => ((Object)(object)SNet.Master != (Object)null) ? (NetstatAPI.GetTickStat(SNet.Master.Lookup).TickTime * 1000f) : 0f } }; } public static class TMPUtil { public static bool CreateTMP(string name, Transform? parent, [NotNullWhen(true)] out TextMeshPro? tp) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) WatermarkGuiLayer watermarkLayer = GuiManager.WatermarkLayer; object obj; if (watermarkLayer == null) { obj = null; } else { PUI_Watermark watermark = watermarkLayer.m_watermark; obj = ((watermark != null) ? watermark.m_fpsText : null); } TextMeshPro val = (TextMeshPro)obj; if ((Object)(object)parent == (Object)null || (Object)(object)val == (Object)null) { tp = null; return false; } tp = Object.Instantiate<TextMeshPro>(val, parent, false); ((Object)tp).name = name; ((TMP_Text)tp).rectTransform.anchorMax = new Vector2(0.5f, 0.5f); ((TMP_Text)tp).rectTransform.anchorMin = new Vector2(0.5f, 0.5f); ((TMP_Text)tp).rectTransform.pivot = new Vector2(1f, 0f); ((TMP_Text)tp).rectTransform.anchoredPosition3D = new Vector3(0f, 2f, 0f); ((Transform)((TMP_Text)tp).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 0f); ((TMP_Text)tp).enableAutoSizing = false; ((TMP_Text)tp).overflowMode = (TextOverflowModes)0; ((TMP_Text)tp).alignment = (TextAlignmentOptions)513; ((TMP_Text)tp).fontSize = 16f; return true; } public static bool CreateTMPUGUI(string name, Transform? parent, [NotNullWhen(true)] out TextMeshProUGUI? tp) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) WatermarkGuiLayer watermarkLayer = GuiManager.WatermarkLayer; object obj; if (watermarkLayer == null) { obj = null; } else { PUI_Watermark watermark = watermarkLayer.m_watermark; obj = ((watermark != null) ? watermark.m_fpsText : null); } TextMeshPro val = (TextMeshPro)obj; GameObject val2 = new GameObject(); val2.transform.SetParent(parent, false); tp = val2.AddComponent<TextMeshProUGUI>(); ((Object)tp).name = name; ((TMP_Text)tp).rectTransform.anchorMax = new Vector2(0.5f, 0.5f); ((TMP_Text)tp).rectTransform.anchorMin = new Vector2(0.5f, 0.5f); ((TMP_Text)tp).rectTransform.pivot = new Vector2(1f, 0f); ((TMP_Text)tp).rectTransform.anchoredPosition3D = new Vector3(0f, 2f, 0f); ((Transform)((TMP_Text)tp).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 0f); ((TMP_Text)tp).enableAutoSizing = false; ((TMP_Text)tp).overflowMode = (TextOverflowModes)0; ((TMP_Text)tp).alignment = (TextAlignmentOptions)513; ((TMP_Text)tp).fontSize = 16f; if ((Object)(object)val != (Object)null) { ((TMP_Text)tp).font = ((TMP_Text)val).font; ((TMP_Text)tp).fontSharedMaterial = ((TMP_Text)val).fontSharedMaterial; } return true; } } public class UIManager : MonoBehaviour { private Canvas _canvas; private CanvasScaler _canvasScaler; private const float ElementSpacing = 4f; private static readonly Vector2 ReferenceResolution = new Vector2(2560f, 1440f); private static readonly Vector2 GraphSize = new Vector2(200f, 100f); public readonly Vector2 Pivot = new Vector2(0.5f, 0.5f); private bool _dirty; private GameObject? _uiRoot; private RectTransform? _graphLayerTrans; private readonly Dictionary<eNetstatGraph, StatGraph> _graphDict = new Dictionary<eNetstatGraph, StatGraph>(); private List<StatGraph> _graphStack = new List<StatGraph>(); private TextMeshProUGUI? _detailsText; private readonly Vector3 _detailsBarOffset = new Vector3(-340f, -12f, 0f); private TextMeshPro? _detailsBar; public static UIManager? Instance { get; private set; } public Vector2 Size { get; set; } = new Vector2(GraphSize.x, 100f); public Vector2 Anchor => ConfigMgr.UIAnchor; public Vector2 AnchorOffset => ConfigMgr.UIAnchorOffset; public bool Active => ConfigMgr.EnableGraphs; public void SetDirty() { _dirty = true; } private void Awake() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)this); return; } Instance = this; _canvas = ((Component)this).gameObject.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 1000; _canvasScaler = ((Component)this).gameObject.AddComponent<CanvasScaler>(); _canvasScaler.uiScaleMode = (ScaleMode)1; _canvasScaler.referenceResolution = ReferenceResolution; _canvasScaler.m_MatchWidthOrHeight = 1f; CreateUI(); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((int)FocusStateManager.Current.m_currentState != 5 && (int)FocusStateManager.Current.m_currentState != 6 && (int)FocusStateManager.Current.m_currentState != 8 && (int)FocusStateManager.Current.m_currentState != 14 && !PlayerChatManager.InChatMode && Input.GetKeyDown(ConfigMgr.GraphToggleKey)) { ConfigMgr.EnableGraphs = !ConfigMgr.EnableGraphs; } if ((Object)(object)_graphLayerTrans != (Object)null && Active != ((Component)_graphLayerTrans).gameObject.activeSelf) { ((Component)_graphLayerTrans).gameObject.SetActive(Active); } if ((Object)(object)_detailsBar != (Object)null && ((UIBehaviour)_detailsBar).IsActive() != ConfigMgr.DetailsBarEnabled) { TextMeshPro? detailsBar = _detailsBar; if (detailsBar != null) { ((Component)detailsBar).gameObject.SetActive(ConfigMgr.DetailsBarEnabled); } } if (_dirty) { _dirty = false; UpdateConfigurableValues(); RefreshGraphStack(); } UpdateTextDisplays(); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void UpdateConfigurableValues() { //IL_0016: 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_0038: 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_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_graphLayerTrans == (Object)null) { return; } _graphLayerTrans.anchorMin = Anchor; _graphLayerTrans.anchorMax = Anchor; _graphLayerTrans.anchoredPosition3D = AnchorOffset.Extend(); foreach (StatGraph value in _graphDict.Values) { value.PlotSize = ConfigMgr.GraphSize; } } private void CreateUI() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) _uiRoot = new GameObject("food.randomuser.gtfo.Netstat.UI"); _graphLayerTrans = _uiRoot.AddComponent<RectTransform>(); ((Transform)_graphLayerTrans).SetParent(((Component)this).gameObject.transform); ((Transform)_graphLayerTrans).localScale = Vector3.one; _graphLayerTrans.anchorMin = Anchor; _graphLayerTrans.anchorMax = Anchor; _graphLayerTrans.pivot = Pivot; _graphLayerTrans.anchoredPosition3D = AnchorOffset.Extend(); _uiRoot.SetActive(true); GenerateGraphs(); if (TMPUtil.CreateTMP("food.randomuser.gtfo.Netstat.UI.DetailsBar", ((Component)GuiManager.PlayerLayer.m_playerStatus).transform, out TextMeshPro tp)) { ((TMP_Text)tp).alignment = (TextAlignmentOptions)513; ((TMP_Text)tp).enableAutoSizing = true; ((TMP_Text)tp).fontSize = 16f; ((TMP_Text)tp).fontSizeMin = 12f; ((TMP_Text)tp).fontSizeMax = 20f; RectTransform rectTransform = ((TMP_Text)tp).rectTransform; rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0f, 1f); rectTransform.sizeDelta = new Vector2(400f, 16f); rectTransform.anchoredPosition3D = _detailsBarOffset; } _detailsBar = tp; if (TMPUtil.CreateTMPUGUI("food.randomuser.gtfo.Netstat.UI.Details", (Transform?)(object)_graphLayerTrans, out TextMeshProUGUI tp2)) { ((TMP_Text)tp2).alignment = (TextAlignmentOptions)257; RectTransform rectTransform2 = ((TMP_Text)tp2).rectTransform; rectTransform2.anchorMax = new Vector2(0.5f, 0.5f); rectTransform2.anchorMin = new Vector2(0.5f, 0.5f); rectTransform2.pivot = new Vector2(1f, 1f); rectTransform2.sizeDelta = new Vector2(Size.x, 12f); rectTransform2.anchoredPosition3D = new Vector3(0f, -4f, 0f); } _detailsText = tp2; } public void UpdateTextDisplays() { if ((Object)(object)_detailsText != (Object)null) { string text = ""; text += (NetstatAPI.IsDesynced ? $"<#AF0000{(uint)((Mathf.Sin(Time.time * (float)Math.PI / 2f) + 1f) * 127f):X2}>DESYNCED</color>" : "\n"); ((TMP_Text)_detailsText).SetText(text.Trim(), true); } if (!((Object)(object)_detailsBar != (Object)null)) { return; } List<string> list = new List<string>(); if (ConfigMgr.DetailsBarData.HasFlag(eNetstatData.Ping)) { list.Add($"Ping {NetstatAPI.PingMs}ms"); } if (ConfigMgr.DetailsBarData.HasFlag(eNetstatData.Rx)) { list.Add("Rx " + Util.Value2SIAbbrStr(NetstatAPI.BytesReceived) + "B/s"); } if (ConfigMgr.DetailsBarData.HasFlag(eNetstatData.Tx)) { list.Add("Tx " + Util.Value2SIAbbrStr(NetstatAPI.BytesSent) + "B/s"); } if (ConfigMgr.DetailsBarData.HasFlag(eNetstatData.STT)) { string text2 = "?"; if ((Object)(object)SNet.Master != (Object)null) { text2 = ((int)(NetstatAPI.GetTickStat(SNet.Master.Lookup).TickTime * 1000f)).ToString(); } list.Add("STT " + text2 + "ms"); } if (ConfigMgr.DetailsBarData.HasFlag(eNetstatData.CTT)) { string text3 = "?"; if ((Object)(object)SNet.LocalPlayer != (Object)null) { text3 = ((int)(NetstatAPI.GetTickStat(SNet.LocalPlayer.Lookup).TickTime * 1000f)).ToString(); } list.Add("CTT " + text3 + "ms"); } string text4 = string.Join(" | ", list); TextMeshPro? detailsBar = _detailsBar; if (detailsBar != null) { ((TMP_Text)detailsBar).SetText(text4, true); } } private void GenerateGraphs() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_graphLayerTrans == (Object)null) { return; } foreach (StatGraph item in _graphStack) { Object.Destroy((Object)(object)((Component)item).gameObject); } eNetstatGraph[] values = Enum.GetValues<eNetstatGraph>(); foreach (eNetstatGraph eNetstatGraph2 in values) { if (StatConfigLib.TryGet(eNetstatGraph2, out var conf)) { _graphDict[eNetstatGraph2] = StatGraph.Create((Transform)(object)_graphLayerTrans, ConfigMgr.GraphSize, conf); } } RefreshGraphStack(); } private void RefreshGraphStack() { _graphStack.Clear(); foreach (eNetstatGraph item in ConfigMgr.GraphsInOrder) { if (_graphDict.TryGetValue(item, out StatGraph value)) { if (ConfigMgr.EnabledGraphs.HasFlag(item)) { ((Component)value).gameObject.SetActive(true); _graphStack.Add(value); } else { ((Component)value).gameObject.SetActive(false); } } } AlignGraphsVertical(); } private void AlignGraphsVertical() { //IL_0021: 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) float num = 0f; for (int i = 0; i < _graphStack.Count; i++) { _graphStack[i].RT.anchoredPosition = new Vector2(0f, num); num += _graphStack[i].Size.y + 4f; } } } } namespace Netstat.Telemetry { internal interface IPinger { static bool IsDesynced { get; } static float Ping { get; } } internal struct PingInfo { public float SendTime; public float RecvTime; public uint SeqNumber; public bool Ackd; } [HarmonyPatch] internal class ChatPinger : MonoBehaviour, IPinger { private const ulong MAGIC_NUMBER = 11474180236421424882uL; private static uint BUFFER_SIZE = 10u; private static PingInfo[] _buffer = new PingInfo[BUFFER_SIZE]; private static uint _seqNumber = 0u; private static float _lastPingReceived = 0f; private static float _ping = 0f; private static float _rawPing = 0f; private static float _jitter = 0f; private static float _rawJitter = 0f; private static bool _running = false; private static float _nextPingSendTime; public static float Ping { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _ping; } return 0f; } } public static float RawPing { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _rawPing; } return 0f; } } public static float Jitter { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _jitter; } return 0f; } } public static float RawJitter { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _rawJitter; } return 0f; } } public static bool IsDesynced { get; private set; } public static void Start() { _seqNumber = 0u; ref PingInfo reference = ref _buffer[_seqNumber]; reference.SeqNumber = _seqNumber; reference.Ackd = false; _running = true; } private static void Pause() { _running = false; } [HarmonyPatch(typeof(SNet_SessionHub), "OnJoinedLobby")] [HarmonyPrefix] private static void SNet_SessionHub_OnJoinedLobby() { Start(); } [HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")] [HarmonyPrefix] private static void SNet_SessionHub_LeaveHub() { Pause(); } private unsafe void Update() { PlayerChatManager current = PlayerChatManager.Current; if ((Object)(object)current == (Object)null) { return; } ((SNet_SyncedAction<pChatMessage>)(object)current.m_sendChatMessage).m_channelType = (SNet_ChannelType)0; if (ConfigMgr.PingerType != 0 || !_running || SNet.IsMaster || (Object)(object)SNet.Master == (Object)null) { return; } PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent(); if ((Object)(object)localPlayerAgent == (Object)null) { return; } _ = localPlayerAgent.Owner.Lookup; float now = SystemTime.Now; if (now > _nextPingSendTime) { _nextPingSendTime = now + 0.5f; if (now - _lastPingReceived > 1f) { IsDesynced = true; } ref PingInfo reference = ref _buffer[_seqNumber++ % BUFFER_SIZE]; reference.SendTime = now; reference.Ackd = false; _buffer[_seqNumber % BUFFER_SIZE].SeqNumber = _seqNumber; string text; fixed (uint* value = &reference.SeqNumber) { text = new string((char*)value, 0, 2); } SNet_Player owner = localPlayerAgent.Owner; owner.Lookup ^= 0x9F3C7A21D8B4E6F2uL; PlayerChatManager.WantToSentTextMessage(localPlayerAgent, text, (PlayerAgent)null); SNet_Player owner2 = localPlayerAgent.Owner; owner2.Lookup ^= 0x9F3C7A21D8B4E6F2uL; } } [HarmonyPatch(typeof(PlayerChatManager), "DoSendChatMessage")] [HarmonyPrefix] private unsafe static bool OnPingReceive(PlayerChatManager __instance, pChatMessage data) { //IL_0066: 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) if (!_running || SNet.IsMaster || (Object)(object)SNet.Master == (Object)null || (Object)(object)SNet.LocalPlayer == (Object)null || (data.fromPlayer.lookup ^ 0x9F3C7A21D8B4E6F2uL) != SNet.LocalPlayer.Lookup) { SNet_Core_STEAM val = ((Il2CppObjectBase)SNet.Core).TryCast<SNet_Core_STEAM>(); if ((Object)(object)val == (Object)null) { return true; } return val.m_playerLookup.ContainsKey(data.fromPlayer.lookup); } float now = SystemTime.Now; uint num; fixed (char* ptr = data.message.m_data) { num = *(uint*)ptr; } if (_buffer[_seqNumber % BUFFER_SIZE].SeqNumber - num >= BUFFER_SIZE) { return false; } PingInfo pingInfo = _buffer[num % BUFFER_SIZE]; if (pingInfo.Ackd) { return false; } pingInfo.Ackd = true; pingInfo.RecvTime = now; float num2 = Mathf.Clamp(pingInfo.RecvTime - pingInfo.SendTime, 0f, 1f); _rawJitter = Mathf.Abs(num2 - _rawPing); _rawPing = num2; _jitter += (_rawJitter - _jitter) / 16f; _ping = 0.5f * _ping + 0.5f * _rawPing; _lastPingReceived = now; IsDesynced = false; return false; } } [HarmonyPatch] internal class MarkerPinger : MonoBehaviour, IPinger { private const uint MAGIC_NUMBER = 2882400175u; private static uint BUFFER_SIZE = 10u; private static PingInfo[] _buffer = new PingInfo[BUFFER_SIZE]; private static uint _seqNumber = 0u; private static float _lastPingReceived = 0f; private static float _ping = 0f; private static float _rawPing = 0f; private static float _jitter = 0f; private static float _rawJitter = 0f; private static bool _running = false; private static int _localPlayerSlotIndex = -1; private static SyncedNavMarkerWrapper? _localPlayerNavMarker = null; private static pNavMarkerState _cachedNavMarkerState = default(pNavMarkerState); private static float _markerAutoHideTime = 0f; private static bool _shouldMarkerBeVisible = false; private static float _nextPingSendTime = 0f; public static float Ping { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _ping; } return 0f; } } public static float RawPing { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _rawPing; } return 0f; } } public static float Jitter { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _jitter; } return 0f; } } public static float RawJitter { get { if (!((Object)(object)SNet.Master == (Object)null) && !SNet.IsMaster) { return _rawJitter; } return 0f; } } public static bool IsMeasuring { get { if (_running) { return SystemTime.Now > _markerAutoHideTime; } return false; } } public static bool IsDesynced { get; private set; } public static void Start() { _seqNumber = 0u; ref PingInfo reference = ref _buffer[_seqNumber]; reference.SeqNumber = _seqNumber; reference.Ackd = false; _markerAutoHideTime = 0f; _nextPingSendTime = 0f; _running = true; } private static void Pause() { _running = false; _localPlayerSlotIndex = -1; _localPlayerNavMarker = null; } [HarmonyPatch(typeof(RundownManager), "EndGameSession")] [HarmonyPrefix] private static void RundownManager_EndGameSession() { Pause(); } [HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")] [HarmonyPrefix] private static void SNet_SessionHub_LeaveHub() { Pause(); } [HarmonyPatch(typeof(GuiManager), "AttemptSetPlayerPingStatus")] [HarmonyPrefix] private static void GuiManager_AttemptSetPlayerPingStatus(PlayerAgent sourceAgent, bool visible, Vector3 worldPos, eNavMarkerStyle style) { if (!visible) { _markerAutoHideTime = 0f; } else { _shouldMarkerBeVisible = false; } } private void Update() { //IL_0102: 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_0140: 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_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (ConfigMgr.PingerType != NetstatAPI.PingerTypeEnum.Marker || SNet.IsMaster || (Object)(object)SNet.Master == (Object)null || (Object)(object)SNet.LocalPlayer == (Object)null) { return; } _localPlayerSlotIndex = SNet.LocalPlayer.PlayerSlotIndex(); GuiManager current = GuiManager.Current; _localPlayerNavMarker = ((current == null) ? null : ((Il2CppArrayBase<SyncedNavMarkerWrapper>)(object)current.m_playerPings)?[_localPlayerSlotIndex]); if ((Object)(object)_localPlayerNavMarker == (Object)null || !_running) { return; } float now = SystemTime.Now; if (now > _markerAutoHideTime) { if (now > _nextPingSendTime) { _nextPingSendTime = now + 0.5f; if (now - _lastPingReceived > 1f) { IsDesynced = true; } ref PingInfo reference = ref _buffer[_seqNumber++ % BUFFER_SIZE]; reference.SendTime = now; reference.Ackd = false; _buffer[_seqNumber % BUFFER_SIZE].SeqNumber = _seqNumber; pNavMarkerInteraction val = default(pNavMarkerInteraction); val.type = (eNavMarkerInteractionType)1; val.worldPos.x = BitConverter.UInt32BitsToSingle(2882400175u); val.worldPos.y = Unsafe.As<uint, float>(ref reference.SeqNumber); pNavMarkerState val2 = default(pNavMarkerState); val2.status = (eNavMarkerStatus)1; val2.worldPos = val.worldPos; val2.terminalItemId = val.terminalItemId; SNet_StateReplicator<pNavMarkerState, pNavMarkerInteraction> stateReplicator = _localPlayerNavMarker.m_stateReplicator; stateReplicator.m_statePacket_Recall.Send(val2, stateReplicator.m_channelType, SNet.Master); stateReplicator.m_interactionPacket.Send(val, stateReplicator.m_channelType, SNet.Master); } } else { _lastPingReceived = now; } } [HarmonyPatch(typeof(SyncedNavMarkerWrapper), "OnStateChange")] [HarmonyPrefix] private static void OnRecievePingStatus(SyncedNavMarkerWrapper __instance, pNavMarkerState oldState, pNavMarkerState newState, bool isDropinState) { //IL_0045: 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) //IL_0076: 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_007d: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00b3: 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_00d4: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsMaster || (Object)(object)SNet.Master == (Object)null || isDropinState || !_running || __instance.m_playerIndex != _localPlayerSlotIndex) { return; } float now = SystemTime.Now; if (!_shouldMarkerBeVisible && now > _markerAutoHideTime && (int)newState.status == 0) { _cachedNavMarkerState = newState; _markerAutoHideTime = now + __instance.AutoHideDelay; _shouldMarkerBeVisible = true; } else if (_shouldMarkerBeVisible && now <= _markerAutoHideTime && (int)newState.status == 1 && (int)_cachedNavMarkerState.status == 0) { pNavMarkerInteraction val = default(pNavMarkerInteraction); val.type = (eNavMarkerInteractionType)0; val.style = _cachedNavMarkerState.style; val.worldPos = _cachedNavMarkerState.worldPos; val.terminalItemId = _cachedNavMarkerState.terminalItemId; __instance.m_stateReplicator.AttemptInteract(val); } else { if (Unsafe.As<float, uint>(ref newState.worldPos.x) != 2882400175u) { return; } uint num = Unsafe.As<float, uint>(ref newState.worldPos.y); if (_buffer[_seqNumber % BUFFER_SIZE].SeqNumber - num < BUFFER_SIZE) { PingInfo pingInfo = _buffer[num % BUFFER_SIZE]; if (!pingInfo.Ackd) { pingInfo.Ackd = true; pingInfo.RecvTime = now; float num2 = Mathf.Clamp(pingInfo.RecvTime - pingInfo.SendTime, 0f, 1f); _rawJitter = Mathf.Abs(num2 - _rawPing); _rawPing = num2; _jitter += (_rawJitter - _jitter) / 16f; _ping = 0.5f * _ping + 0.5f * _rawPing; _lastPingReceived = now; IsDesynced = false; } } } } } public struct ChannelStats { public uint _accumulatedBytesReceived; public uint BytesReceived; public uint _accumulatedPacketsReceived; public uint PacketsReceived; public uint _accumulatedBytesSent; public uint BytesSent; public uint _accumulatedPacketsSent; public uint PacketsSent; public ChannelStats() { _accumulatedBytesReceived = 0u; BytesReceived = 0u; _accumulatedPacketsReceived = 0u; PacketsReceived = 0u; _accumulatedBytesSent = 0u; BytesSent = 0u; _accumulatedPacketsSent = 0u; PacketsSent = 0u; } } [HarmonyPatch] internal class SteamP2P : MonoBehaviour { private static float _nextPollTimestamp = 0f; private static ChannelStats[] _channels = new ChannelStats[Enum.GetValues(typeof(SNet_ChannelType)).Length]; public static ReadOnlySpan<ChannelStats> Channels => _channels; public static uint BytesReceived { get; private set; } public static uint PacketsReceived { get; private set; } public static uint BytesSent { get; private set; } public static uint PacketsSent { get; private set; } public static int BytesQueuedForSend { get; private set; } public static int PacketsQueuedForSend { get; private set; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] private static void SteamNetworking_ReadP2PPacket(Il2CppStructArray<byte> pubDest, uint cubDest, uint pcubMsgSize, CSteamID psteamIDRemote, int nChannel) { if (nChannel >= 0 && nChannel < _channels.Length) { ref ChannelStats reference = ref _channels[nChannel]; reference._accumulatedBytesReceived += pcubMsgSize; reference._accumulatedPacketsReceived++; } } [HarmonyPatch(typeof(SteamNetworking), "SendP2PPacket")] [HarmonyPrefix] private static void SteamNetworking_SendP2PPacket(CSteamID steamIDRemote, Il2CppStructArray<byte> pubData, uint cubData, EP2PSend eP2PSendType, int nChannel) { if (nChannel >= 0 && nChannel < _channels.Length) { ref ChannelStats reference = ref _channels[nChannel]; reference._accumulatedBytesSent += cubData; reference._accumulatedPacketsSent++; } } private void Update() { //IL_0036: 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_0059: Unknown result type (might be due to invalid IL or missing references) BytesQueuedForSend = 0; PacketsQueuedForSend = 0; Enumerator<SNet_Player> enumerator = SNet.LobbyPlayers.GetEnumerator(); P2PSessionState_t val = default(P2PSessionState_t); while (enumerator.MoveNext()) { SNet_Player current = enumerator.Current; if (!current.IsLocal && !current.IsBot) { SteamNetworking.GetP2PSessionState(new CSteamID(current.Lookup), ref val); BytesQueuedForSend += val.m_nBytesQueuedForSend; PacketsQueuedForSend += val.m_nPacketsQueuedForSend; } } float now = SystemTime.Now; if (now > _nextPollTimestamp) { _nextPollTimestamp = now + 1f; BytesReceived = 0u; PacketsReceived = 0u; BytesSent = 0u; PacketsSent = 0u; for (int i = 0; i < _channels.Length; i++) { ref ChannelStats reference = ref _channels[i]; reference.BytesReceived = (uint)((float)reference._accumulatedBytesReceived * 1f); reference._accumulatedBytesReceived = 0u; reference.PacketsReceived = (uint)((float)reference._accumulatedPacketsReceived * 1f); reference._accumulatedPacketsReceived = 0u; reference.BytesSent = (uint)((float)reference._accumulatedBytesSent * 1f); reference._accumulatedBytesSent = 0u; reference.PacketsSent = (uint)((float)reference._accumulatedPacketsSent * 1f); reference._accumulatedPacketsSent = 0u; BytesReceived += reference.BytesReceived; PacketsReceived += reference.PacketsReceived; BytesSent += reference.BytesSent; PacketsSent += reference.PacketsSent; } } } public static string SNetChannelType2Str(SNet_ChannelType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown return (int)t switch { 5 => "BotCmds", 4 => "NonCrit", 2 => "Crit", 3 => "RecvCrit", 1 => "SessMig", 0 => "SessCrit", _ => "???", }; } public static string SNetChannelType2StrShort(SNet_ChannelType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown return (int)t switch { 5 => "BC", 4 => "NC", 2 => "CR", 3 => "RC", 1 => "SM", 0 => "SC", _ => "???", }; } } internal class SystemTime { private static long _startTimestamp = _unixMs; private static long _unixMs => ((DateTimeOffset)DateTime.Now).ToUnixTimeMilliseconds(); public static float Now => (float)(_unixMs - _startTimestamp) / 1000f; } public struct TickStats { public ulong SteamId; public float _lastTickTimestamp; public float TickTime; public float RawTickTime; public bool IsMeasuring; public TickStats(ulong steamId) { SteamId = 0uL; _lastTickTimestamp = 0f; TickTime = 0f; RawTickTime = 0f; IsMeasuring = false; SteamId = steamId; } } [HarmonyPatch] internal class TickTimer : MonoBehaviour { private static Dictionary<ulong, TickStats> _playerTicks = new Dictionary<ulong, TickStats>(); private static void Measure(ref TickStats info) { float now = SystemTime.Now; if (info.IsMeasuring) { info.RawTickTime = now - info._lastTickTimestamp; info.TickTime = 0.5f * info.TickTime + 0.5f * info.RawTickTime; } info.IsMeasuring = true; info._lastTickTimestamp = now; } [HarmonyPatch(typeof(PlayerSync), "IncomingLocomotion")] [HarmonyPrefix] private static void PlayerSync_IncomingLocomotion(PlayerSync __instance, pPlayerLocomotion data) { SNet_Player owner = __instance.m_agent.Owner; if (!owner.IsBot && !owner.IsLocal) { ulong lookup = owner.Lookup; TickStats info = GetTickStat(lookup); float num = ((SFloat8)(ref data.VelRight)).Get(10f); float num2 = ((SFloat8)(ref data.VelFwd)).Get(10f); if (num * num + num2 * num2 < 1f) { info.IsMeasuring = false; _playerTicks[lookup] = info; } else { Measure(ref info); _playerTicks[lookup] = info; } } } [HarmonyPatch(typeof(PlayerSync), "SendLocomotion")] [HarmonyPrefix] private static void PlayerSync_SendLocomotion(PlayerSync __instance, PLOC_State state, Vector3 pos, Vector3 lookDir, float velFwd, float velRight) { SNet_Player owner = __instance.m_agent.Owner; if (!owner.IsBot && owner.IsLocal) { ulong lookup = owner.Lookup; TickStats info = GetTickStat(lookup); Measure(ref info); _playerTicks[lookup] = info; } } [HarmonyPatch(typeof(PLOC_ClimbLadder), "Exit")] [HarmonyPrefix] private static void PLOC_ClimbLadder_Exit(PLOC_ClimbLadder __instance) { CommonLadderExit(__instance); } [HarmonyPatch(typeof(PLOC_ClimbLadder), "SyncExit")] [HarmonyPrefix] private static void PLOC_ClimbLadder_SyncExit(PLOC_ClimbLadder __instance) { CommonLadderExit(__instance); } private static void CommonLadderExit(PLOC_ClimbLadder __instance) { SNet_Player owner = ((PLOC_Base)__instance).m_owner.Owner; if (!owner.IsBot && owner.IsLocal) { ulong lookup = owner.Lookup; TickStats tickStat = GetTickStat(lookup); tickStat.IsMeasuring = false; _playerTicks[lookup] = tickStat; } } public static TickStats GetTickStat(ulong steamId) { if (!_playerTicks.ContainsKey(steamId)) { _playerTicks.Add(steamId, new TickStats(steamId)); } return _playerTicks[steamId]; } public static void Start() { _playerTicks.Clear(); } private static void Pause() { _playerTicks.Clear(); } [HarmonyPatch(typeof(RundownManager), "EndGameSession")] [HarmonyPrefix] private static void RundownManager_EndGameSession() { Pause(); } [HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")] [HarmonyPrefix] private static void SNet_SessionHub_LeaveHub() { Pause(); } } } namespace Netstat.Grapher { public sealed class Plotter : Graphic { [Flags] public enum PlotComponent { None = 0, Line = 1, Fill = 2, Background = 4, Border = 8, Standard = 0xF, StandardNoBorder = 7, StandardNoFill = 0xD } private struct ChannelStyle { public bool DrawLine; public float LineThickness; public Color LineColor; public bool DrawFill; public float FillChunkWidth; public Color FillColor; public ChannelStyle() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) DrawLine = true; LineThickness = 2f; LineColor = new Color(0.85f, 0.85f, 0.85f, 1f); DrawFill = false; FillChunkWidth = 3f; FillColor = new Color(1f, 1f, 1f, 0.25f); } } private int _capacity = 120; private float _minY; private float _maxY; private bool _autoScale; private float _autoscaleInc = -1f; private float _autoScaleLerp = 0.35f; private bool _logScale; private Vector2 _plotSize = new Vector2(200f, 100f); private bool _drawBackground = true; private bool _drawBorder = true; private float _borderThickness = 1f; private int _channelCount = 1; private ChannelStyle[] _styles = new ChannelStyle[0]; private float[,] _samples = new float[0, 0]; private int[] _heads = new int[0]; private int[] _counts = new int[0]; private float[] _maxObserved = new float[0]; private bool _dirty; private int _lineResolution = 4; private float _clearance; private float _dispMax; public Vector2 PlotSize { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _plotSize; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) _plotSize = value; ((Graphic)this).rectTransform.sizeDelta = new Vector2(_plotSize.x, _plotSize.y + _clearance); MarkDirty(); } } public Vector2 Size => ((Graphic)this).rectTransform.sizeDelta; public Color BgColor { get; private set; } = new Color(0f, 0f, 0f, 0.35f); public Color BorderColor { get; private set; } = new Color(1f, 1f, 1f, 0.35f); public int Capacity => _capacity; public float MinY { get { return _minY; } set { _minY = value; MarkDirty(); } } public float MaxY { get { return _maxY; } set { _maxY = value; _dispMax = value; MarkDirty(); } } public float DisplayMaxY => _dispMax; public event Action<Graphic, VertexHelper>? AfterPopulateMesh; public override void Awake() { EnsureBuffer(); _dispMax = _maxY; } public void SetStyle(PlotComponent style, int channel = 0) { _styles[channel].DrawLine = style.HasFlag(PlotComponent.Line); _styles[channel].DrawFill = style.HasFlag(PlotComponent.Fill); _drawBackground = style.HasFlag(PlotComponent.Background); _drawBorder = style.HasFlag(PlotComponent.Border); MarkDirty(); } public void SetColor(PlotComponent comp, Color c, int channel = 0) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (comp.HasFlag(PlotComponent.Line)) { _styles[channel].LineColor = c; } if (comp.HasFlag(PlotComponent.Fill)) { _styles[channel].FillColor = c; } if (comp.HasFlag(PlotComponent.Background)) { BgColor = c; } if (comp.HasFlag(PlotComponent.Border)) { BorderColor = c; } MarkDirty(); } public void SetThickness(PlotComponent comp, float thickness, int channel = 0) { if (comp.HasFlag(PlotComponent.Line)) { _styles[channel].LineThickness = Mathf.Max(1f, thickness); } if (comp.HasFlag(PlotComponent.Fill)) { _styles[channel].FillChunkWidth = Mathf.Max(0f, thickness); } if (comp.HasFlag(PlotComponent.Border)) { _borderThickness = Mathf.Max(0f, thickness); } MarkDirty(); } public void SetGraphMinMax(float min, float max) { _minY = min; _maxY = max; _dispMax = max; MarkDirty(); } public void SetLogScale(bool enable) { _logScale = enable; MarkDirty(); } public void SetSampleCapacity(int capacity) { _capacity = Mathf.Max(8, capacity); EnsureBuffer(); MarkDirty(); } public void SetAutoScale(bool enable) { _autoScale = enable; MarkDirty(); } public void SetAutoScaleIncrement(float increment) { _autoscaleInc = increment; MarkDirty(); } public void SetAutoScaleLerp(float lerp) { _autoScaleLerp = Mathf.Clamp01(lerp); MarkDirty(); } public void SetClearance(float clearance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) _clearance = clearance; ((Graphic)this).rectTransform.sizeDelta = new Vector2(_plotSize.x, _plotSize.y + _clearance); MarkDirty(); } public void SetLineResolution(int resolution) { _lineResolution = Mathf.Max(1, resolution); MarkDirty(); } public void AllocateChannels(int channelCount) { _channelCount = Mathf.Max(1, channelCount); EnsureBuffer(); } private void EnsureBuffer() { if (_styles.Length != _channelCount || _samples.Length != _capacity * _channelCount) { _styles = new ChannelStyle[_channelCount]; for (int i = 0; i < _styles.Length; i++) { _styles[i] = new ChannelStyle(); } _samples = new float[_channelCount, _capacity]; _heads = new int[_channelCount]; Array.Fill(_heads, _capacity - 1); _counts = new int[_channelCount]; _maxObserved = new float[_channelCount]; _dirty = true; } } public void PushSample(float value, int channel = 0) { EnsureBuffer(); _heads[channel] = (_heads[channel] + 1) % _capacity; _samples[channel, _heads[channel]] = value; if (_counts[channel] < _capacity) { _counts[channel]++; } if (_autoScale) { float num = _minY + 0.0001f; for (int i = 0; i < _counts[channel]; i++) { float sampleReverse = GetSampleReverse(i, channel); if (sampleReverse > num) { num = sampleReverse; } } _maxObserved[channel] = Mathf.Max(num, _minY + 0.0001f); float num2 = _minY + 0.0001f; for (int j = 0; j < _channelCount; j++) { if (_maxObserved[j] > num2) { num2 = _maxObserved[j]; } } float num3 = num2; if (_autoscaleInc > 0f) { num3 = Mathf.Ceil((num2 - _minY) / _autoscaleInc) * _autoscaleInc + _minY; } _dispMax = Mathf.Lerp(_dispMax, num3, _autoScaleLerp); _dispMax = Mathf.Max(Mathf.Max(_dispMax, _minY + 0.0001f), _maxY); } MarkDirty(); } public void Clear() { Array.Clear(_samples); for (int i = 0; i < _channelCount; i++) { _heads[i] = _capacity - 1; _counts[i] = 0; _maxObserved[i] = _minY; } MarkDirty(); } private void MarkDirty() { if (!_dirty) { _dirty = true; ((Graphic)this).SetVerticesDirty(); } } private float GetSample(int i, int channel = 0) { int n = _heads[channel] + 1 + i; n = Util.TrueMod(n, _capacity); if (!_logScale) { return _samples[channel, n]; } return Mathf.Log(_samples[channel, n]); } private float GetSampleReverse(int i, int channel = 0) { int n = _heads[channel] - i; n = Util.TrueMod(n, _capacity); if (!_logScale) { return _samples[channel, n]; } return Mathf.Log(_samples[channel, n]); } public override void OnPopulateMesh(VertexHelper vh) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0185: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: 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_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) vh.Clear(); _dirty = false; Rect pixelAdjustedRect = ((Graphic)this).GetPixelAdjustedRect(); if (((Rect)(ref pixelAdjustedRect)).width <= 1f || ((Rect)(ref pixelAdjustedRect)).height <= 1f) { return; } if (_drawBackground) { AddRect(vh, pixelAdjustedRect, BgColor); } Vector2 val2 = default(Vector2); for (int i = 0; i < _channelCount; i++) { ChannelStyle channelStyle = _styles[i]; if (_counts[i] <= 1) { continue; } float num = (_autoScale ? _dispMax : _maxY); num = Mathf.Max(num, _minY + 0.0001f); float xMin = ((Rect)(ref pixelAdjustedRect)).xMin; float xMax = ((Rect)(ref pixelAdjustedRect)).xMax; float yMin = ((Rect)(ref pixelAdjustedRect)).yMin; float num2 = ((Rect)(ref pixelAdjustedRect)).yMax - _clearance; int capacity = _capacity; float num3 = (xMax - xMin) / (float)(capacity - 1); float num4 = 1f / (num - _minY); if (channelStyle.DrawFill) { float num5 = Mathf.Min(channelStyle.FillChunkWidth * 0.5f, num3 * 0.5f); for (int j = 0; j < capacity; j++) { float num6 = Mathf.Clamp01((GetSample(j, i) - _minY) * num4); float num7 = xMin + num3 * (float)j; float num8 = Mathf.Lerp(yMin, num2, num6); Rect r = Rect.MinMaxRect(num7 - num5, yMin, num7 + num5, num8); AddRect(vh, r, channelStyle.FillColor); } } if (!channelStyle.DrawLine) { continue; } float halfThickness = channelStyle.LineThickness * 0.5f; Vector2 val = default(Vector2); for (int k = 0; k < capacity; k++) { float num9 = Mathf.Clamp01((GetSample(k, i) - _minY) * num4); float num10 = xMin + num3 * (float)k; float num11 = Mathf.Lerp(yMin, num2, num9); ((Vector2)(ref val2))..ctor(num10, num11); if (k > 0) { for (int l = 1; l <= _lineResolution; l++) { float num12 = (float)l / (float)_lineResolution; Vector2 b = Vector2.Lerp(val, val2, num12); Vector2 a = Vector2.Lerp(val, val2, (float)(l - 1) / (float)_lineResolution); AddThickSegment(vh, a, b, halfThickness, channelStyle.LineColor); } } val = val2; } } if (_drawBorder && _borderThickness > 0f) { AddBorder(vh, pixelAdjustedRect, _borderThickness, BorderColor); } this.AfterPopulateMesh?.Invoke((Graphic)(object)this, vh); } public static void AddRect(VertexHelper vh, Rect r, Color c) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_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_002a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //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_0076: 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_0080: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) int currentVertCount = vh.currentVertCount; UIVertex simpleVert = UIVertex.simpleVert; simpleVert.color = Color32.op_Implicit(c); simpleVert.position = Vector2.op_Implicit(new Vector2(((Rect)(ref r)).xMin, ((Rect)(ref r)).yMin)); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(new Vector2(((Rect)(ref r)).xMin, ((Rect)(ref r)).yMax)); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(new Vector2(((Rect)(ref r)).xMax, ((Rect)(ref r)).yMax)); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(new Vector2(((Rect)(ref r)).xMax, ((Rect)(ref r)).yMin)); vh.AddVert(simpleVert); vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); vh.AddTriangle(currentVertCount + 2, currentVertCount + 3, currentVertCount); } private static void AddBorder(VertexHelper vh, Rect r, float thickness, Color c) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) AddRect(vh, Rect.MinMaxRect(((Rect)(ref r)).xMin, ((Rect)(ref r)).yMax - thickness, ((Rect)(ref r)).xMax, ((Rect)(ref r)).yMax), c); AddRect(vh, Rect.MinMaxRect(((Rect)(ref r)).xMin, ((Rect)(ref r)).yMin, ((Rect)(ref r)).xMax, ((Rect)(ref r)).yMin + thickness), c); AddRect(vh, Rect.MinMaxRect(((Rect)(ref r)).xMin, ((Rect)(ref r)).yMin, ((Rect)(ref r)).xMin + thickness, ((Rect)(ref r)).yMax), c); AddRect(vh, Rect.MinMaxRect(((Rect)(ref r)).xMax - thickness, ((Rect)(ref r)).yMin, ((Rect)(ref r)).xMax, ((Rect)(ref r)).yMax), c); } private static void AddThickSegment(VertexHelper vh, Vector2 a, Vector2 b, float halfThickness, Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0034: 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_003a: 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_003c: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_004b: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) Vector2 val = b - a; float magnitude = ((Vector2)(ref val)).magnitude; if (!(magnitude < 0.0001f)) { val /= magnitude; Vector2 val2 = new Vector2(0f - val.y, val.x) * halfThickness; Vector2 val3 = a - val2; Vector2 val4 = a + val2; Vector2 val5 = b + val2; Vector2 val6 = b - val2; int currentVertCount = vh.currentVertCount; UIVertex simpleVert = UIVertex.simpleVert; simpleVert.color = Color32.op_Implicit(c); simpleVert.position = Vector2.op_Implicit(val3); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(val4); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(val5); vh.AddVert(simpleVert); simpleVert.position = Vector2.op_Implicit(val6); vh.AddVert(simpleVert); vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); vh.AddTriangle(currentVertCount + 2, currentVertCount + 3, currentVertCount); } } } } namespace Netstat.Config { public enum ConfigEntryRule { Min, Max } public class ConfigEntryExtended<T> { private Dictionary<ConfigEntryRule, T> _rules = new Dictionary<ConfigEntryRule, T>(); private ConfigEntry<T> _entry; public T Value { get { return _entry.Value; } set { _entry.Value = Enforce(value); } } public object BoxedValue { get { return ((ConfigEntryBase)_entry).BoxedValue; } set { ((ConfigEntryBase)_entry).BoxedValue = Enforce((T)value); } } public ConfigEntryExtended(ConfigEntry<T> entry) { _entry = entry; } public bool AddRule(ConfigEntryRule rule, T ruleValue) { if (_rules.TryAdd(rule, ruleValue)) { Enforce(rule); return true; } return false; } private void Enforce() { T val = Enforce(_entry.Value); if (val != null && !val.Equals(_entry.Value)) { _entry.Value = val; } } private T Enforce(T val) { foreach (var (configEntryRule2, val3) in _rules) { switch (configEntryRule2) { case ConfigEntryRule.Min: if (Comparer<T>.Default.Compare(val, val3) < 0) { val = val3; } break; case ConfigEntryRule.Max: if (Comparer<T>.Default.Compare(val, val3) > 0) { val = val3; } break; } } return val; } private void Enforce(ConfigEntryRule rule) { T value = _entry.Value; value = Enforce(value, rule); if (value != null && !value.Equals(_entry.Value)) { _entry.Value = value; } } private T Enforce(T val, ConfigEntryRule rule) { if (!_rules.TryGetValue(rule, out var value)) { return val; } switch (rule) { case ConfigEntryRule.Min: if (Comparer<T>.Default.Compare(val, value) < 0) { val = value; } break; case ConfigEntryRule.Max: if (Comparer<T>.Default.Compare(val, value) > 0) { val = value; } break; } return val; } public static implicit operator ConfigEntryExtended<T>(ConfigEntry<T> entry) { return new ConfigEntryExtended<T>(entry); } } internal static class ConfigMgr { private static readonly ConfigFile Conf; private static readonly FileSystemWatcher? ConfigWatcher; private static readonly ConfigEntryExtended<bool> DebugConf; private static readonly ConfigEntryExtended<NetstatAPI.PingerTypeEnum> PingerTypeConf; private static readonly ConfigEntryExtended<float> UIAnchorXConf; private static readonly ConfigEntryExtended<float> UIAnchorYConf; private static readonly ConfigEntryExtended<float> UIAnchorOffsetXConf; private static readonly ConfigEntryExtended<float> UIAnchorOffsetYConf; private static readonly ConfigEntryExtended<bool> GraphEnabledConf; private static readonly ConfigEntryExtended<KeyCode> GraphToggleKeyConf; private static readonly ConfigEntryExtended<float> GraphSizeXConf; private static readonly ConfigEntryExtended<float> GraphSizeYConf; private static readonly ConfigEntryExtended<eNetstatGraph> EnabledGraphsConf; private static readonly ConfigEntryExtended<string> GraphsOrderConf; private static readonly ConfigEntryExtended<bool> DetailsBarEnabledConf; private static readonly ConfigEntryExtended<eNetstatData> DetailsBarDataConf; public static bool Processed { get; private set; } public static bool Debug => DebugConf.Value; public static NetstatAPI.PingerTypeEnum PingerType => PingerTypeConf.Value; public static Vector2 UIAnchor => new Vector2(UIAnchorXConf.Value, UIAnchorYConf.Value); public static Vector2 UIAnchorOffset => new Vector2(UIAnchorOffsetXConf.Value, UIAnchorOffsetYConf.Value); public static bool EnableGraphs { get { return GraphEnabledConf.Value; } set { GraphEnabledConf.Value = value; } } public static KeyCode GraphToggleKey => GraphToggleKeyConf.Value; public static Vector2 GraphSize => new Vector2(GraphSizeXConf.Value, GraphSizeYConf.Value); public static eNetstatGraph EnabledGraphs => EnabledGraphsConf.Value; public static List<eNetstatGraph> GraphsInOrder { get; } public static bool DetailsBarEnabled => DetailsBarEnabledConf.Value; public static eNetstatData DetailsBarData => DetailsBarDataConf.Value; public static void Init() { Logger.Info($"debug={Debug}"); Process(); } public static void Process() { GraphsInOrder.Clear(); eNetstatGraph[] array = GraphsOrderConf.Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(StatConfigLib.Str2GraphType).ToArray(); foreach (eNetstatGraph eNetstatGraph in array) { if (!Enum.IsDefined(eNetstatGraph)) { Logger.Warn($"Invalid graph type in Graphs Order config: {eNetstatGraph}"); } else if (!GraphsInOrder.Contain