Decompiled source of Scoreboard v1.2.2

BepInEx/plugins/Scoreboard.dll

Decompiled 21 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using Scoreboard.Config;
using Scoreboard.Data;
using Scoreboard.Networking;
using Scoreboard.Tracking;
using Scoreboard.UI;
using Sparroh.UI;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: AssemblyInformationalVersion("1.2.2")]
[assembly: AssemblyProduct("Scoreboard")]
[assembly: AssemblyTitle("Scoreboard")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[BepInPlugin("sparroh.scoreboard", "Scoreboard", "1.2.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class ScoreboardPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.scoreboard";

	public const string PluginName = "Scoreboard";

	public const string PluginVersion = "1.2.2";

	internal static ManualLogSource Log;

	internal static ScoreboardPlugin Instance;

	private Harmony _harmony;

	private ScoreboardUI _ui;

	private bool _wasHeld;

	private void Awake()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Log);
		_harmony = new Harmony("sparroh.scoreboard");
		try
		{
			_harmony.PatchAll(typeof(MissionStatPatches).Assembly);
			Log.LogInfo((object)"Scoreboard v1.2.2 loaded.");
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Harmony patch failed: {arg}");
		}
		ScoreboardNetwork.Initialize();
	}

	private void Update()
	{
		ConfigManager.Tick();
		if (ConfigManager.Enabled == null || !ConfigManager.Enabled.Value)
		{
			if (_wasHeld)
			{
				_ui?.Hide();
				_wasHeld = false;
			}
			return;
		}
		bool flag = IsHoldKeyPressed();
		if (flag && !_wasHeld)
		{
			if (_ui == null)
			{
				_ui = new ScoreboardUI();
			}
			_ui.Show();
		}
		else if (!flag && _wasHeld)
		{
			_ui?.Hide();
		}
		else if (flag)
		{
			_ui?.Tick();
		}
		_wasHeld = flag;
		if (ConfigManager.NetworkingEnabled != null && ConfigManager.NetworkingEnabled.Value)
		{
			ScoreboardNetwork.Tick();
		}
	}

	private void OnDestroy()
	{
		try
		{
			_ui?.Destroy();
			_ui = null;
			ScoreboardNetwork.Shutdown();
			ConfigManager.Dispose();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
		catch (Exception arg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)$"Cleanup error: {arg}");
			}
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private bool IsHoldKeyPressed()
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((GameManager.players == null || GameManager.players.Count == 0) && (Object)(object)Player.LocalPlayer == (Object)null)
			{
				return false;
			}
			Key value = ConfigManager.HoldKey.Value;
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return false;
			}
			return ((ButtonControl)current[value]).isPressed;
		}
		catch
		{
			return false;
		}
	}
}
namespace Scoreboard
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Scoreboard";

		public const string PLUGIN_NAME = "Scoreboard";

		public const string PLUGIN_VERSION = "1.2.2";
	}
}
namespace Scoreboard.UI
{
	internal static class ScoreboardDataBuilder
	{
		public static void Build(List<ScoreboardRow> buffer)
		{
			buffer.Clear();
			try
			{
				List<Player> players = GameManager.players;
				if (players == null || players.Count == 0)
				{
					return;
				}
				for (int i = 0; i < players.Count; i++)
				{
					Player val = players[i];
					if (!((Object)(object)val == (Object)null))
					{
						ScoreboardRow scoreboardRow = new ScoreboardRow
						{
							ClientId = ((NetworkBehaviour)val).OwnerClientId,
							UserId = val.UserID,
							PlayerNumber = val.PlayerNumber,
							Name = (string.IsNullOrEmpty(val.Name) ? $"Player {val.PlayerNumber + 1}" : val.Name),
							IsLocal = ((NetworkBehaviour)val).IsLocalPlayer,
							IsAlive = val.IsAlive
						};
						int pingMs = PlayerPresentation.GetPingMs(val);
						int pingMs2;
						if (pingMs >= 0)
						{
							scoreboardRow.PingMs = pingMs;
						}
						else if (ScoreboardNetwork.TryGetRemotePing(((NetworkBehaviour)val).OwnerClientId, out pingMs2))
						{
							scoreboardRow.PingMs = pingMs2;
						}
						else
						{
							scoreboardRow.PingMs = -1;
						}
						PlayerPresentation.FillCharacterVisuals(val, scoreboardRow);
						PlayerPresentation.FillGearIcons(val, scoreboardRow);
						PlayerStatsSnapshot snapshot;
						if (scoreboardRow.IsLocal)
						{
							MissionStatTracker.FillLocalStats(scoreboardRow);
						}
						else if (ScoreboardNetwork.TryGetRemoteStats(scoreboardRow.ClientId, out snapshot))
						{
							snapshot.ApplyTo(scoreboardRow);
						}
						else
						{
							scoreboardRow.HasStats = false;
						}
						buffer.Add(scoreboardRow);
					}
				}
				buffer.Sort(delegate(ScoreboardRow a, ScoreboardRow b)
				{
					int num = b.CoreKills.CompareTo(a.CoreKills);
					if (num != 0)
					{
						return num;
					}
					num = a.PlayerNumber.CompareTo(b.PlayerNumber);
					return (num != 0) ? num : string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
				});
			}
			catch (Exception arg)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"Scoreboard data build failed: {arg}");
				}
			}
		}

		public static void Apply(List<ScoreboardRow> dataBuffer, List<ScoreboardRowView> rows, UIText subtitleText)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: 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_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: 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_0459: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			try
			{
				flag = (Object)(object)MissionManager.Instance != (Object)null && MissionManager.Instance.IsMissionActive;
			}
			catch
			{
			}
			string text = (flag ? "MISSION" : ((!MissionStatTracker.HasSession) ? "LOBBY" : "LAST MISSION"));
			if (subtitleText != null)
			{
				int modPeerCount = ScoreboardNetwork.ModPeerCount;
				string text2 = ((!ScoreboardNetwork.IsNetworkingEnabled) ? string.Empty : ((modPeerCount > 1) ? $" ·  {modPeerCount} synced" : " ·  solo/net"));
				subtitleText.Text = string.Format("{0}  ·  {1} player{2}{3}", text, dataBuffer.Count, (dataBuffer.Count == 1) ? "" : "s", text2);
			}
			for (int i = 0; i < rows.Count; i++)
			{
				if (i >= dataBuffer.Count)
				{
					rows[i].Root.SetActive(false);
					continue;
				}
				ScoreboardRow scoreboardRow = dataBuffer[i];
				ScoreboardRowView scoreboardRowView = rows[i];
				scoreboardRowView.Root.SetActive(true);
				Color color = (scoreboardRow.IsLocal ? UIColors.Sky : UIColors.TextPrimary);
				if (!scoreboardRow.IsAlive)
				{
					color = UIColors.TextMuted;
				}
				string value = (scoreboardRow.IsLocal ? ("> " + scoreboardRow.Name) : scoreboardRow.Name);
				SetText(scoreboardRowView.NameText, value, color);
				ApplyIcon(scoreboardRowView.ClassIcon, scoreboardRow.CharacterIcon, (Color)(scoreboardRow.IsAlive ? new Color(scoreboardRow.CharacterColorR, scoreboardRow.CharacterColorG, scoreboardRow.CharacterColorB, scoreboardRow.CharacterColorA) : UIColors.TextMuted));
				object obj2;
				if (!((Object)(object)scoreboardRowView.ClassIcon != (Object)null) || !((Object)(object)((Component)scoreboardRowView.ClassIcon).transform.parent != (Object)null))
				{
					Image classIcon = scoreboardRowView.ClassIcon;
					obj2 = ((classIcon != null) ? ((Component)classIcon).gameObject : null);
				}
				else
				{
					obj2 = ((Component)((Component)scoreboardRowView.ClassIcon).transform.parent).gameObject;
				}
				GameObject val = (GameObject)obj2;
				if ((Object)(object)val != (Object)null)
				{
					SetTooltip(val, string.IsNullOrEmpty(scoreboardRow.CharacterTooltip) ? scoreboardRow.CharacterName : scoreboardRow.CharacterTooltip);
				}
				if ((Object)(object)scoreboardRow.CharacterIcon == (Object)null)
				{
					SetText(scoreboardRowView.ClassText, string.IsNullOrEmpty(scoreboardRow.CharacterName) ? "—" : scoreboardRow.CharacterName, (Color)(scoreboardRow.IsAlive ? new Color(scoreboardRow.CharacterColorR, scoreboardRow.CharacterColorG, scoreboardRow.CharacterColorB, scoreboardRow.CharacterColorA) : UIColors.TextMuted));
					scoreboardRowView.ClassText.GameObject.SetActive(true);
				}
				else
				{
					scoreboardRowView.ClassText.GameObject.SetActive(false);
				}
				ApplyGearSlot(scoreboardRowView.Gear0, scoreboardRow.GearIcon0, scoreboardRow.GearName0);
				ApplyGearSlot(scoreboardRowView.Gear1, scoreboardRow.GearIcon1, scoreboardRow.GearName1);
				ApplyGearSlot(scoreboardRowView.Gear3, scoreboardRow.GearIcon3, scoreboardRow.GearName3);
				SetText(scoreboardRowView.StatKills, ScoreboardRow.FormatStat(scoreboardRow.CoreKills, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.Rose));
				SetText(scoreboardRowView.StatTgt, ScoreboardRow.FormatStat(scoreboardRow.TargetKills, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.Orchid));
				SetText(scoreboardRowView.StatDmg, ScoreboardRow.FormatStat(scoreboardRow.Damage, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.Macaroon));
				SetText(scoreboardRowView.StatHeal, ScoreboardRow.FormatStat(scoreboardRow.Healing, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.Shamrock));
				SetText(scoreboardRowView.StatDth, ScoreboardRow.FormatStat(scoreboardRow.Deaths, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.TextSecondary));
				SetText(scoreboardRowView.StatRev, ScoreboardRow.FormatStat(scoreboardRow.Revives, scoreboardRow.HasStats), StatColor(scoreboardRow, UIColors.Electric));
				SetText(scoreboardRowView.StatPing, ScoreboardRow.FormatPing(scoreboardRow.PingMs), PingColor(scoreboardRow.PingMs));
				if ((Object)(object)scoreboardRowView.Background != (Object)null)
				{
					((Graphic)scoreboardRowView.Background).color = (scoreboardRow.IsLocal ? UIColors.WithAlpha(UIColors.BorderAccent, 0.28f) : ((i % 2 == 0) ? UIColors.EntryBg : UIColors.WithAlpha(UIColors.Surface, 0.9f)));
				}
				if ((Object)(object)scoreboardRowView.Accent != (Object)null)
				{
					((Behaviour)scoreboardRowView.Accent).enabled = scoreboardRow.IsLocal;
					if (scoreboardRow.IsLocal)
					{
						((Graphic)scoreboardRowView.Accent).color = UIColors.BorderAccent;
					}
				}
			}
		}

		private static void ApplyGearSlot(Image img, Sprite sprite, string tooltip)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)img == (Object)null)
			{
				return;
			}
			if ((Object)(object)sprite != (Object)null)
			{
				img.sprite = sprite;
				((Graphic)img).color = Color.white;
				((Behaviour)img).enabled = true;
				((Component)img).gameObject.SetActive(true);
				if ((Object)(object)((Component)img).transform.parent != (Object)null)
				{
					((Component)((Component)img).transform.parent).gameObject.SetActive(true);
				}
				SetTooltip(((Object)(object)((Component)img).transform.parent != (Object)null) ? ((Component)((Component)img).transform.parent).gameObject : ((Component)img).gameObject, tooltip);
			}
			else
			{
				img.sprite = null;
				((Behaviour)img).enabled = false;
				if ((Object)(object)((Component)img).transform.parent != (Object)null)
				{
					((Component)((Component)img).transform.parent).gameObject.SetActive(true);
				}
				((Component)img).gameObject.SetActive(true);
				((Graphic)img).color = UIColors.WithAlpha(UIColors.TextMuted, 0.2f);
				UIFactory.ApplyWhiteSprite(img);
				((Behaviour)img).enabled = true;
				img.preserveAspect = false;
				SetTooltip(((Object)(object)((Component)img).transform.parent != (Object)null) ? ((Component)((Component)img).transform.parent).gameObject : ((Component)img).gameObject, string.IsNullOrEmpty(tooltip) ? "—" : tooltip);
			}
			if ((Object)(object)sprite != (Object)null)
			{
				img.preserveAspect = true;
			}
		}

		private static void ApplyIcon(Image img, Sprite sprite, Color tint)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)img == (Object)null)
			{
				return;
			}
			if ((Object)(object)sprite != (Object)null)
			{
				img.sprite = sprite;
				((Graphic)img).color = tint;
				((Behaviour)img).enabled = true;
				img.preserveAspect = true;
				((Component)img).gameObject.SetActive(true);
				if ((Object)(object)((Component)img).transform.parent != (Object)null)
				{
					((Component)((Component)img).transform.parent).gameObject.SetActive(true);
				}
			}
			else
			{
				img.sprite = null;
				((Behaviour)img).enabled = false;
				((Component)img).gameObject.SetActive(false);
				if ((Object)(object)((Component)img).transform.parent != (Object)null)
				{
					((Component)((Component)img).transform.parent).gameObject.SetActive(false);
				}
			}
		}

		private static void SetTooltip(GameObject go, string message)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			try
			{
				Image component = go.GetComponent<Image>();
				if ((Object)(object)component != (Object)null)
				{
					((Graphic)component).raycastTarget = true;
				}
				TooltipHoverFollower component2 = go.GetComponent<TooltipHoverFollower>();
				if ((Object)(object)component2 == (Object)null)
				{
					UITooltip.Attach(go, message ?? string.Empty);
				}
				else
				{
					component2.Message = message ?? string.Empty;
				}
			}
			catch
			{
			}
		}

		private static void SetText(UIText text, string value, Color color)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (text != null && text.IsAlive)
			{
				text.Text = value ?? string.Empty;
				text.Color = color;
			}
		}

		private static Color StatColor(ScoreboardRow data, Color accent)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (!data.HasStats)
			{
				return UIColors.TextMuted;
			}
			if (!data.IsAlive)
			{
				return UIColors.WithAlpha(accent, 0.55f);
			}
			return accent;
		}

		private static Color PingColor(int ping)
		{
			//IL_0004: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (ping < 0)
			{
				return UIColors.TextMuted;
			}
			if (ping < 60)
			{
				return UIColors.Shamrock;
			}
			if (ping < 120)
			{
				return UIColors.Macaroon;
			}
			return UIColors.Rose;
		}
	}
	internal sealed class ScoreboardRowView
	{
		public Image Accent;

		public Image Background;

		public Image ClassIcon;

		public UIText ClassText;

		public Image Gear0;

		public Image Gear1;

		public Image Gear3;

		public UIText NameText;

		public GameObject Root;

		public UIText StatDmg;

		public UIText StatDth;

		public UIText StatHeal;

		public UIText StatKills;

		public UIText StatPing;

		public UIText StatRev;

		public UIText StatTgt;
	}
	internal struct IconSlot
	{
		public RectTransform Root;

		public Image Inner;
	}
	internal static class ScoreboardRowBuilder
	{
		public static readonly string[] Headers = new string[10] { "PLAYER", "CLASS", "GEAR", "KILLS", "TGT", "DMG", "HEAL", "DTH", "REV", "PING" };

		public static readonly float[] ColWeights = new float[10] { 0.19f, 0.09f, 0.18f, 0.08f, 0.07f, 0.09f, 0.08f, 0.07f, 0.07f, 0.08f };

		public static void BuildHeaderColumns(RectTransform parent)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			float scaledFontSmall = UITheme.ScaledFontSmall;
			for (int i = 0; i < Headers.Length; i++)
			{
				float num2 = ColWeights[i];
				TextAlignmentOptions val = (TextAlignmentOptions)((i <= 2) ? 513 : 514);
				UIText val2 = UIText.Create((Transform)(object)parent, "H" + i, Headers[i], scaledFontSmall, (Color?)UIColors.TextSecondary, val, false);
				RectTransform rect = val2.Rect;
				rect.anchorMin = new Vector2(num, 0f);
				rect.anchorMax = new Vector2(num + num2, 1f);
				rect.offsetMin = new Vector2(UITheme.S(6f), 0f);
				rect.offsetMax = new Vector2(0f - UITheme.S(4f), 0f);
				if ((Object)(object)val2.Tmp != (Object)null)
				{
					((TMP_Text)val2.Tmp).fontStyle = (FontStyles)1;
				}
				num += num2;
			}
		}

		public static ScoreboardRowView CreateRowView(Transform parent, int index, float rowH)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: 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_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Expected O, but got Unknown
			Image val = UIFactory.CreateImage("Row" + index, parent, (index % 2 == 0) ? UIColors.EntryBg : UIColors.WithAlpha(UIColors.Surface, 0.9f), false);
			UIFactory.ApplyWhiteSprite(val);
			RectTransform rectTransform = ((Graphic)val).rectTransform;
			LayoutElement obj = ((Component)val).gameObject.AddComponent<LayoutElement>();
			obj.minHeight = rowH;
			obj.preferredHeight = rowH;
			obj.flexibleHeight = 0f;
			obj.flexibleWidth = 1f;
			ScoreboardRowView scoreboardRowView = new ScoreboardRowView
			{
				Root = ((Component)val).gameObject,
				Background = val
			};
			Image val2 = UIFactory.CreateImage("Accent", (Transform)(object)rectTransform, UIColors.BorderAccent, false);
			UIFactory.ApplyWhiteSprite(val2);
			RectTransform rectTransform2 = ((Graphic)val2).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 0f);
			rectTransform2.anchorMax = new Vector2(0f, 1f);
			rectTransform2.pivot = new Vector2(0f, 0.5f);
			rectTransform2.sizeDelta = new Vector2(UITheme.S(3f), 0f);
			rectTransform2.anchoredPosition = Vector2.zero;
			((Behaviour)val2).enabled = false;
			scoreboardRowView.Accent = val2;
			float num = 0f;
			float height = UITheme.S(22f);
			float width = UITheme.S(64f);
			float num2 = UITheme.S(22f);
			float scaledFontBody = UITheme.ScaledFontBody;
			scoreboardRowView.NameText = CreateCellText((Transform)(object)rectTransform, "Name", num, ColWeights[0], scaledFontBody, (TextAlignmentOptions)513, bold: true);
			num += ColWeights[0];
			float num3 = ColWeights[1];
			RectTransform val3 = UIFactory.CreateRect("Class", (Transform)(object)rectTransform);
			val3.anchorMin = new Vector2(num, 0f);
			val3.anchorMax = new Vector2(num + num3, 1f);
			val3.offsetMin = new Vector2(UITheme.S(4f), UITheme.S(6f));
			val3.offsetMax = new Vector2(0f - UITheme.S(2f), 0f - UITheme.S(6f));
			IconSlot iconSlot = CreateFixedIconSlot((Transform)(object)val3, "IconSlot", num2, height);
			scoreboardRowView.ClassIcon = iconSlot.Inner;
			RectTransform root = iconSlot.Root;
			root.anchorMin = new Vector2(0f, 0.5f);
			root.anchorMax = new Vector2(0f, 0.5f);
			root.pivot = new Vector2(0f, 0.5f);
			root.anchoredPosition = Vector2.zero;
			scoreboardRowView.ClassText = UIText.Create((Transform)(object)val3, "Label", string.Empty, UITheme.ScaledFontSmall, (Color?)UIColors.TextPrimary, (TextAlignmentOptions)513, false);
			RectTransform rect = scoreboardRowView.ClassText.Rect;
			rect.anchorMin = new Vector2(0f, 0f);
			rect.anchorMax = new Vector2(1f, 1f);
			rect.offsetMin = new Vector2(num2 + UITheme.S(4f), 0f);
			rect.offsetMax = Vector2.zero;
			if ((Object)(object)scoreboardRowView.ClassText.Tmp != (Object)null)
			{
				((TMP_Text)scoreboardRowView.ClassText.Tmp).fontStyle = (FontStyles)1;
			}
			num += num3;
			float num4 = ColWeights[2];
			RectTransform val4 = UIFactory.CreateRect("Gear", (Transform)(object)rectTransform);
			val4.anchorMin = new Vector2(num, 0f);
			val4.anchorMax = new Vector2(num + num4, 1f);
			val4.offsetMin = new Vector2(UITheme.S(2f), UITheme.S(6f));
			val4.offsetMax = new Vector2(0f - UITheme.S(2f), 0f - UITheme.S(6f));
			Image obj2 = ((Component)val4).gameObject.AddComponent<Image>();
			((Graphic)obj2).color = new Color(0f, 0f, 0f, 0.01f);
			((Graphic)obj2).raycastTarget = false;
			UIFactory.ApplyWhiteSprite(obj2);
			((Component)val4).gameObject.AddComponent<Mask>().showMaskGraphic = false;
			UIFactory.AddHorizontalLayout(((Component)val4).gameObject, UITheme.S(3f), new RectOffset(0, 0, 0, 0), (TextAnchor)3, false, false, false, false);
			scoreboardRowView.Gear0 = CreateFixedIconSlot((Transform)(object)val4, "G0", width, height).Inner;
			scoreboardRowView.Gear1 = CreateFixedIconSlot((Transform)(object)val4, "G1", width, height).Inner;
			scoreboardRowView.Gear3 = CreateFixedIconSlot((Transform)(object)val4, "G3", num2, height).Inner;
			num += num4;
			scoreboardRowView.StatKills = CreateCellText((Transform)(object)rectTransform, "Kills", num, ColWeights[3], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[3];
			scoreboardRowView.StatTgt = CreateCellText((Transform)(object)rectTransform, "Tgt", num, ColWeights[4], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[4];
			scoreboardRowView.StatDmg = CreateCellText((Transform)(object)rectTransform, "Dmg", num, ColWeights[5], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[5];
			scoreboardRowView.StatHeal = CreateCellText((Transform)(object)rectTransform, "Heal", num, ColWeights[6], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[6];
			scoreboardRowView.StatDth = CreateCellText((Transform)(object)rectTransform, "Dth", num, ColWeights[7], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[7];
			scoreboardRowView.StatRev = CreateCellText((Transform)(object)rectTransform, "Rev", num, ColWeights[8], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			num += ColWeights[8];
			scoreboardRowView.StatPing = CreateCellText((Transform)(object)rectTransform, "Ping", num, ColWeights[9], scaledFontBody, (TextAlignmentOptions)514, bold: true);
			return scoreboardRowView;
		}

		public static IconSlot CreateFixedIconSlot(Transform parent, string name, float width, float height)
		{
			//IL_0047: 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)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00b9: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = UIFactory.CreateRect(name, parent);
			LayoutElement obj = ((Component)val).gameObject.AddComponent<LayoutElement>();
			obj.minWidth = width;
			obj.minHeight = height;
			obj.preferredWidth = width;
			obj.preferredHeight = height;
			obj.flexibleWidth = 0f;
			obj.flexibleHeight = 0f;
			val.sizeDelta = new Vector2(width, height);
			Image obj2 = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)obj2).color = UIColors.WithAlpha(UIColors.Surface, 0.35f);
			((Graphic)obj2).raycastTarget = true;
			UIFactory.ApplyWhiteSprite(obj2);
			((Component)val).gameObject.AddComponent<Mask>().showMaskGraphic = false;
			Image val2 = UIFactory.CreateImage("Sprite", (Transform)(object)val, Color.white, false);
			val2.preserveAspect = true;
			RectTransform rectTransform = ((Graphic)val2).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			((Behaviour)val2).enabled = false;
			return new IconSlot
			{
				Root = val,
				Inner = val2
			};
		}

		public static UIText CreateCellText(Transform parent, string name, float x, float w, float font, TextAlignmentOptions align, bool bold)
		{
			//IL_0009: 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_0029: 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_0056: 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)
			UIText val = UIText.Create(parent, name, string.Empty, font, (Color?)UIColors.TextPrimary, align, false);
			RectTransform rect = val.Rect;
			rect.anchorMin = new Vector2(x, 0f);
			rect.anchorMax = new Vector2(x + w, 1f);
			rect.offsetMin = new Vector2(UITheme.S(4f), 0f);
			rect.offsetMax = new Vector2(0f - UITheme.S(2f), 0f);
			if (bold && (Object)(object)val.Tmp != (Object)null)
			{
				((TMP_Text)val.Tmp).fontStyle = (FontStyles)1;
				((TMP_Text)val.Tmp).characterSpacing = -1f;
			}
			return val;
		}
	}
	public sealed class ScoreboardUI
	{
		private const int MaxRows = 16;

		private const int VisibleRowCap = 4;

		private const float RefreshInterval = 0.2f;

		private readonly List<ScoreboardRow> _dataBuffer = new List<ScoreboardRow>(16);

		private readonly List<ScoreboardRowView> _rows = new List<ScoreboardRowView>(16);

		private Canvas _canvas;

		private GameObject _canvasGo;

		private float _gap;

		private float _headerH;

		private int _lastPlayerCount = -1;

		private float _nextRefresh;

		private float _pad;

		private UIPanel _panel;

		private RectTransform _panelRt;

		private float _panelW;

		private float _rowH;

		private UIScrollView _scroll;

		private UIText _subtitleText;

		private float _titleH;

		private UIText _titleText;

		public bool IsVisible { get; private set; }

		public void EnsureCreated()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: 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_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0450: 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_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Expected O, but got Unknown
			if (!((Object)(object)_canvasGo != (Object)null))
			{
				UITheme.Initialize();
				_canvas = UIFactory.CreateOverlayCanvas("Scoreboard_Canvas", UITheme.WindowSortingOrder + 20);
				_canvasGo = ((Component)_canvas).gameObject;
				Image obj = UIFactory.CreateImage("Backdrop", ((Component)_canvas).transform, UIColors.WithAlpha(Color.black, 0.55f), false);
				UIFactory.ApplyWhiteSprite(obj);
				UIHelpers.SetFillParent(((Graphic)obj).rectTransform, 0f);
				_pad = UITheme.S(14f);
				_titleH = UITheme.S(36f);
				_headerH = UITheme.S(30f);
				_rowH = UITheme.S(40f);
				_gap = UITheme.S(4f);
				_panelW = UITheme.S(980f);
				_panelW = Mathf.Min(_panelW, (float)Screen.width * 0.9f);
				float num = ComputePanelHeight(4);
				num = Mathf.Min(num, (float)Screen.height * 0.7f);
				_panel = UIPanel.Create(((Component)_canvas).transform, "ScoreboardPanel", (Color?)UIColors.PanelBg, true);
				_panelRt = _panel.Rect;
				RectTransform panelRt = _panelRt;
				RectTransform panelRt2 = _panelRt;
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(0.5f, 0.5f);
				panelRt2.anchorMax = val;
				panelRt.anchorMin = val;
				_panelRt.pivot = new Vector2(0.5f, 0.5f);
				_panelRt.sizeDelta = new Vector2(_panelW, num);
				_panelRt.anchoredPosition = Vector2.zero;
				_titleText = UIText.Create(_panel.Content, "Title", "SCOREBOARD", UITheme.ScaledFontHeader, (Color?)UIColors.TextPrimary, (TextAlignmentOptions)513, false);
				RectTransform rect = _titleText.Rect;
				rect.anchorMin = new Vector2(0f, 1f);
				rect.anchorMax = new Vector2(1f, 1f);
				rect.pivot = new Vector2(0.5f, 1f);
				rect.sizeDelta = new Vector2((0f - _pad) * 2f, _titleH);
				rect.anchoredPosition = new Vector2(0f, 0f - _pad);
				if ((Object)(object)_titleText.Tmp != (Object)null)
				{
					((TMP_Text)_titleText.Tmp).fontStyle = (FontStyles)1;
				}
				_subtitleText = UIText.Create(_panel.Content, "Subtitle", string.Empty, UITheme.ScaledFontSmall, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)516, false);
				RectTransform rect2 = _subtitleText.Rect;
				rect2.anchorMin = new Vector2(0f, 1f);
				rect2.anchorMax = new Vector2(1f, 1f);
				rect2.pivot = new Vector2(1f, 1f);
				rect2.sizeDelta = new Vector2((0f - _pad) * 2f, _titleH);
				rect2.anchoredPosition = new Vector2(0f, 0f - _pad);
				RectTransform obj2 = CreateStrip(_panel.Content, "Header", _headerH, UIColors.SectionBar);
				PlaceBelow(obj2, _pad, _titleH + _pad + _gap);
				ScoreboardRowBuilder.BuildHeaderColumns(obj2);
				float num2 = _pad + _titleH + _gap + _headerH + _gap;
				_scroll = UIScrollView.Create(_panel.Content, "RowsScroll", true, false);
				RectTransform rect3 = _scroll.Rect;
				rect3.anchorMin = new Vector2(0f, 0f);
				rect3.anchorMax = new Vector2(1f, 1f);
				rect3.pivot = new Vector2(0.5f, 1f);
				rect3.offsetMin = new Vector2(_pad, _pad);
				rect3.offsetMax = new Vector2(0f - _pad, 0f - num2);
				Image component = _scroll.GameObject.GetComponent<Image>();
				if ((Object)(object)component != (Object)null)
				{
					((Graphic)component).color = UIColors.WithAlpha(Color.clear, 0f);
				}
				VerticalLayoutGroup component2 = ((Component)_scroll.Content).GetComponent<VerticalLayoutGroup>();
				if ((Object)(object)component2 != (Object)null)
				{
					((HorizontalOrVerticalLayoutGroup)component2).spacing = _gap;
					((LayoutGroup)component2).padding = new RectOffset(0, 0, 0, 0);
					((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
					((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
					((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = true;
				}
				for (int i = 0; i < 16; i++)
				{
					ScoreboardRowView scoreboardRowView = ScoreboardRowBuilder.CreateRowView((Transform)(object)_scroll.Content, i, _rowH);
					scoreboardRowView.Root.SetActive(false);
					_rows.Add(scoreboardRowView);
				}
				Hide(immediate: true);
			}
		}

		public void Show()
		{
			EnsureCreated();
			if (!((Object)(object)_canvasGo == (Object)null))
			{
				IsVisible = true;
				_canvasGo.SetActive(true);
				_nextRefresh = 0f;
				_lastPlayerCount = -1;
				Refresh(force: true);
			}
		}

		public void Hide(bool immediate = false)
		{
			IsVisible = false;
			try
			{
				UITooltip.Shared.Hide();
			}
			catch
			{
			}
			if ((Object)(object)_canvasGo != (Object)null)
			{
				_canvasGo.SetActive(false);
			}
		}

		public void Tick()
		{
			if (IsVisible && Time.unscaledTime >= _nextRefresh)
			{
				Refresh(force: false);
			}
		}

		public void Destroy()
		{
			Hide(immediate: true);
			UIHelpers.DestroySafe((Object)(object)_canvasGo);
			_canvasGo = null;
			_canvas = null;
			_panelRt = null;
			_panel = null;
			_scroll = null;
			_rows.Clear();
			_titleText = null;
			_subtitleText = null;
		}

		private void Refresh(bool force)
		{
			_nextRefresh = Time.unscaledTime + 0.2f;
			ScoreboardDataBuilder.Build(_dataBuffer);
			ApplyLayout();
			ScoreboardDataBuilder.Apply(_dataBuffer, _rows, _subtitleText);
		}

		private float ComputePanelHeight(int visibleRows)
		{
			int num = Mathf.Max(1, visibleRows);
			return _pad * 2f + _titleH + _gap + _headerH + _gap + (float)num * _rowH + (float)Mathf.Max(0, num - 1) * _gap + _pad * 0.5f;
		}

		private void ApplyLayout()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panelRt == (Object)null)
			{
				return;
			}
			int count = _dataBuffer.Count;
			if (count == _lastPlayerCount && count > 0)
			{
				return;
			}
			_lastPlayerCount = count;
			int visibleRows = Mathf.Clamp((count <= 0) ? 1 : count, 1, 4);
			float num = ComputePanelHeight(visibleRows);
			num = Mathf.Min(num, (float)Screen.height * 0.7f);
			num = Mathf.Max(num, UITheme.S(160f));
			_panelRt.sizeDelta = new Vector2(_panelW, num);
			if (_scroll != null && (Object)(object)_scroll.ScrollRect != (Object)null)
			{
				_scroll.ScrollRect.vertical = count > 4;
				if (count <= 4)
				{
					_scroll.ScrollRect.verticalNormalizedPosition = 1f;
				}
			}
		}

		private static RectTransform CreateStrip(Transform parent, string name, float height, Color bg)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0049: 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)
			Image obj = UIFactory.CreateImage(name, parent, bg, false);
			UIFactory.ApplyWhiteSprite(obj);
			RectTransform rectTransform = ((Graphic)obj).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = new Vector2(1f, 1f);
			rectTransform.pivot = new Vector2(0.5f, 1f);
			rectTransform.sizeDelta = new Vector2(0f, height);
			return rectTransform;
		}

		private static void PlaceBelow(RectTransform rt, float horizontalPad, float topOffset)
		{
			//IL_0008: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_004f: 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_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_0074: Unknown result type (might be due to invalid IL or missing references)
			rt.anchoredPosition = new Vector2(0f, 0f - topOffset);
			float y = rt.sizeDelta.y;
			rt.offsetMin = new Vector2(horizontalPad, rt.offsetMin.y);
			rt.offsetMax = new Vector2(0f - horizontalPad, rt.offsetMax.y);
			rt.sizeDelta = new Vector2(rt.sizeDelta.x, y);
			Vector2 sizeDelta = rt.sizeDelta;
			sizeDelta.y = y;
			rt.sizeDelta = sizeDelta;
		}
	}
}
namespace Scoreboard.Tracking
{
	[HarmonyPatch]
	internal static class MissionStatPatches
	{
		[HarmonyPatch(typeof(MissionManager), "OnMissionStarted_Client")]
		[HarmonyPostfix]
		private static void PostMissionStarted()
		{
			MissionStatTracker.OnMissionStarted();
		}

		[HarmonyPatch(typeof(MissionManager), "FinalizeMissionData")]
		[HarmonyPostfix]
		private static void PostFinalizeMissionData()
		{
			MissionStatTracker.OnMissionEnded();
		}

		[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerDamageTarget")]
		[HarmonyPostfix]
		private static void PostDamageTarget(in DamageCallbackData data)
		{
			MissionStatTracker.OnDamageDealt(data.damageData.damage);
		}

		[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerHealTarget")]
		[HarmonyPostfix]
		private static void PostHealTarget(float healing)
		{
			MissionStatTracker.OnHealingDealt(healing);
		}

		[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerKillTarget")]
		[HarmonyPostfix]
		private static void PostKillTarget(in KillCallbackData data)
		{
			MissionStatTracker.OnKill(in data);
		}
	}
	public static class MissionStatTracker
	{
		private static bool _hasFrozenStats;

		private static int _frozenCoreKills;

		private static int _frozenTargetKills;

		private static int _frozenDamage;

		private static int _frozenHealing;

		private static int _frozenDeaths;

		private static int _frozenRevives;

		private static bool _accumActive;

		private static float _accDamage;

		private static float _accHealing;

		private static int _accCoreKills;

		private static int _accTargetKills;

		private static int _accDeaths;

		private static int _accRevives;

		private static int _lastSeenDeaths;

		private static int _lastSeenRepairs;

		public static bool HasSession
		{
			get
			{
				MissionManager mm;
				if (!_hasFrozenStats && !_accumActive)
				{
					return TryGetMissionManager(out mm);
				}
				return true;
			}
		}

		public static void ResetAll()
		{
			_hasFrozenStats = false;
			_frozenCoreKills = (_frozenTargetKills = (_frozenDamage = 0));
			_frozenHealing = (_frozenDeaths = (_frozenRevives = 0));
			ResetAccumulators();
		}

		private static void ResetAccumulators()
		{
			_accumActive = false;
			_accDamage = (_accHealing = 0f);
			_accCoreKills = (_accTargetKills = (_accDeaths = (_accRevives = 0)));
			_lastSeenDeaths = (_lastSeenRepairs = 0);
		}

		public static void OnMissionStarted()
		{
			try
			{
				_hasFrozenStats = false;
				_frozenCoreKills = (_frozenTargetKills = (_frozenDamage = 0));
				_frozenHealing = (_frozenDeaths = (_frozenRevives = 0));
				ResetAccumulators();
				_accumActive = true;
				PlayerData instance = PlayerData.Instance;
				if (instance != null)
				{
					_lastSeenDeaths = instance.deaths;
					_lastSeenRepairs = instance.playersRepaired;
				}
				if (TryGetMissionManager(out var mm))
				{
					ref MissionPlayerData missionData = ref mm.MissionData;
					ManualLogSource log = ScoreboardPlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)($"[Scoreboard] Mission start. MissionData snapshot dmg={missionData.damageDealt:F0} kills={missionData.enemiesKilled} | " + $"PlayerData dmg={instance?.damageDealt:F0} kills={instance?.enemiesKilled}"));
					}
				}
				else
				{
					ManualLogSource log2 = ScoreboardPlugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[Scoreboard] Mission start (no MissionManager yet). Accumulators armed.");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log3 = ScoreboardPlugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)$"[Scoreboard] OnMissionStarted failed: {arg}");
				}
			}
		}

		public static void OnMissionEnded()
		{
			try
			{
				if (TryGetMissionManager(out var mm))
				{
					ref MissionPlayerData missionData = ref mm.MissionData;
					_frozenCoreKills = Math.Max(Mathf.Max(0, missionData.enemiesKilled), _accCoreKills);
					_frozenTargetKills = Math.Max(Mathf.Max(0, missionData.targetsKilled), _accTargetKills);
					_frozenDamage = Math.Max(Mathf.Max(0, Mathf.FloorToInt(missionData.damageDealt)), Mathf.Max(0, Mathf.FloorToInt(_accDamage)));
					_frozenHealing = Math.Max(Mathf.Max(0, Mathf.FloorToInt(missionData.healingDealt)), Mathf.Max(0, Mathf.FloorToInt(_accHealing)));
					_frozenDeaths = Mathf.Max(0, missionData.deaths);
					_frozenRevives = Mathf.Max(0, missionData.playersRepaired);
					_hasFrozenStats = true;
					ManualLogSource log = ScoreboardPlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)($"[Scoreboard] Frozen: dmg={_frozenDamage} kills={_frozenCoreKills} " + $"heal={_frozenHealing} deaths={_frozenDeaths} rev={_frozenRevives} | " + $"MissionData dmg={missionData.damageDealt:F0} acc dmg={_accDamage:F0}"));
					}
				}
				else if (_accumActive)
				{
					FreezeFromAccumulators();
					ManualLogSource log2 = ScoreboardPlugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)$"[Scoreboard] Frozen from accumulators (no MM): dmg={_frozenDamage} kills={_frozenCoreKills}");
					}
				}
				_accumActive = false;
			}
			catch (Exception arg)
			{
				ManualLogSource log3 = ScoreboardPlugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)$"[Scoreboard] OnMissionEnded failed: {arg}");
				}
			}
		}

		private static void FreezeFromAccumulators()
		{
			PollDeathsAndRevives();
			_frozenCoreKills = _accCoreKills;
			_frozenTargetKills = _accTargetKills;
			_frozenDamage = Mathf.Max(0, Mathf.FloorToInt(_accDamage));
			_frozenHealing = Mathf.Max(0, Mathf.FloorToInt(_accHealing));
			_frozenDeaths = _accDeaths;
			_frozenRevives = _accRevives;
			_hasFrozenStats = true;
		}

		public static PlayerStatsSnapshot GetLocalSnapshot()
		{
			ScoreboardRow scoreboardRow = new ScoreboardRow();
			FillLocalStats(scoreboardRow);
			ulong clientId = 0uL;
			try
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					clientId = NetworkManager.Singleton.LocalClientId;
				}
				else if ((Object)(object)Player.LocalPlayer != (Object)null)
				{
					clientId = ((NetworkBehaviour)Player.LocalPlayer).OwnerClientId;
				}
			}
			catch
			{
			}
			int pingMs = -1;
			try
			{
				if ((Object)(object)Player.LocalPlayer != (Object)null)
				{
					pingMs = PlayerPresentation.GetPingMs(Player.LocalPlayer);
				}
			}
			catch
			{
			}
			return new PlayerStatsSnapshot
			{
				ClientId = clientId,
				HasStats = scoreboardRow.HasStats,
				CoreKills = scoreboardRow.CoreKills,
				TargetKills = scoreboardRow.TargetKills,
				Damage = scoreboardRow.Damage,
				Healing = scoreboardRow.Healing,
				Deaths = scoreboardRow.Deaths,
				Revives = scoreboardRow.Revives,
				PingMs = pingMs
			};
		}

		public static void FillLocalStats(ScoreboardRow row)
		{
			if (row == null)
			{
				return;
			}
			EnsureArmedIfMissionLive();
			if (_accumActive)
			{
				PollDeathsAndRevives();
			}
			int coreKills;
			int targetKills;
			int damage;
			int healing;
			int deaths;
			int revives;
			if (_hasFrozenStats)
			{
				row.HasStats = true;
				row.CoreKills = _frozenCoreKills;
				row.TargetKills = _frozenTargetKills;
				row.Damage = _frozenDamage;
				row.Healing = _frozenHealing;
				row.Deaths = _frozenDeaths;
				row.Revives = _frozenRevives;
			}
			else if (TryGetLiveFromMissionData(out coreKills, out targetKills, out damage, out healing, out deaths, out revives))
			{
				row.HasStats = true;
				if (_accumActive)
				{
					row.CoreKills = Math.Max(coreKills, _accCoreKills);
					row.TargetKills = Math.Max(targetKills, _accTargetKills);
					row.Damage = Math.Max(damage, Mathf.Max(0, Mathf.FloorToInt(_accDamage)));
					row.Healing = Math.Max(healing, Mathf.Max(0, Mathf.FloorToInt(_accHealing)));
				}
				else
				{
					row.CoreKills = coreKills;
					row.TargetKills = targetKills;
					row.Damage = damage;
					row.Healing = healing;
				}
				row.Deaths = deaths;
				row.Revives = revives;
			}
			else if (_accumActive)
			{
				FillFromAccumulators(row);
			}
			else
			{
				row.HasStats = false;
			}
		}

		private static void FillFromAccumulators(ScoreboardRow row)
		{
			row.HasStats = true;
			row.CoreKills = _accCoreKills;
			row.TargetKills = _accTargetKills;
			row.Damage = Mathf.Max(0, Mathf.FloorToInt(_accDamage));
			row.Healing = Mathf.Max(0, Mathf.FloorToInt(_accHealing));
			row.Deaths = _accDeaths;
			row.Revives = _accRevives;
		}

		private static bool TryGetLiveFromMissionData(out int coreKills, out int targetKills, out int damage, out int healing, out int deaths, out int revives)
		{
			coreKills = (targetKills = (damage = (healing = (deaths = (revives = 0)))));
			if (!TryGetMissionManager(out var mm))
			{
				return false;
			}
			if (mm.HasMissionEnded)
			{
				ref MissionPlayerData missionData = ref mm.MissionData;
				coreKills = Mathf.Max(0, missionData.enemiesKilled);
				targetKills = Mathf.Max(0, missionData.targetsKilled);
				damage = Mathf.Max(0, Mathf.FloorToInt(missionData.damageDealt));
				healing = Mathf.Max(0, Mathf.FloorToInt(missionData.healingDealt));
				deaths = Mathf.Max(0, missionData.deaths);
				revives = Mathf.Max(0, missionData.playersRepaired);
				return true;
			}
			PlayerData instance = PlayerData.Instance;
			if (instance == null)
			{
				return false;
			}
			ref MissionPlayerData missionData2 = ref mm.MissionData;
			coreKills = Mathf.Max(0, instance.enemiesKilled - missionData2.enemiesKilled);
			targetKills = Mathf.Max(0, instance.targetsKilled - missionData2.targetsKilled);
			damage = Mathf.Max(0, Mathf.FloorToInt(instance.damageDealt - missionData2.damageDealt));
			healing = Mathf.Max(0, Mathf.FloorToInt(instance.healingDealt - missionData2.healingDealt));
			deaths = Mathf.Max(0, instance.deaths - missionData2.deaths);
			revives = Mathf.Max(0, instance.playersRepaired - missionData2.playersRepaired);
			return true;
		}

		private static bool TryGetMissionManager(out MissionManager mm)
		{
			mm = null;
			try
			{
				mm = MissionManager.Instance;
				return (Object)(object)mm != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static void EnsureArmedIfMissionLive()
		{
			if (_hasFrozenStats || _accumActive)
			{
				return;
			}
			try
			{
				if (TryGetMissionManager(out var mm) && mm.IsMissionActive && !mm.HasMissionEnded)
				{
					ManualLogSource log = ScoreboardPlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)"[Scoreboard] Late-arming trackers (missed start hook).");
					}
					OnMissionStarted();
				}
			}
			catch
			{
			}
		}

		private static void PollDeathsAndRevives()
		{
			try
			{
				PlayerData instance = PlayerData.Instance;
				if (instance != null)
				{
					if (instance.deaths > _lastSeenDeaths)
					{
						_accDeaths += instance.deaths - _lastSeenDeaths;
						_lastSeenDeaths = instance.deaths;
					}
					if (instance.playersRepaired > _lastSeenRepairs)
					{
						_accRevives += instance.playersRepaired - _lastSeenRepairs;
						_lastSeenRepairs = instance.playersRepaired;
					}
				}
			}
			catch
			{
			}
		}

		public static void OnDamageDealt(float amount)
		{
			if (_accumActive && !(amount <= 0f))
			{
				_accDamage += amount;
			}
		}

		public static void OnHealingDealt(float amount)
		{
			if (_accumActive && !(amount <= 0f))
			{
				_accHealing += amount;
			}
		}

		public static void OnKill(in KillCallbackData data)
		{
			//IL_000f: 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)
			if (!_accumActive)
			{
				return;
			}
			try
			{
				if ((((IFollowable)data.target).Type & 1) != 0)
				{
					_accTargetKills++;
					if (data.target is EnemyCore)
					{
						_accCoreKills++;
					}
				}
			}
			catch
			{
			}
		}
	}
	public static class PlayerPresentation
	{
		public static int GetPingMs(Player player)
		{
			try
			{
				if ((Object)(object)player == (Object)null)
				{
					return -1;
				}
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || (Object)(object)singleton.NetworkConfig?.NetworkTransport == (Object)null)
				{
					return -1;
				}
				if (((NetworkBehaviour)player).IsLocalPlayer)
				{
					if (singleton.IsHost || singleton.IsServer)
					{
						return 0;
					}
					ulong num = 0uL;
					int num2 = (int)singleton.NetworkConfig.NetworkTransport.GetCurrentRtt(num);
					return (num2 >= 0) ? num2 : (-1);
				}
				if (singleton.IsServer || singleton.IsHost)
				{
					int num3 = (int)singleton.NetworkConfig.NetworkTransport.GetCurrentRtt(((NetworkBehaviour)player).OwnerClientId);
					return (num3 >= 0) ? num3 : (-1);
				}
				return -1;
			}
			catch
			{
				return -1;
			}
		}

		public static void FillGearIcons(Player player, ScoreboardRow row)
		{
			if (row == null)
			{
				return;
			}
			row.GearIcon0 = (row.GearIcon1 = (row.GearIcon3 = null));
			row.GearName0 = (row.GearName1 = (row.GearName3 = string.Empty));
			try
			{
				if ((Object)(object)player == (Object)null)
				{
					return;
				}
				IGear[] array = null;
				try
				{
					array = player.Gear;
				}
				catch
				{
					return;
				}
				if (array != null)
				{
					if (array.Length != 0)
					{
						FillOneGear(array[0], out row.GearIcon0, out row.GearName0);
					}
					if (array.Length > 1)
					{
						FillOneGear(array[1], out row.GearIcon1, out row.GearName1);
					}
					if (array.Length > 3)
					{
						FillOneGear(array[3], out row.GearIcon3, out row.GearName3);
					}
				}
			}
			catch
			{
			}
		}

		public static void FillCharacterVisuals(Player player, ScoreboardRow row)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (row == null)
			{
				return;
			}
			row.CharacterIcon = null;
			row.CharacterTooltip = string.Empty;
			try
			{
				if (!((Object)(object)((player != null) ? player.Character : null) == (Object)null))
				{
					Character character = player.Character;
					row.CharacterName = ((!string.IsNullOrEmpty(((Dude)character).ClassName)) ? ((Dude)character).ClassName : ((Object)character).name);
					if ((Object)(object)character.MiniIcon != (Object)null)
					{
						row.CharacterIcon = character.MiniIcon;
					}
					else if ((Object)(object)character.RectIcon != (Object)null)
					{
						row.CharacterIcon = character.RectIcon;
					}
					else if ((Object)(object)((Dude)character).Info != (Object)null && (Object)(object)((Dude)character).Info.Icon != (Object)null)
					{
						row.CharacterIcon = ((Dude)character).Info.Icon;
					}
					row.CharacterTooltip = row.CharacterName;
					Color uIColor = character.UIColor;
					row.SetCharacterColor(uIColor.r, uIColor.g, uIColor.b, uIColor.a);
				}
			}
			catch
			{
				row.CharacterName = "—";
			}
		}

		private static void FillOneGear(IGear gear, out Sprite icon, out string name)
		{
			icon = null;
			name = string.Empty;
			try
			{
				if (gear == null)
				{
					return;
				}
				GearInfo info = ((IUpgradable)gear).Info;
				if (!((Object)(object)info == (Object)null))
				{
					icon = info.Icon;
					if (!string.IsNullOrEmpty(info.Name))
					{
						name = info.Name;
					}
					else if (!string.IsNullOrEmpty(info.APIName))
					{
						name = info.APIName;
					}
				}
			}
			catch
			{
			}
		}
	}
}
namespace Scoreboard.Networking
{
	public static class PeerRegistry
	{
		private const float PeerTimeout = 20f;

