Decompiled source of Match Stats v0.2.2

UCHMatchStats.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("UCHMatchStats")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.2.0")]
[assembly: AssemblyInformationalVersion("0.2.2")]
[assembly: AssemblyProduct("UCHMatchStats")]
[assembly: AssemblyTitle("UCHMatchStats")]
[assembly: AssemblyVersion("0.2.2.0")]
[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;
		}
	}
}
namespace UCHMatchStats
{
	internal static class FontPicker
	{
		private static bool done;

		private static Font font;

		internal static Font Get()
		{
			if (done)
			{
				return font;
			}
			done = true;
			string wanted = Plugin.FontName.Value.Trim();
			if (wanted.ToLowerInvariant() == "default")
			{
				return null;
			}
			try
			{
				Dictionary<Font, int> dictionary = new Dictionary<Font, int>();
				Text[] array = Resources.FindObjectsOfTypeAll<Text>();
				foreach (Text val in array)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val.font != (Object)null && val.font.dynamic)
					{
						dictionary.TryGetValue(val.font, out var value);
						dictionary[val.font] = value + 1;
					}
				}
				if (dictionary.Count == 0)
				{
					Plugin.LogVerbose("[Stats] No game font found, using the default font");
					done = false;
					return null;
				}
				Plugin.LogVerbose("[Stats] Fonts used by the game: " + string.Join(", ", (from u in dictionary
					orderby u.Value descending
					select $"{((Object)u.Key).name} ({u.Value})").ToArray()));
				if (wanted.Length > 0 && wanted.ToLowerInvariant() != "auto")
				{
					font = ((IEnumerable<Font>)dictionary.Keys).FirstOrDefault((Func<Font, bool>)((Font f) => ((Object)f).name == wanted));
					if ((Object)(object)font == (Object)null)
					{
						Plugin.Log.LogWarning((object)("[Stats] Font '" + wanted + "' not found, using the game's main font instead"));
					}
				}
				if ((Object)(object)font == (Object)null)
				{
					font = dictionary.OrderByDescending((KeyValuePair<Font, int> u) => u.Value).First().Key;
				}
				Plugin.Log.LogInfo((object)("[Stats] Panel font: " + ((Object)font).name));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Stats] Could not pick a game font: " + ex.Message));
				font = null;
			}
			return font;
		}
	}
	internal class PlayerStats
	{
		public int Number;

		public string RawName = "";

		public Animals Animal;

		public int Deaths;

		public int Kills;

		public int OwnTrapDeaths;

		public int FallDeaths;

		public int GaveUp;

		public int Goals;

		public int Coins;

		public int Blocks;

		public readonly Dictionary<int, int> KilledBy = new Dictionary<int, int>();

		public readonly Dictionary<string, int> DeathCauses = new Dictionary<string, int>();
	}
	internal static class MatchData
	{
		internal static readonly Dictionary<int, PlayerStats> Players = new Dictionary<int, PlayerStats>();

		internal static readonly Dictionary<string, int> TrapKills = new Dictionary<string, int>();

		internal static int Rounds;

		internal static bool Ended;

		internal static int Version;

		internal static void Reset()
		{
			Players.Clear();
			TrapKills.Clear();
			Rounds = 0;
			Ended = false;
			Version++;
		}

		internal static PlayerStats Get(int number)
		{
			if (!Players.TryGetValue(number, out var value))
			{
				value = new PlayerStats
				{
					Number = number
				};
				Players[number] = value;
				Version++;
			}
			return value;
		}

		internal static void Bump(Dictionary<string, int> map, string key)
		{
			map.TryGetValue(key, out var value);
			map[key] = value + 1;
		}

		internal static void Bump(Dictionary<int, int> map, int key)
		{
			map.TryGetValue(key, out var value);
			map[key] = value + 1;
		}

		internal static string NameOf(int number)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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)
			if (!Players.TryGetValue(number, out var value))
			{
				return "Player " + number;
			}
			string text = AnimalName(value.Animal);
			if (string.IsNullOrEmpty(value.RawName))
			{
				return text ?? ("Player " + number);
			}
			if (text != null && Plugin.AnimalNamesForLocal.Value)
			{
				string text2 = BaseName(value.RawName);
				foreach (PlayerStats value2 in Players.Values)
				{
					if (value2 == value || !(BaseName(value2.RawName) == text2))
					{
						continue;
					}
					foreach (PlayerStats value3 in Players.Values)
					{
						if (value3 != value && value3.Animal == value.Animal && BaseName(value3.RawName) == text2)
						{
							return text + " " + number;
						}
					}
					return text;
				}
			}
			return value.RawName;
		}

		private static string BaseName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "";
			}
			int num = name.Length;
			while (num > 0 && char.IsDigit(name[num - 1]))
			{
				num--;
			}
			if (num < name.Length && num > 0 && name[num - 1] == ' ')
			{
				return name.Substring(0, num - 1);
			}
			return name;
		}

		private unsafe static string AnimalName(Animals animal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)animal == 0)
			{
				return null;
			}
			string text = ((object)(*(Animals*)(&animal))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
			return char.ToUpperInvariant(text[0]) + text.Substring(1);
		}

		internal static string TrapName(string cause)
		{
			switch (cause)
			{
			case "SpikeBall":
				return "Spikey Ball";
			case "BarbedWire":
				return "Barbed Wire";
			case "LinearSaw":
				return "Saw";
			case "TennisBallLauncher":
				return "Ball Launcher";
			case "PunchingBlock":
				return "Boxing Glove";
			case "PunchingPlant":
				return "Punching Plant";
			case "LuckyWheel":
				return "Lucky Wheel";
			case "Drowning_In_Lava":
				return "Lava";
			default:
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < cause.Length; i++)
				{
					char c = cause[i];
					if (c == '_')
					{
						stringBuilder.Append(' ');
						continue;
					}
					if (i > 0 && char.IsUpper(c) && char.IsLower(cause[i - 1]))
					{
						stringBuilder.Append(' ');
					}
					stringBuilder.Append(c);
				}
				return stringBuilder.ToString();
			}
			}
		}
	}
	internal static class PanelSkin
	{
		private static bool loaded;

		internal static Texture2D Texture { get; private set; }

		internal static float Border { get; private set; } = 60f;

		internal static float Padding { get; private set; } = 22f;

		internal static Color TitleColor { get; private set; } = new Color(1f, 0.82f, 0.25f);

		internal static Color HeaderColor { get; private set; } = new Color(0.75f, 0.78f, 0.9f);

		internal static Color TextColor { get; private set; } = Color.white;

		internal static Color LineColor { get; private set; } = new Color(0.95f, 0.95f, 0.9f);

		internal static Color HintColor { get; private set; } = new Color(0.65f, 0.65f, 0.7f);

		internal static bool HasTexture
		{
			get
			{
				Load();
				return (Object)(object)Texture != (Object)null;
			}
		}

		private static string Find(string file)
		{
			string path = Path.GetDirectoryName(typeof(PanelSkin).Assembly.Location) ?? ".";
			string text = Path.Combine(Path.Combine(path, "textures"), file);
			if (File.Exists(text))
			{
				return text;
			}
			string text2 = Path.Combine(path, file);
			if (!File.Exists(text2))
			{
				return null;
			}
			return text2;
		}

		internal static void Load()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (loaded)
			{
				return;
			}
			loaded = true;
			try
			{
				string text = Find("panel.txt");
				if (text != null)
				{
					ReadSettings(text);
				}
				string text2 = Find("panel.png");
				if (text2 == null)
				{
					Plugin.LogVerbose("[Stats] No panel.png found, using the built-in panel");
					return;
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(text2)))
				{
					Plugin.Log.LogWarning((object)"[Stats] panel.png could not be read, using the built-in panel");
					return;
				}
				((Texture)val).filterMode = (FilterMode)1;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				Texture = val;
				Plugin.Log.LogInfo((object)$"[Stats] Custom panel loaded: {((Texture)val).width} x {((Texture)val).height}, border {Border}, padding {Padding}");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Stats] Could not load the custom panel: " + ex.Message));
			}
		}

		private static void ReadSettings(string path)
		{
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				int num = text.IndexOf('=');
				if (!text.StartsWith("#") && num >= 0)
				{
					string text2 = text.Substring(0, num).Trim();
					string s = text.Substring(num + 1).Trim();
					switch (text2)
					{
					case "border":
						Border = Number(s, Border);
						break;
					case "padding":
						Padding = Number(s, Padding);
						break;
					case "title_color":
						TitleColor = Hex(s, TitleColor);
						break;
					case "header_color":
						HeaderColor = Hex(s, HeaderColor);
						break;
					case "text_color":
						TextColor = Hex(s, TextColor);
						break;
					case "line_color":
						LineColor = Hex(s, LineColor);
						break;
					case "hint_color":
						HintColor = Hex(s, HintColor);
						break;
					}
				}
			}
		}

		private static float Number(string s, float fallback)
		{
			if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return fallback;
			}
			return result;
		}

		private static Color Hex(string s, Color fallback)
		{
			//IL_0026: 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)
			Color result = default(Color);
			if (!ColorUtility.TryParseHtmlString(s.StartsWith("#") ? s : ("#" + s), ref result))
			{
				return fallback;
			}
			return result;
		}

		internal static void Draw(Rect box)
		{
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: 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)
			Texture2D texture = Texture;
			float num = ((Rect)(ref box)).width / (float)((Texture)texture).width;
			float num2 = Mathf.Min(new float[3]
			{
				Border * num,
				((Rect)(ref box)).width / 2f,
				((Rect)(ref box)).height / 2f
			});
			float num3 = Mathf.Clamp(Border / (float)((Texture)texture).width, 0f, 0.5f);
			float num4 = Mathf.Clamp(Border / (float)((Texture)texture).height, 0f, 0.5f);
			float[] array = new float[4]
			{
				Mathf.Round(((Rect)(ref box)).x),
				Mathf.Round(((Rect)(ref box)).x + num2),
				Mathf.Round(((Rect)(ref box)).xMax - num2),
				Mathf.Round(((Rect)(ref box)).xMax)
			};
			float[] array2 = new float[4]
			{
				Mathf.Round(((Rect)(ref box)).y),
				Mathf.Round(((Rect)(ref box)).y + num2),
				Mathf.Round(((Rect)(ref box)).yMax - num2),
				Mathf.Round(((Rect)(ref box)).yMax)
			};
			float[] array3 = new float[4]
			{
				0f,
				num3,
				1f - num3,
				1f
			};
			float[] array4 = new float[4]
			{
				1f,
				1f - num4,
				num4,
				0f
			};
			Rect val2 = default(Rect);
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					Rect val = Rect.MinMaxRect(array[j], array2[i], array[j + 1], array2[i + 1]);
					if (!(((Rect)(ref val)).width <= 0f) && !(((Rect)(ref val)).height <= 0f))
					{
						((Rect)(ref val2))..ctor(array3[j], array4[i + 1], array3[j + 1] - array3[j], array4[i] - array4[i + 1]);
						GUI.DrawTextureWithTexCoords(val, (Texture)(object)texture, val2, true);
					}
				}
			}
		}
	}
	[BepInPlugin("mpb27.uch.matchstats", "UCH Match Stats", "0.2.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "mpb27.uch.matchstats";

		public const string Name = "UCH Match Stats";

		public const string Version = "0.2.2";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ModEnabled;

		internal static ConfigEntry<bool> ShowAtMatchEnd;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<int> HighlightCount;

		internal static ConfigEntry<float> EndDelay;

		internal static ConfigEntry<string> FontName;

		internal static ConfigEntry<bool> AnimalNamesForLocal;

		internal static ConfigEntry<bool> VerboseLog;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns the whole mod on or off.");
			ShowAtMatchEnd = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowAtMatchEnd", true, "Open the stats panel automatically when a match ends.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Display", "ToggleKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Opens and closes the stats panel at any time, also in the middle of a match.");
			HighlightCount = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "HighlightCount", 8, new ConfigDescription("How many highlight lines are shown.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
			EndDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "EndDelay", 2f, new ConfigDescription("Seconds after the match ends before the panel opens.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), Array.Empty<object>()));
			AnimalNamesForLocal = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AnimalNamesForLocalPlayers", true, "Several players on one machine share one account name. true = show them by their animal (Horse, Chicken ...), false = show the name with the number the game appends.");
			FontName = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "Font", "auto", "Font of the panel. auto = the font the game uses most in its menus, default = plain system font, or the exact name of a game font (the names are listed in the log).");
			VerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLog", true, "Log every recorded death, point and placed block.");
			if (!ModEnabled.Value)
			{
				Log.LogInfo((object)"UCH Match Stats 0.2.2 loaded, but disabled in the config.");
				return;
			}
			harmony = new Harmony("mpb27.uch.matchstats");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((Component)this).gameObject.AddComponent<Tracker>();
			((Component)this).gameObject.AddComponent<StatsWindow>();
			int num = 0;
			foreach (MethodBase patchedMethod in harmony.GetPatchedMethods())
			{
				_ = patchedMethod;
				num++;
			}
			Log.LogInfo((object)string.Format("{0} {1} loaded, {2} method(s) patched. Toggle key: {3}", "UCH Match Stats", "0.2.2", num, ToggleKey.Value));
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		internal static void LogVerbose(string msg)
		{
			if (VerboseLog.Value)
			{
				Log.LogInfo((object)msg);
			}
		}
	}
	internal static class Report
	{
		private class Line
		{
			public float Weight;

			public string Text;
		}

		private static int seed = 1;

		internal static void NewSeed()
		{
			seed = Environment.TickCount;
		}

		private static string Pick(Random rng, params string[] variants)
		{
			return variants[rng.Next(variants.Length)];
		}

		private static string Times(int n)
		{
			return n switch
			{
				2 => "twice", 
				1 => "once", 
				_ => n + " times", 
			};
		}

		private static string Cap(string s)
		{
			if (!string.IsNullOrEmpty(s))
			{
				return char.ToUpperInvariant(s[0]) + s.Substring(1);
			}
			return s;
		}

		internal static List<string> Highlights(int max)
		{
			List<Line> list = new List<Line>();
			Random rng = new Random(seed);
			List<PlayerStats> list2 = MatchData.Players.Values.OrderBy((PlayerStats p) => p.Number).ToList();
			int rounds = MatchData.Rounds;
			foreach (PlayerStats item in list2)
			{
				string text = MatchData.NameOf(item.Number);
				if (item.KilledBy.Count > 0)
				{
					KeyValuePair<int, int> keyValuePair = item.KilledBy.OrderByDescending((KeyValuePair<int, int> k) => k.Value).First();
					if (keyValuePair.Value >= 2)
					{
						string text2 = MatchData.NameOf(keyValuePair.Key);
						list.Add(new Line
						{
							Weight = 50 + keyValuePair.Value * 10,
							Text = Pick(rng, text + " was owned by " + text2 + ". Died " + Times(keyValuePair.Value) + " to their traps.", $"{text2} lives rent-free in {text}'s head: {keyValuePair.Value} kills.", text + " kept walking into " + text2 + "'s traps. " + Cap(Times(keyValuePair.Value)) + ".")
						});
					}
				}
				if (item.OwnTrapDeaths >= 1)
				{
					list.Add(new Line
					{
						Weight = 45 + item.OwnTrapDeaths * 12,
						Text = Pick(rng, text + " played themselves: died " + Times(item.OwnTrapDeaths) + " to their own traps.", text + " built a trap. " + text + " found the trap. " + Cap(Times(item.OwnTrapDeaths)) + ".", $"{text}'s worst enemy was {text}: {item.OwnTrapDeaths} self-inflicted deaths.")
					});
				}
				if (item.FallDeaths >= 2)
				{
					list.Add(new Line
					{
						Weight = 30 + item.FallDeaths * 6,
						Text = Pick(rng, $"{text} lost {item.FallDeaths} fights against gravity.", text + " forgot how jumping works " + Times(item.FallDeaths) + ".", "The floor was optional for " + text + ": fell " + Times(item.FallDeaths) + ".")
					});
				}
				if (item.GaveUp >= 2)
				{
					list.Add(new Line
					{
						Weight = 26 + item.GaveUp * 5,
						Text = Pick(rng, text + " gave up on the round " + Times(item.GaveUp) + ".", text + " hit the panic button " + Times(item.GaveUp) + ".")
					});
				}
				if (item.DeathCauses.TryGetValue("LuckyWheel", out var value) && value >= 1)
				{
					list.Add(new Line
					{
						Weight = 42 + value * 8,
						Text = Pick(rng, text + " gambled at the Lucky Wheel and lost " + Times(value) + ".", $"The house always wins. Ask {text}: {value} lost spins.")
					});
				}
				if (rounds >= 3 && item.Goals == 0)
				{
					list.Add(new Line
					{
						Weight = 38f,
						Text = Pick(rng, text + " has not seen the goal up close. Not once.", text + " heard rumours of a goal. Never confirmed.")
					});
				}
				if (item.Blocks >= 3 && item.Kills == 0)
				{
					list.Add(new Line
					{
						Weight = 28 + item.Blocks,
						Text = Pick(rng, $"{text} placed {item.Blocks} blocks and hurt nobody. Interior designer.", $"{text} placed {item.Blocks} blocks. All of them harmless.")
					});
				}
			}
			for (int num = 0; num < list2.Count; num++)
			{
				for (int num2 = num + 1; num2 < list2.Count; num2++)
				{
					list2[num].KilledBy.TryGetValue(list2[num2].Number, out var value2);
					list2[num2].KilledBy.TryGetValue(list2[num].Number, out var value3);
					if (value2 >= 2 && value3 >= 2)
					{
						string text3 = MatchData.NameOf(list2[num].Number);
						string text4 = MatchData.NameOf(list2[num2].Number);
						list.Add(new Line
						{
							Weight = 58 + (value2 + value3) * 4,
							Text = Pick(rng, $"{text3} and {text4} have beef: {value3} to {value2} in kills.", $"{text3} vs {text4} got personal: {value3} to {value2}.")
						});
					}
				}
			}
			if (list2.Count >= 2)
			{
				PlayerStats killer = list2.OrderByDescending((PlayerStats p) => p.Kills).First();
				int value4;
				bool flag = list2.Any((PlayerStats p) => p != killer && p.KilledBy.TryGetValue(killer.Number, out value4) && value4 == killer.Kills);
				if (killer.Kills >= 2 && !flag)
				{
					string arg = MatchData.NameOf(killer.Number);
					list.Add(new Line
					{
						Weight = 55 + killer.Kills * 5,
						Text = Pick(rng, $"{arg} is the trap master with {killer.Kills} kills.", $"{arg} chose violence: {killer.Kills} kills.", $"Nobody was safe from {arg}: {killer.Kills} kills.")
					});
				}
				PlayerStats playerStats = list2.OrderByDescending((PlayerStats p) => p.Deaths).First();
				if (playerStats.Deaths >= 3)
				{
					string text5 = MatchData.NameOf(playerStats.Number);
					list.Add(new Line
					{
						Weight = 35 + playerStats.Deaths * 4,
						Text = Pick(rng, text5 + " died " + Times(playerStats.Deaths) + ". Someone check on them.", $"{text5} found {playerStats.Deaths} different ways to not finish.")
					});
				}
				if (rounds >= 3)
				{
					PlayerStats playerStats2 = list2.OrderBy((PlayerStats p) => p.Deaths).First();
					if (playerStats2 != playerStats)
					{
						string text6 = MatchData.NameOf(playerStats2.Number);
						list.Add(new Line
						{
							Weight = ((playerStats2.Deaths == 0) ? 44 : 30),
							Text = ((playerStats2.Deaths == 0) ? Pick(rng, text6 + " never died. Suspicious.", text6 + " went the whole match without dying. Show-off.") : Pick(rng, $"{text6} barely got a scratch: only {playerStats2.Deaths} deaths.", $"{text6} was hard to kill: just {playerStats2.Deaths} deaths."))
						});
					}
				}
				PlayerStats playerStats3 = list2.OrderByDescending((PlayerStats p) => p.Goals).First();
				if (playerStats3.Goals >= 2)
				{
					string text7 = MatchData.NameOf(playerStats3.Number);
					list.Add(new Line
					{
						Weight = 32 + playerStats3.Goals * 3,
						Text = Pick(rng, text7 + " reached the goal " + Times(playerStats3.Goals) + ". Show-off.", $"{text7} made it look easy: {playerStats3.Goals} finishes.")
					});
				}
				PlayerStats playerStats4 = list2.OrderByDescending((PlayerStats p) => p.Coins).First();
				if (playerStats4.Coins >= 2)
				{
					string arg2 = MatchData.NameOf(playerStats4.Number);
					list.Add(new Line
					{
						Weight = 30 + playerStats4.Coins * 4,
						Text = Pick(rng, $"{arg2} is the coin goblin: {playerStats4.Coins} coins.", $"{arg2} only came for the money: {playerStats4.Coins} coins.")
					});
				}
			}
			if (MatchData.TrapKills.Count > 0)
			{
				KeyValuePair<string, int> keyValuePair2 = MatchData.TrapKills.OrderByDescending((KeyValuePair<string, int> t) => t.Value).First();
				if (keyValuePair2.Value >= 2)
				{
					string arg3 = MatchData.TrapName(keyValuePair2.Key);
					list.Add(new Line
					{
						Weight = 40 + keyValuePair2.Value * 5,
						Text = Pick(rng, $"Deadliest trap: {arg3} with {keyValuePair2.Value} victims.", $"The {arg3} did most of the work: {keyValuePair2.Value} victims.")
					});
				}
			}
			return (from l in list.OrderByDescending((Line l) => l.Weight).Take(max)
				select l.Text).ToList();
		}

		internal static string BuildText(int maxHighlights)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(string.Format("=== MATCH STATS ({0} round{1}) ===", MatchData.Rounds, (MatchData.Rounds == 1) ? "" : "s"));
			stringBuilder.AppendLine(string.Format("{0,-24}{1,7}{2,7}{3,6}{4,7}{5,7}{6,7}{7,8}", "Player", "Deaths", "Kills", "Own", "Falls", "Goals", "Coins", "Blocks"));
			foreach (PlayerStats item in MatchData.Players.Values.OrderBy((PlayerStats x) => x.Number))
			{
				stringBuilder.AppendLine($"{MatchData.NameOf(item.Number),-24}{item.Deaths,7}{item.Kills,7}{item.OwnTrapDeaths,6}{item.FallDeaths,7}{item.Goals,7}{item.Coins,7}{item.Blocks,8}");
			}
			List<string> list = Highlights(maxHighlights);
			if (list.Count > 0)
			{
				stringBuilder.AppendLine("--- Highlights ---");
				foreach (string item2 in list)
				{
					stringBuilder.AppendLine(item2);
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal class StatsWindow : MonoBehaviour
	{
		private static bool visible;

		private static bool autoShown;

		private GUIStyle title;

		private GUIStyle header;

		private GUIStyle cell;

		private GUIStyle nameCell;

		private GUIStyle line;

		private GUIStyle hint;

		private Texture2D background;

		private float builtForHeight;

		private int cachedVersion = -1;

		private List<string> highlights = new List<string>();

		private readonly List<float> lineHeights = new List<float>();

		private static readonly string[] Columns = new string[7] { "Deaths", "Kills", "Own trap", "Falls", "Goals", "Coins", "Blocks" };

		private const float MinNameScale = 0.6f;

		internal static void Hide()
		{
			visible = false;
			autoShown = false;
			Report.NewSeed();
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ToggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				visible = !visible;
			}
			if (Plugin.ShowAtMatchEnd.Value && MatchData.Ended && !autoShown && Tracker.EndedAt > 0f && Time.unscaledTime - Tracker.EndedAt >= Plugin.EndDelay.Value)
			{
				autoShown = true;
				visible = true;
			}
		}

		private void BuildStyles(float scale)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_003a: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_008b: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			builtForHeight = Screen.height;
			PanelSkin.Load();
			background = new Texture2D(1, 1);
			background.SetPixel(0, 0, new Color(0.08f, 0.07f, 0.11f, 0.92f));
			background.Apply();
			title = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(30f * scale),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4,
				wordWrap = false
			};
			title.normal.textColor = PanelSkin.TitleColor;
			header = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(16f * scale),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4,
				wordWrap = false
			};
			header.normal.textColor = PanelSkin.HeaderColor;
			cell = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(19f * scale),
				alignment = (TextAnchor)4,
				wordWrap = false
			};
			cell.normal.textColor = PanelSkin.TextColor;
			nameCell = new GUIStyle(cell)
			{
				alignment = (TextAnchor)3,
				fontStyle = (FontStyle)1,
				clipping = (TextClipping)1
			};
			line = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(19f * scale),
				alignment = (TextAnchor)0,
				wordWrap = true
			};
			line.normal.textColor = PanelSkin.LineColor;
			hint = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(13f * scale),
				alignment = (TextAnchor)4,
				wordWrap = false
			};
			hint.normal.textColor = PanelSkin.HintColor;
			Font val = FontPicker.Get();
			if ((Object)(object)val != (Object)null)
			{
				GUIStyle[] array = (GUIStyle[])(object)new GUIStyle[6] { title, header, cell, nameCell, line, hint };
				for (int i = 0; i < array.Length; i++)
				{
					array[i].font = val;
				}
			}
		}

		private static void FitLabel(Rect rect, string text, GUIStyle style)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			int fontSize = style.fontSize;
			GUIContent val = new GUIContent(text);
			float x = style.CalcSize(val).x;
			if (x > ((Rect)(ref rect)).width)
			{
				style.fontSize = Mathf.Max(Mathf.RoundToInt((float)fontSize * 0.6f), Mathf.FloorToInt((float)fontSize * ((Rect)(ref rect)).width / x));
				while (text.Length > 4 && style.CalcSize(val).x > ((Rect)(ref rect)).width)
				{
					text = text.Substring(0, text.Length - 1);
					val.text = text.TrimEnd(Array.Empty<char>()) + "...";
				}
			}
			GUI.Label(rect, val, style);
			style.fontSize = fontSize;
		}

		private float MeasureLines(float textWidth, float minHeight, float gap)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			lineHeights.Clear();
			float num = 0f;
			foreach (string highlight in highlights)
			{
				float num2 = Mathf.Max(minHeight, line.CalcHeight(new GUIContent(highlight), textWidth) + gap);
				lineHeights.Add(num2);
				num += num2;
			}
			return num;
		}

		private void OnGUI()
		{
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: 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_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			if (!visible)
			{
				return;
			}
			float num = Mathf.Clamp((float)Screen.height / 1080f, 0.6f, 2.5f);
			if (title == null || !Mathf.Approximately(builtForHeight, (float)Screen.height))
			{
				BuildStyles(num);
			}
			if (cachedVersion != MatchData.Version)
			{
				cachedVersion = MatchData.Version;
				highlights = Report.Highlights(Plugin.HighlightCount.Value);
			}
			List<PlayerStats> list = MatchData.Players.Values.OrderBy((PlayerStats p) => p.Number).ToList();
			float num2 = PanelSkin.Padding * num;
			float num3 = 30f * num;
			float num4 = 250f * num;
			float num5 = 96f * num;
			float num6 = num2 * 2f + num4 + num5 * (float)Columns.Length;
			float num7 = 26f * num;
			float num8 = num6 - num2 * 2f - num7;
			float num9 = MeasureLines(num8, 30f * num, 6f * num);
			int num10 = ((list.Count <= 0) ? 1 : (list.Count + 1));
			float num11 = num2 * 2f + 46f * num + num3 * (float)num10 + 14f * num + ((highlights.Count > 0) ? (34f * num + num9) : 0f) + 26f * num;
			num11 = Mathf.Min(num11, (float)Screen.height - 20f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((float)Screen.width - num6) / 2f, ((float)Screen.height - num11) / 2f, num6, num11);
			if (PanelSkin.HasTexture)
			{
				PanelSkin.Draw(val);
			}
			else
			{
				GUI.DrawTexture(val, (Texture)(object)background);
			}
			float num12 = ((Rect)(ref val)).x + num2;
			float num13 = ((Rect)(ref val)).y + num2;
			string text = MatchData.Rounds + ((MatchData.Rounds == 1) ? " round" : " rounds");
			GUI.Label(new Rect(((Rect)(ref val)).x, num13, num6, 40f * num), "MATCH STATS  -  " + text.ToUpperInvariant(), title);
			num13 += 46f * num;
			if (list.Count == 0)
			{
				GUI.Label(new Rect(((Rect)(ref val)).x, num13, num6, num3), "Nothing recorded yet.", cell);
				num13 += num3;
			}
			else
			{
				for (int num14 = 0; num14 < Columns.Length; num14++)
				{
					GUI.Label(new Rect(num12 + num4 + (float)num14 * num5, num13, num5, num3), Columns[num14], header);
				}
				num13 += num3;
				foreach (PlayerStats item in list)
				{
					FitLabel(new Rect(num12, num13, num4 - 8f * num, num3), MatchData.NameOf(item.Number), nameCell);
					int[] array = new int[7] { item.Deaths, item.Kills, item.OwnTrapDeaths, item.FallDeaths, item.Goals, item.Coins, item.Blocks };
					for (int num15 = 0; num15 < array.Length; num15++)
					{
						GUI.Label(new Rect(num12 + num4 + (float)num15 * num5, num13, num5, num3), array[num15].ToString(), cell);
					}
					num13 += num3;
				}
			}
			num13 += 14f * num;
			if (highlights.Count > 0)
			{
				GUI.Label(new Rect(num12, num13, num6 - num2 * 2f, 30f * num), "HIGHLIGHTS", header);
				num13 += 34f * num;
				for (int num16 = 0; num16 < highlights.Count; num16++)
				{
					GUI.Label(new Rect(num12, num13, num7, lineHeights[num16]), "•", line);
					GUI.Label(new Rect(num12 + num7, num13, num8, lineHeights[num16]), highlights[num16], line);
					num13 += lineHeights[num16];
				}
			}
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).yMax - num2 - 22f * num, num6, 22f * num), "Press " + ((object)Plugin.ToggleKey.Value/*cast due to .constrained prefix*/).ToString() + " to close", hint);
		}
	}
	internal class Tracker : MonoBehaviour
	{
		private const float ScanInterval = 0.25f;

		private const float SameDeathWindow = 0.5f;

		private static readonly Dictionary<int, float> lastDeath = new Dictionary<int, float>();

		private static readonly HashSet<int> reachedGoal = new HashSet<int>();

		private GameControl controller;

		private GamePhase phase;

		private float nextScan;

		internal static float EndedAt { get; private set; } = -1f;

		private static bool InRun(GamePhase p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)p != 2)
			{
				return (int)p == 4;
			}
			return true;
		}

		private void Update()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00a4: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			LobbyManager instance = LobbyManager.instance;
			GameControl val = (((Object)(object)instance != (Object)null) ? instance.CurrentGameController : null);
			if ((Object)(object)val == (Object)null)
			{
				controller = null;
				phase = (GamePhase)0;
				return;
			}
			if ((Object)(object)val != (Object)(object)controller)
			{
				controller = val;
				phase = (GamePhase)0;
				MatchData.Reset();
				lastDeath.Clear();
				reachedGoal.Clear();
				EndedAt = -1f;
				StatsWindow.Hide();
				Plugin.LogVerbose("[Stats] New match, statistics reset");
			}
			GamePhase val2 = val.Phase;
			if (val2 != phase)
			{
				OnPhaseChanged(phase, val2);
				phase = val2;
			}
			if (InRun(phase) && Time.unscaledTime >= nextScan)
			{
				nextScan = Time.unscaledTime + 0.25f;
				ScanCharacters();
			}
		}

		private void OnPhaseChanged(GamePhase from, GamePhase to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			if ((int)to == 2)
			{
				MatchData.Rounds++;
				MatchData.Version++;
				reachedGoal.Clear();
				ScanCharacters();
				Plugin.LogVerbose($"[Stats] Round {MatchData.Rounds} started");
			}
			else if ((int)to == 5 && !MatchData.Ended)
			{
				MatchData.Ended = true;
				MatchData.Version++;
				EndedAt = Time.unscaledTime;
				Plugin.Log.LogInfo((object)("[Stats] Match ended\n" + Report.BuildText(Plugin.HighlightCount.Value)));
			}
		}

		private static void ScanCharacters()
		{
			Character[] array = Object.FindObjectsOfType<Character>();
			foreach (Character val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.networkNumber > 0)
				{
					PlayerStats playerStats = Register(val);
					if (val.Success && reachedGoal.Add(val.networkNumber))
					{
						playerStats.Goals++;
						MatchData.Version++;
						Plugin.LogVerbose($"[Stats] {MatchData.NameOf(playerStats.Number)} reached the goal ({playerStats.Goals})");
					}
				}
			}
		}

		private static PlayerStats Register(Character c)
		{
			//IL_0074: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			PlayerStats playerStats = MatchData.Get(c.networkNumber);
			string text = null;
			if ((Object)(object)c.AssociatedGamePlayer != (Object)null)
			{
				text = c.AssociatedGamePlayer.playerName;
			}
			if (string.IsNullOrEmpty(text) && (Object)(object)c.AssociatedLobbyPlayer != (Object)null)
			{
				text = c.AssociatedLobbyPlayer.playerName;
			}
			if (!string.IsNullOrEmpty(text) && text != playerStats.RawName)
			{
				playerStats.RawName = text;
				MatchData.Version++;
			}
			if ((int)c.CharacterSprite != 0 && c.CharacterSprite != playerStats.Animal)
			{
				playerStats.Animal = c.CharacterSprite;
				MatchData.Version++;
			}
			return playerStats;
		}

		internal static void OnDeath(Character victim, string cause, int killerNumber)
		{
			if (MatchData.Ended || (Object)(object)victim == (Object)null || victim.networkNumber <= 0 || string.IsNullOrEmpty(cause) || cause == "Retry")
			{
				return;
			}
			int networkNumber = victim.networkNumber;
			if (lastDeath.TryGetValue(networkNumber, out var value) && Time.unscaledTime - value < 0.5f)
			{
				return;
			}
			lastDeath[networkNumber] = Time.unscaledTime;
			PlayerStats playerStats = Register(victim);
			playerStats.Deaths++;
			MatchData.Bump(playerStats.DeathCauses, cause);
			string text;
			switch (cause)
			{
			case "Falling":
			case "Drowning":
			case "Drowning_In_Lava":
				playerStats.FallDeaths++;
				text = "fell";
				break;
			case "Suicide":
			case "Run Timer":
			case "AFK Auto-Kill":
				playerStats.GaveUp++;
				text = "gave up / timed out";
				break;
			default:
				if (killerNumber == networkNumber)
				{
					playerStats.OwnTrapDeaths++;
					MatchData.Bump(MatchData.TrapKills, cause);
					text = "own trap";
				}
				else if (killerNumber > 0)
				{
					MatchData.Bump(playerStats.KilledBy, killerNumber);
					MatchData.Get(killerNumber).Kills++;
					MatchData.Bump(MatchData.TrapKills, cause);
					text = "trap of " + MatchData.NameOf(killerNumber);
				}
				else
				{
					text = "level hazard";
				}
				break;
			}
			MatchData.Version++;
			Plugin.LogVerbose("[Stats] Death: " + MatchData.NameOf(networkNumber) + " by " + cause + " (" + text + ")");
		}

		internal static void OnPoint(PointBlock point)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (!MatchData.Ended && point != null && point.playerNumber > 0)
			{
				if ((int)point.type == 7)
				{
					MatchData.Get(point.playerNumber).Coins++;
					MatchData.Version++;
				}
				Plugin.LogVerbose($"[Stats] Point: {point.type} for {MatchData.NameOf(point.playerNumber)}");
			}
		}

		internal static void OnBlockPlaced(Placeable block, int playerNumber)
		{
			if (!MatchData.Ended && !((Object)(object)block == (Object)null) && playerNumber > 0 && (!((Object)(object)((Component)block).transform.parent != (Object)null) || !((Object)(object)((Component)((Component)block).transform.parent).GetComponentInParent<Placeable>() != (Object)null)))
			{
				MatchData.Get(playerNumber).Blocks++;
				Plugin.LogVerbose("[Stats] Block: " + MatchData.NameOf(playerNumber) + " placed '" + block.Name + "'");
				MatchData.Version++;
			}
		}
	}
}
namespace UCHMatchStats.Patches
{
	[HarmonyPatch(typeof(Character), "setupDeath")]
	internal static class Character_setupDeath_Patch
	{
		private static void Postfix(Character __instance, string cause, int causedByPlayerNumber)
		{
			Tracker.OnDeath(__instance, cause, causedByPlayerNumber);
		}
	}
	[HarmonyPatch(typeof(ScoreKeeper), "addPointBlock")]
	internal static class ScoreKeeper_addPointBlock_Patch
	{
		private static void Postfix(PointBlock pointBlock)
		{
			Tracker.OnPoint(pointBlock);
		}
	}
	[HarmonyPatch(typeof(Placeable), "Place", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(bool)
	})]
	internal static class Placeable_Place_Patch
	{
		private static void Postfix(Placeable __instance, int playerNumber)
		{
			Tracker.OnBlockPlaced(__instance, playerNumber);
		}
	}
}