		private static readonly Dictionary<ulong, PlayerStatsSnapshot> RemoteStats = new Dictionary<ulong, PlayerStatsSnapshot>(8);

		private static readonly Dictionary<ulong, float> PeerLastSeen = new Dictionary<ulong, float>(8);

		private static readonly Dictionary<ulong, float> LastRelayTime = new Dictionary<ulong, float>(8);

		private static readonly HashSet<ulong> ModPeers = new HashSet<ulong>();

		public static int Count
		{
			get
			{
				PruneStale();
				return ModPeers.Count;
			}
		}

		public static int RemoteStatsCount => RemoteStats.Count;

		public static IEnumerable<KeyValuePair<ulong, PlayerStatsSnapshot>> EnumerateRemoteStats()
		{
			return RemoteStats;
		}

		public static void Clear()
		{
			RemoteStats.Clear();
			PeerLastSeen.Clear();
			LastRelayTime.Clear();
			ModPeers.Clear();
		}

		public static void NotePeer(ulong clientId)
		{
			ModPeers.Add(clientId);
			PeerLastSeen[clientId] = Time.unscaledTime;
		}

		public static void StoreSnapshot(PlayerStatsSnapshot snap)
		{
			RemoteStats[snap.ClientId] = snap;
			PeerLastSeen[snap.ClientId] = Time.unscaledTime;
		}

		public static bool TryGetRemoteStats(ulong clientId, out PlayerStatsSnapshot snapshot)
		{
			PruneStale();
			if (RemoteStats.TryGetValue(clientId, out snapshot) && snapshot.HasStats)
			{
				return true;
			}
			snapshot = default(PlayerStatsSnapshot);
			return false;
		}

		public static bool TryGetRemotePing(ulong clientId, out int pingMs)
		{
			pingMs = -1;
			if (RemoteStats.TryGetValue(clientId, out var value) && value.PingMs >= 0)
			{
				pingMs = value.PingMs;
				return true;
			}
			return false;
		}

		public static bool TryGetExisting(ulong clientId, out PlayerStatsSnapshot snapshot)
		{
			return RemoteStats.TryGetValue(clientId, out snapshot);
		}

		public static void TouchPeer(ulong clientId)
		{
			PeerLastSeen[clientId] = Time.unscaledTime;
		}

		public static bool ShouldRelay(ulong clientId, float minRelayInterval, float now)
		{
			if (!LastRelayTime.TryGetValue(clientId, out var value) || now - value >= minRelayInterval)
			{
				LastRelayTime[clientId] = now;
				return true;
			}
			return false;
		}

		public static void RemoveClient(ulong clientId)
		{
			RemoteStats.Remove(clientId);
			PeerLastSeen.Remove(clientId);
			LastRelayTime.Remove(clientId);
			ModPeers.Remove(clientId);
		}

		public static void PruneStale()
		{
			float unscaledTime = Time.unscaledTime;
			List<ulong> list = null;
			foreach (KeyValuePair<ulong, float> item in PeerLastSeen)
			{
				if (unscaledTime - item.Value > 20f)
				{
					if (list == null)
					{
						list = new List<ulong>(4);
					}
					list.Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			ulong num = ulong.MaxValue;
			try
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					num = NetworkManager.Singleton.LocalClientId;
				}
			}
			catch
			{
			}
			for (int i = 0; i < list.Count; i++)
			{
				ulong num2 = list[i];
				if (num2 != num)
				{
					PeerLastSeen.Remove(num2);
					ModPeers.Remove(num2);
					LastRelayTime.Remove(num2);
				}
			}
		}
	}
	public static class ScoreboardNetwork
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHelloReceived;

			public static HandleNamedMessageDelegate <1>__OnStatsReceived;

			public static HandleNamedMessageDelegate <2>__OnFullStateReceived;

			public static HandleNamedMessageDelegate <3>__OnRequestFullReceived;

			public static Action<ulong> <4>__OnClientConnected;

			public static Action<ulong> <5>__OnClientDisconnected;
		}

		public const string HelloMessage = "sparroh.scoreboard.hello";

		public const string StatsMessage = "sparroh.scoreboard.stats";

		public const string FullStateMessage = "sparroh.scoreboard.full";

		public const string RequestFullMessage = "sparroh.scoreboard.reqfull";

		private const float HelloInterval = 4f;

		private const float StatsInterval = 1f;

		private const float HostPushInterval = 1f;

		private const float PostConnectDelay = 1.5f;

		private const float MinRelayInterval = 0.5f;

		private static readonly List<ulong> SendTargetBuffer = new List<ulong>(8);

		private static bool _enabled = true;

		private static bool _debugLog;

		private static bool _handlersRegistered;

		private static bool _networkingDisabledForSession;

		private static bool _requestedFullOnce;

		private static float _readyAt = -1f;

		private static float _nextHelloTime;

		private static float _nextStatsTime;

		private static float _nextHostPushTime;

		private static float _nextDebugLogTime;

		private static PlayerStatsSnapshot _lastSent;

		private static NetworkManager _boundNm;

		public static bool IsNetworkingEnabled
		{
			get
			{
				if (_enabled && _handlersRegistered)
				{
					return !_networkingDisabledForSession;
				}
				return false;
			}
		}

		public static int ModPeerCount => PeerRegistry.Count;

		public static void SetEnabled(bool enabled)
		{
			_enabled = enabled;
			if (!enabled)
			{
				Shutdown();
			}
		}

		public static void SetDebugLog(bool enabled)
		{
			_debugLog = enabled;
		}

		public static void Initialize()
		{
		}

		public static void Shutdown()
		{
			UnregisterHandlers();
			PeerRegistry.Clear();
			_lastSent = default(PlayerStatsSnapshot);
			_readyAt = -1f;
			_requestedFullOnce = false;
			_networkingDisabledForSession = false;
		}

		public static void Tick()
		{
			if (!_enabled || _networkingDisabledForSession)
			{
				return;
			}
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
				{
					if (_handlersRegistered)
					{
						UnregisterHandlers();
					}
					_readyAt = -1f;
					_requestedFullOnce = false;
				}
				else
				{
					if (!singleton.IsServer && !singleton.IsConnectedClient)
					{
						return;
					}
					if (!_handlersRegistered || (Object)(object)_boundNm != (Object)(object)singleton)
					{
						if (TryRegisterHandlers(singleton))
						{
							_readyAt = Time.unscaledTime + 1.5f;
							_nextHelloTime = _readyAt;
							_nextStatsTime = _readyAt + 0.25f;
							_nextHostPushTime = _readyAt + 0.5f;
							_requestedFullOnce = false;
						}
					}
					else
					{
						if (Time.unscaledTime < _readyAt)
						{
							return;
						}
						float unscaledTime = Time.unscaledTime;
						PeerRegistry.PruneStale();
						if (unscaledTime >= _nextHelloTime)
						{
							_nextHelloTime = unscaledTime + 4f;
							SafeSendHello(singleton);
						}
						if (!singleton.IsServer && !_requestedFullOnce)
						{
							_requestedFullOnce = true;
							SafeRequestFull(singleton);
						}
						if (unscaledTime >= _nextStatsTime)
						{
							_nextStatsTime = unscaledTime + 1f;
							if (ShouldPushStats(singleton))
							{
								SafeSendLocalStats(singleton, forceHostPush: false);
							}
						}
						if (singleton.IsServer && unscaledTime >= _nextHostPushTime)
						{
							_nextHostPushTime = unscaledTime + 1f;
							if (HasRemoteClients(singleton))
							{
								SafeSendLocalStats(singleton, forceHostPush: true);
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] Network tick warning: " + ex.Message));
				}
			}
		}

		public static bool TryGetRemoteStats(ulong clientId, out PlayerStatsSnapshot snapshot)
		{
			return PeerRegistry.TryGetRemoteStats(clientId, out snapshot);
		}

		public static bool TryGetRemotePing(ulong clientId, out int pingMs)
		{
			return PeerRegistry.TryGetRemotePing(clientId, out pingMs);
		}

		private static bool ShouldPushStats(NetworkManager nm)
		{
			if (MissionStatTracker.HasSession)
			{
				return true;
			}
			if (PeerRegistry.Count > 0)
			{
				return true;
			}
			return HasRemoteClients(nm);
		}

		private static bool HasRemoteClients(NetworkManager nm)
		{
			try
			{
				IReadOnlyList<ulong> connectedClientsIds = nm.ConnectedClientsIds;
				return connectedClientsIds != null && connectedClientsIds.Count > 1;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryRegisterHandlers(NetworkManager nm)
		{
			//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_005b: Expected O, but got Unknown
			//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_0081: Expected O, but got Unknown
			//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_00a7: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			try
			{
				if ((Object)(object)_boundNm != (Object)null && (Object)(object)_boundNm != (Object)(object)nm)
				{
					UnregisterHandlers();
				}
				CustomMessagingManager customMessagingManager = nm.CustomMessagingManager;
				if (customMessagingManager == null)
				{
					DisableNetworkingForSession("CustomMessagingManager is null");
					return false;
				}
				object obj = <>O.<0>__OnHelloReceived;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnHelloReceived;
					<>O.<0>__OnHelloReceived = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("sparroh.scoreboard.hello", (HandleNamedMessageDelegate)obj);
				object obj2 = <>O.<1>__OnStatsReceived;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnStatsReceived;
					<>O.<1>__OnStatsReceived = val2;
					obj2 = (object)val2;
				}
				customMessagingManager.RegisterNamedMessageHandler("sparroh.scoreboard.stats", (HandleNamedMessageDelegate)obj2);
				object obj3 = <>O.<2>__OnFullStateReceived;
				if (obj3 == null)
				{
					HandleNamedMessageDelegate val3 = OnFullStateReceived;
					<>O.<2>__OnFullStateReceived = val3;
					obj3 = (object)val3;
				}
				customMessagingManager.RegisterNamedMessageHandler("sparroh.scoreboard.full", (HandleNamedMessageDelegate)obj3);
				object obj4 = <>O.<3>__OnRequestFullReceived;
				if (obj4 == null)
				{
					HandleNamedMessageDelegate val4 = OnRequestFullReceived;
					<>O.<3>__OnRequestFullReceived = val4;
					obj4 = (object)val4;
				}
				customMessagingManager.RegisterNamedMessageHandler("sparroh.scoreboard.reqfull", (HandleNamedMessageDelegate)obj4);
				nm.OnClientConnectedCallback += OnClientConnected;
				nm.OnClientDisconnectCallback += OnClientDisconnected;
				_handlersRegistered = true;
				_boundNm = nm;
				PeerRegistry.NotePeer(nm.LocalClientId);
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[Scoreboard] Named message handlers registered.");
				}
				return true;
			}
			catch (Exception ex)
			{
				DisableNetworkingForSession("Register failed: " + ex.Message);
				ManualLogSource log2 = ScoreboardPlugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Scoreboard] Failed to register named messages: {ex}");
				}
				return false;
			}
		}

		private static void UnregisterHandlers()
		{
			try
			{
				if ((Object)(object)_boundNm != (Object)null)
				{
					_boundNm.OnClientConnectedCallback -= OnClientConnected;
					_boundNm.OnClientDisconnectCallback -= OnClientDisconnected;
					CustomMessagingManager customMessagingManager = _boundNm.CustomMessagingManager;
					if (customMessagingManager != null)
					{
						customMessagingManager.UnregisterNamedMessageHandler("sparroh.scoreboard.hello");
						customMessagingManager.UnregisterNamedMessageHandler("sparroh.scoreboard.stats");
						customMessagingManager.UnregisterNamedMessageHandler("sparroh.scoreboard.full");
						customMessagingManager.UnregisterNamedMessageHandler("sparroh.scoreboard.reqfull");
					}
				}
			}
			catch
			{
			}
			_handlersRegistered = false;
			_boundNm = null;
		}

		private static void OnClientConnected(ulong clientId)
		{
			try
			{
				float num = Time.unscaledTime + 1.5f;
				if (_nextHelloTime < 0f || _nextHelloTime > num)
				{
					_nextHelloTime = num;
				}
				if (_nextStatsTime < 0f || _nextStatsTime > num + 0.25f)
				{
					_nextStatsTime = num + 0.25f;
				}
				if (_nextHostPushTime < 0f || _nextHostPushTime > num + 0.5f)
				{
					_nextHostPushTime = num + 0.5f;
				}
				LogDebug($"Client connected: {clientId}");
			}
			catch
			{
			}
		}

		private static void OnClientDisconnected(ulong clientId)
		{
			PeerRegistry.RemoveClient(clientId);
			LogDebug($"Client disconnected: {clientId}");
		}

		private static void SafeSendHello(NetworkManager nm)
		{
			//IL_001e: 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_0038: 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_0053: 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)
			if (!TryGetMessenger(nm, out var cmm))
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				byte b = 2;
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				ulong localClientId = nm.LocalClientId;
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref localClientId, default(ForPrimitives));
				if (nm.IsServer)
				{
					SendToRemoteClients(nm, cmm, "sparroh.scoreboard.hello", val);
					LogDebug($"Hello → remotes as host id={nm.LocalClientId}");
				}
				else if (nm.IsConnectedClient)
				{
					cmm.SendNamedMessage("sparroh.scoreboard.hello", 0uL, val, (NetworkDelivery)2);
					LogDebug($"Hello → server id={nm.LocalClientId}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] SendHello failed: " + ex.Message));
				}
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
		}

		private static void SafeRequestFull(NetworkManager nm)
		{
			//IL_002a: 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)
			if (nm.IsServer || !TryGetMessenger(nm, out var cmm))
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1);
			try
			{
				ulong localClientId = nm.LocalClientId;
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref localClientId, default(ForPrimitives));
				cmm.SendNamedMessage("sparroh.scoreboard.reqfull", 0uL, val, (NetworkDelivery)2);
				LogDebug("Requested full state from server");
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] RequestFull failed: " + ex.Message));
				}
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
		}

		private static void SafeSendLocalStats(NetworkManager nm, bool forceHostPush)
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetMessenger(nm, out var cmm))
			{
				return;
			}
			PlayerStatsSnapshot snap;
			try
			{
				snap = MissionStatTracker.GetLocalSnapshot();
				snap.ClientId = nm.LocalClientId;
			}
			catch
			{
				return;
			}
			PeerRegistry.StoreSnapshot(snap);
			PeerRegistry.NotePeer(snap.ClientId);
			if (!forceHostPush && snap.Equals(_lastSent))
			{
				return;
			}
			try
			{
				if (nm.IsServer)
				{
					SendSnapshotToRemotes(nm, cmm, in snap);
					SendFullStateToRemotes(nm, cmm);
					LogDebug($"Host push → remotes dmg={snap.Damage} has={snap.HasStats} ping={snap.PingMs} rows={PeerRegistry.RemoteStatsCount}");
				}
				else if (nm.IsConnectedClient)
				{
					FastBufferWriter writer = default(FastBufferWriter);
					((FastBufferWriter)(ref writer))..ctor(64, (Allocator)2, -1);
					try
					{
						SnapshotSerializer.Write(ref writer, in snap);
						cmm.SendNamedMessage("sparroh.scoreboard.stats", 0uL, writer, (NetworkDelivery)2);
						LogDebug($"Stats → server id={snap.ClientId} dmg={snap.Damage} rev={snap.Revives} has={snap.HasStats}");
					}
					finally
					{
						((FastBufferWriter)(ref writer)).Dispose();
					}
				}
				_lastSent = snap;
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] SendLocalStats failed: " + ex.Message));
				}
			}
		}

		private static void SendHostStatsTo(NetworkManager nm, CustomMessagingManager cmm, ulong targetClientId)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (targetClientId == nm.LocalClientId)
			{
				return;
			}
			try
			{
				PlayerStatsSnapshot snap = MissionStatTracker.GetLocalSnapshot();
				snap.ClientId = nm.LocalClientId;
				PeerRegistry.StoreSnapshot(snap);
				PeerRegistry.NotePeer(snap.ClientId);
				FastBufferWriter writer = default(FastBufferWriter);
				((FastBufferWriter)(ref writer))..ctor(64, (Allocator)2, -1);
				try
				{
					SnapshotSerializer.Write(ref writer, in snap);
					cmm.SendNamedMessage("sparroh.scoreboard.stats", targetClientId, writer, (NetworkDelivery)2);
					LogDebug($"Host stats → {targetClientId} dmg={snap.Damage} has={snap.HasStats}");
				}
				finally
				{
					((FastBufferWriter)(ref writer)).Dispose();
				}
				SendFullStateTo(nm, cmm, targetClientId);
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] SendHostStatsTo failed: " + ex.Message));
				}
			}
		}

		private static void SendSnapshotToRemotes(NetworkManager nm, CustomMessagingManager cmm, in PlayerStatsSnapshot snap)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter writer = default(FastBufferWriter);
			((FastBufferWriter)(ref writer))..ctor(64, (Allocator)2, -1);
			try
			{
				SnapshotSerializer.Write(ref writer, in snap);
				SendToRemoteClients(nm, cmm, "sparroh.scoreboard.stats", writer);
			}
			finally
			{
				((FastBufferWriter)(ref writer)).Dispose();
			}
		}

		private static void SendToRemoteClients(NetworkManager nm, CustomMessagingManager cmm, string messageName, FastBufferWriter writer)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			BuildRemoteClientList(nm, nm.LocalClientId);
			if (SendTargetBuffer.Count == 0)
			{
				return;
			}
			for (int i = 0; i < SendTargetBuffer.Count; i++)
			{
				try
				{
					cmm.SendNamedMessage(messageName, SendTargetBuffer[i], writer, (NetworkDelivery)2);
				}
				catch (Exception ex)
				{
					ManualLogSource log = ScoreboardPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)$"[Scoreboard] Send {messageName} to {SendTargetBuffer[i]} failed: {ex.Message}");
					}
				}
			}
		}

		private static void SendToRemoteClientsExcept(NetworkManager nm, CustomMessagingManager cmm, string messageName, FastBufferWriter writer, ulong alsoExclude)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			BuildRemoteClientList(nm, nm.LocalClientId);
			if (SendTargetBuffer.Count == 0)
			{
				return;
			}
			for (int i = 0; i < SendTargetBuffer.Count; i++)
			{
				ulong num = SendTargetBuffer[i];
				if (num == alsoExclude)
				{
					continue;
				}
				try
				{
					cmm.SendNamedMessage(messageName, num, writer, (NetworkDelivery)2);
				}
				catch (Exception ex)
				{
					ManualLogSource log = ScoreboardPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)$"[Scoreboard] Send {messageName} to {num} failed: {ex.Message}");
					}
				}
			}
		}

		private static void BuildRemoteClientList(NetworkManager nm, ulong excludeClientId)
		{
			SendTargetBuffer.Clear();
			try
			{
				IReadOnlyList<ulong> connectedClientsIds = nm.ConnectedClientsIds;
				if (connectedClientsIds == null)
				{
					return;
				}
				for (int i = 0; i < connectedClientsIds.Count; i++)
				{
					ulong num = connectedClientsIds[i];
					if (num != excludeClientId)
					{
						SendTargetBuffer.Add(num);
					}
				}
			}
			catch
			{
			}
		}

		private static void SendFullStateToRemotes(NetworkManager nm, CustomMessagingManager cmm)
		{
			//IL_004e: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerStatsSnapshot localSnapshot = MissionStatTracker.GetLocalSnapshot();
				localSnapshot.ClientId = nm.LocalClientId;
				PeerRegistry.StoreSnapshot(localSnapshot);
				PeerRegistry.NotePeer(localSnapshot.ClientId);
			}
			catch
			{
			}
			int remoteStatsCount = PeerRegistry.RemoteStatsCount;
			FastBufferWriter writer = default(FastBufferWriter);
			((FastBufferWriter)(ref writer))..ctor(Mathf.Max(16, 8 + remoteStatsCount * 52), (Allocator)2, -1);
			try
			{
				ushort num = (ushort)remoteStatsCount;
				((FastBufferWriter)(ref writer)).WriteValueSafe<ushort>(ref num, default(ForPrimitives));
				foreach (KeyValuePair<ulong, PlayerStatsSnapshot> item in PeerRegistry.EnumerateRemoteStats())
				{
					SnapshotSerializer.Write(ref writer, item.Value);
				}
				SendToRemoteClients(nm, cmm, "sparroh.scoreboard.full", writer);
			}
			finally
			{
				((FastBufferWriter)(ref writer)).Dispose();
			}
		}

		private static void SendFullStateTo(NetworkManager nm, CustomMessagingManager cmm, ulong targetClientId)
		{
			//IL_0059: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (targetClientId == nm.LocalClientId)
			{
				return;
			}
			try
			{
				PlayerStatsSnapshot localSnapshot = MissionStatTracker.GetLocalSnapshot();
				localSnapshot.ClientId = nm.LocalClientId;
				PeerRegistry.StoreSnapshot(localSnapshot);
				PeerRegistry.NotePeer(localSnapshot.ClientId);
			}
			catch
			{
			}
			int remoteStatsCount = PeerRegistry.RemoteStatsCount;
			FastBufferWriter writer = default(FastBufferWriter);
			((FastBufferWriter)(ref writer))..ctor(Mathf.Max(16, 8 + remoteStatsCount * 52), (Allocator)2, -1);
			try
			{
				ushort num = (ushort)remoteStatsCount;
				((FastBufferWriter)(ref writer)).WriteValueSafe<ushort>(ref num, default(ForPrimitives));
				foreach (KeyValuePair<ulong, PlayerStatsSnapshot> item in PeerRegistry.EnumerateRemoteStats())
				{
					SnapshotSerializer.Write(ref writer, item.Value);
				}
				cmm.SendNamedMessage("sparroh.scoreboard.full", targetClientId, writer, (NetworkDelivery)2);
				LogDebug($"Full state → client {targetClientId} rows={remoteStatsCount}");
			}
			finally
			{
				((FastBufferWriter)(ref writer)).Dispose();
			}
		}

		private static void OnHelloReceived(ulong senderId, FastBufferReader reader)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton != (Object)null && senderId == singleton.LocalClientId)
				{
					return;
				}
				byte b = default(byte);
				((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
				ulong num = default(ulong);
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
				if (b != 1 && b != 2)
				{
					return;
				}
				ulong num2 = ((senderId != 0L) ? senderId : num);
				if ((Object)(object)singleton != (Object)null && num2 == singleton.LocalClientId)
				{
					return;
				}
				PeerRegistry.NotePeer(num2);
				LogDebug($"Hello ← {senderId} claimed={num} modPeers={PeerRegistry.Count}");
				if ((Object)(object)singleton == (Object)null)
				{
					return;
				}
				if (singleton.IsServer && TryGetMessenger(singleton, out var cmm))
				{
					SendHostStatsTo(singleton, cmm, senderId);
					_nextHostPushTime = Time.unscaledTime + 1f;
				}
				else if (!singleton.IsServer)
				{
					_nextStatsTime = Mathf.Min(_nextStatsTime, Time.unscaledTime + 0.25f);
					if (!_requestedFullOnce)
					{
						_requestedFullOnce = true;
						SafeRequestFull(singleton);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] Hello handler: " + ex.Message));
				}
			}
		}

		private static void OnStatsReceived(ulong senderId, FastBufferReader reader)
		{
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (((Object)(object)singleton != (Object)null && senderId == singleton.LocalClientId) || !SnapshotSerializer.TryRead(ref reader, out var snap))
				{
					return;
				}
				if ((senderId != 0L || snap.ClientId == 0L) && senderId != 0L)
				{
					snap.ClientId = senderId;
				}
				if ((Object)(object)singleton != (Object)null && snap.ClientId == singleton.LocalClientId)
				{
					return;
				}
				PeerRegistry.NotePeer(snap.ClientId);
				PlayerStatsSnapshot snapshot;
				bool flag = PeerRegistry.TryGetExisting(snap.ClientId, out snapshot) && snapshot.Equals(snap);
				if (flag)
				{
					PeerRegistry.TouchPeer(snap.ClientId);
				}
				else
				{
					PeerRegistry.StoreSnapshot(snap);
					LogDebug($"Stats ← id={snap.ClientId} dmg={snap.Damage} rev={snap.Revives} ping={snap.PingMs} has={snap.HasStats}");
				}
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer || !TryGetMessenger(singleton, out var cmm))
				{
					return;
				}
				float unscaledTime = Time.unscaledTime;
				if (!flag && PeerRegistry.ShouldRelay(snap.ClientId, 0.5f, unscaledTime))
				{
					FastBufferWriter writer = default(FastBufferWriter);
					((FastBufferWriter)(ref writer))..ctor(64, (Allocator)2, -1);
					try
					{
						SnapshotSerializer.Write(ref writer, in snap);
						SendToRemoteClientsExcept(singleton, cmm, "sparroh.scoreboard.stats", writer, senderId);
					}
					finally
					{
						((FastBufferWriter)(ref writer)).Dispose();
					}
				}
				SendHostStatsTo(singleton, cmm, senderId);
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] Stats handler: " + ex.Message));
				}
			}
		}

		private static void OnFullStateReceived(ulong senderId, FastBufferReader reader)
		{
			//IL_0023: 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)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton != (Object)null && senderId == singleton.LocalClientId)
				{
					return;
				}
				ushort num = default(ushort);
				((FastBufferReader)(ref reader)).ReadValueSafe<ushort>(ref num, default(ForPrimitives));
				int num2 = 0;
				for (int i = 0; i < num; i++)
				{
					if (!SnapshotSerializer.TryRead(ref reader, out var snap))
					{
						break;
					}
					if (!((Object)(object)singleton != (Object)null) || snap.ClientId != singleton.LocalClientId)
					{
						PeerRegistry.NotePeer(snap.ClientId);
						PeerRegistry.StoreSnapshot(snap);
						num2++;
					}
				}
				LogDebug($"Full state ← from={senderId} rows={num2}/{num}");
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] FullState handler: " + ex.Message));
				}
			}
		}

		private static void OnRequestFullReceived(ulong senderId, FastBufferReader reader)
		{
			//IL_0035: 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)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsServer && TryGetMessenger(singleton, out var cmm) && senderId != singleton.LocalClientId)
				{
					try
					{
						ulong num = default(ulong);
						((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
					}
					catch
					{
					}
					PeerRegistry.NotePeer(senderId);
					LogDebug($"Full state requested by {senderId}");
					SendHostStatsTo(singleton, cmm, senderId);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Scoreboard] RequestFull handler: " + ex.Message));
				}
			}
		}

		private static void DisableNetworkingForSession(string reason)
		{
			_networkingDisabledForSession = true;
			try
			{
				UnregisterHandlers();
			}
			catch
			{
			}
			ManualLogSource log = ScoreboardPlugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("[Scoreboard] Networking disabled for this session: " + reason));
			}
		}

		private static bool TryGetMessenger(NetworkManager nm, out CustomMessagingManager cmm)
		{
			cmm = null;
			if (_networkingDisabledForSession || (Object)(object)nm == (Object)null || !nm.IsListening || !_handlersRegistered)
			{
				return false;
			}
			try
			{
				cmm = nm.CustomMessagingManager;
				return cmm != null;
			}
			catch
			{
				return false;
			}
		}

		private static void LogDebug(string msg)
		{
			if (!_debugLog)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (!(unscaledTime < _nextDebugLogTime))
			{
				_nextDebugLogTime = unscaledTime + 0.05f;
				ManualLogSource log = ScoreboardPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[Scoreboard] " + msg));
				}
			}
		}
	}
	public static class SnapshotSerializer
	{
		public static void Write(ref FastBufferWriter writer, in PlayerStatsSnapshot snap)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0061: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			ulong clientId = snap.ClientId;
			int coreKills = snap.CoreKills;
			int targetKills = snap.TargetKills;
			int damage = snap.Damage;
			int healing = snap.Healing;
			int deaths = snap.Deaths;
			int revives = snap.Revives;
			int pingMs = snap.PingMs;
			bool hasStats = snap.HasStats;
			((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref clientId, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref coreKills, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref targetKills, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref damage, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref healing, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref deaths, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref revives, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref pingMs, default(ForPrimitives));
			((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref hasStats, default(ForPrimitives));
		}

		public static bool TryRead(ref FastBufferReader reader, out PlayerStatsSnapshot snap)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_008d: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			snap = default(PlayerStatsSnapshot);
			try
			{
				ulong clientId = default(ulong);
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref clientId, default(ForPrimitives));
				int coreKills = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref coreKills, default(ForPrimitives));
				int targetKills = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref targetKills, default(ForPrimitives));
				int damage = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref damage, default(ForPrimitives));
				int healing = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref healing, default(ForPrimitives));
				int deaths = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref deaths, default(ForPrimitives));
				int revives = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref revives, default(ForPrimitives));
				int pingMs = -1;
				bool hasStats = default(bool);
				try
				{
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref pingMs, default(ForPrimitives));
					((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref hasStats, default(ForPrimitives));
				}
				catch
				{
					hasStats = false;
					try
					{
						((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref hasStats, default(ForPrimitives));
					}
					catch
					{
					}
				}
				snap = new PlayerStatsSnapshot
				{
					ClientId = clientId,
					CoreKills = coreKills,
					TargetKills = targetKills,
					Damage = damage,
					Healing = healing,
					Deaths = deaths,
					Revives = revives,
					PingMs = pingMs,
					HasStats = hasStats
				};
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
}
namespace Scoreboard.Data
{
	public struct PlayerStatsSnapshot : IEquatable<PlayerStatsSnapshot>
	{
		public const byte ProtocolVersion = 2;

		public ulong ClientId;

		public int CoreKills;

		public int TargetKills;

		public int Damage;

		public int Healing;

		public int Deaths;

		public int Revives;

		public int PingMs;

		public bool HasStats;

		public bool Equals(PlayerStatsSnapshot other)
		{
			if (ClientId == other.ClientId && CoreKills == other.CoreKills && TargetKills == other.TargetKills && Damage == other.Damage && Healing == other.Healing && Deaths == other.Deaths && Revives == other.Revives && PingMs == other.PingMs)
			{
				return HasStats == other.HasStats;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is PlayerStatsSnapshot other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((((((((((((((((int)ClientId * 397) ^ CoreKills) * 397) ^ TargetKills) * 397) ^ Damage) * 397) ^ Healing) * 397) ^ Deaths) * 397) ^ Revives) * 397) ^ PingMs) * 397) ^ (HasStats ? 1 : 0);
		}

		public void ApplyTo(ScoreboardRow row)
		{
			if (row != null)
			{
				row.HasStats = HasStats;
				if (PingMs >= 0)
				{
					row.PingMs = PingMs;
				}
				if (HasStats)
				{
					row.CoreKills = CoreKills;
					row.TargetKills = TargetKills;
					row.Damage = Damage;
					row.Healing = Healing;
					row.Deaths = Deaths;
					row.Revives = Revives;
				}
			}
		}
	}
	public sealed class ScoreboardRow
	{
		public float CharacterColorA = 1f;

		public float CharacterColorB = 1f;

		public float CharacterColorG = 1f;

		public float CharacterColorR = 1f;

		public Sprite CharacterIcon;

		public string CharacterName = string.Empty;

		public string CharacterTooltip = string.Empty;

		public ulong ClientId;

		public int CoreKills;

		public int Damage;

		public int Deaths;

		public Sprite GearIcon0;

		public Sprite GearIcon1;

		public Sprite GearIcon3;

		public string GearName0 = string.Empty;

		public string GearName1 = string.Empty;

		public string GearName3 = string.Empty;

		public bool HasStats;

		public int Healing;

		public bool IsAlive = true;

		public bool IsLocal;

		public string Name = string.Empty;

		public int PingMs = -1;

		public int PlayerNumber;

		public int Revives;

		public int TargetKills;

		public ulong UserId;

		public void SetCharacterColor(float r, float g, float b, float a = 1f)
		{
			CharacterColorR = r;
			CharacterColorG = g;
			CharacterColorB = b;
			CharacterColorA = a;
		}

		public static string FormatStat(int value, bool hasStats)
		{
			if (!hasStats)
			{
				return "—";
			}
			return value.ToString();
		}

		public static string FormatPing(int pingMs)
		{
			if (pingMs < 0)
			{
				return "—";
			}
			return pingMs.ToString();
		}
	}
}
namespace Scoreboard.Config
{
	public static class ConfigManager
	{
		private const float DebounceSeconds = 0.25f;

		private static ConfigFile _config;

		private static ManualLogSource _logger;

		private static FileSystemWatcher _configWatcher;

		private static volatile bool _reloadPending;

		private static float _lastReloadTime;

		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<bool> NetworkingEnabled { get; private set; }

		public static ConfigEntry<bool> NetworkingDebug { get; private set; }

		public static ConfigEntry<Key> HoldKey { get; private set; }

		public static void Initialize(ConfigFile configFile, ManualLogSource log)
		{
			_config = configFile;
			_logger = log;
			Enabled = _config.Bind<bool>("General", "Enabled", true, "Master toggle for the scoreboard overlay.");
			NetworkingEnabled = _config.Bind<bool>("Networking", "Enabled", true, "Sync mission stats with other players who also have Scoreboard. Host must have the mod too.");
			NetworkingDebug = _config.Bind<bool>("Networking", "DebugLog", false, "Log hello/stats/full-state traffic to BepInEx console (off by default — was part of a log flood crash).");
			HoldKey = _config.Bind<Key>("Input", "HoldKey", (Key)72, "Hold this key to show the scoreboard (default: Caps Lock).");
			NetworkingEnabled.SettingChanged += OnNetworkingSettingChanged;
			NetworkingDebug.SettingChanged += OnNetworkingSettingChanged;
			ApplyNetworkingSettings();
			try
			{
				SetupFileWatcher();
			}
			catch (Exception ex)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
				}
			}
		}

		public static void Tick()
		{
			if (!_reloadPending || Time.unscaledTime - _lastReloadTime < 0.25f)
			{
				return;
			}
			_reloadPending = false;
			_lastReloadTime = Time.unscaledTime;
			try
			{
				_config.Reload();
				ApplyNetworkingSettings();
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)"Config reloaded from disk.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogError((object)("Error reloading config: " + ex.Message));
				}
			}
		}

		public static void Dispose()
		{
			if (NetworkingEnabled != null)
			{