Decompiled source of Classes v0.5.0

UCHClasses.dll

Decompiled an hour ago
using System;
using System.Collections;
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 GameEvent;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using UnityEngine.Networking;
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("UCHClasses")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: AssemblyInformationalVersion("0.5.0")]
[assembly: AssemblyProduct("UCHClasses")]
[assembly: AssemblyTitle("UCHClasses")]
[assembly: AssemblyVersion("0.5.0.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 UCHClasses
{
	internal static class Abilities
	{
		private const float DashSpeed = 26f;

		private const float DashTime = 0.18f;

		private const float SlamSpeed = 42f;

		private const float PullSpeed = 28f;

		private const float GrappleRange = 11f;

		internal static void Tick(Character c, PlayerState s)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_00a0: 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_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0efe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c76: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e59: Unknown result type (might be due to invalid IL or missing references)
			//IL_0dfc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e85: Unknown result type (might be due to invalid IL or missing references)
			//IL_0810: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_084a: Unknown result type (might be due to invalid IL or missing references)
			//IL_084f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0857: Unknown result type (might be due to invalid IL or missing references)
			//IL_0870: Unknown result type (might be due to invalid IL or missing references)
			//IL_0944: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			//IL_0772: Unknown result type (might be due to invalid IL or missing references)
			//IL_0774: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05da: Unknown result type (might be due to invalid IL or missing references)
			//IL_05df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0780: Unknown result type (might be due to invalid IL or missing references)
			//IL_0782: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_09bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bc5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0604: Unknown result type (might be due to invalid IL or missing references)
			//IL_09cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0617: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d12: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d17: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d1c: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a06: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d2c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0515: Unknown result type (might be due to invalid IL or missing references)
			//IL_0662: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d43: Unknown result type (might be due to invalid IL or missing references)
			bool flag = c.LocalPlayer != null && (Object)(object)c.LocalPlayer.UseController != (Object)null && (int)c.LocalPlayer.UseController.GetControllerType() == 0;
			bool flag2 = (c.rotateRight && !c.rotateLeft) || (flag && Runtime.KeyHeld);
			bool flag3 = (c.rotateRightDown && !c.rotateLeftDown) || (flag && Runtime.TakeKeyDown());
			s.PrevKey = flag2;
			if (s.CarriedBy > 0 && s.Class == ClassId.Sticky && c.jumpDown)
			{
				ClassNet.SendEffect(EffectKind.Release, s.Number, s.CarriedBy, Vector2.zero, 0f);
				s.CarriedBy = 0;
				Classes.Body(c).velocity = new Vector2(0f, 14f);
				Plugin.LogVerbose($"[Ability] Player {s.Number}: jumped off the carrier");
			}
			if (s.Class == ClassId.Ghost && flag3 && !s.UsedThisRound && Runtime.AbilitiesAllowed && (c.Dead || c.Dying))
			{
				Character val = null;
				float num = float.MaxValue;
				foreach (Character item in Classes.Players())
				{
					float num2 = Vector2.Distance(Vector2.op_Implicit(((Component)item).transform.position), Vector2.op_Implicit(((Component)c).transform.position));
					if ((Object)(object)item != (Object)(object)c && Classes.Alive(item) && num2 < num)
					{
						num = num2;
						val = item;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					float num3 = ((Random.value < 0.5f) ? (-1f) : 1f);
					ClassNet.SendEffect(EffectKind.Push, s.Number, val.networkNumber, new Vector2(num3 * 22f, 16f), 0f);
					s.UsedThisRound = true;
					ClassNet.SendEffect(EffectKind.Haunt, s.Number, val.networkNumber, Vector2.zero, 0f);
					Runtime.Flash(Classes.DisplayName(c) + " haunts " + Classes.DisplayName(val));
					if (val.networkNumber == s.LastKiller && ScoreKeeper.Instance != null)
					{
						ScoreKeeper.Instance.AwardPoint(new PointBlock((pointBlockType)7, s.Number), false);
						Runtime.Flash(Classes.DisplayName(c) + ": revenge from the grave");
					}
				}
			}
			if (!Runtime.AbilitiesAllowed || !Classes.Alive(c) || c.Frozen)
			{
				s.ExplodeAt = 0f;
				s.Slamming = false;
				s.DashUntil = 0f;
				s.PullUntil = 0f;
				if (s.ShieldUp)
				{
					s.ShieldUp = false;
					ClassNet.SendEffect(EffectKind.Shield, s.Number, 0, Vector2.zero, 0f);
				}
				return;
			}
			float time = Time.time;
			Vector2 val2 = Vector2.op_Implicit(((Component)c).transform.position);
			if (Runtime.InLobby)
			{
				s.UsedThisRound = false;
				s.CooldownUntil = Mathf.Min(s.CooldownUntil, time + 0.3f);
			}
			switch (s.Class)
			{
			case ClassId.Sprinter:
				if (flag3 && time >= s.CooldownUntil)
				{
					float num4 = c.right - c.left;
					if (Mathf.Abs(num4) < 0.2f)
					{
						num4 = Classes.Facing(c);
					}
					s.DashDir = ((num4 < 0f) ? (-1f) : 1f);
					s.DashUntil = time + 0.18f;
					s.CooldownUntil = time + 2.5f;
					ClassNet.SendEffect(EffectKind.Dash, s.Number, 0, new Vector2(s.DashDir, 0f), 0.3f);
					Plugin.LogVerbose($"[Ability] Player {s.Number}: dash");
				}
				if (!(time < s.DashUntil))
				{
					break;
				}
				if (time < s.StuckUntil)
				{
					s.DashUntil = 0f;
					break;
				}
				{
					foreach (Character item2 in Classes.Players())
					{
						Vector2 val5 = Vector2.op_Implicit(((Component)item2).transform.position) - val2;
						if ((Object)(object)item2 != (Object)(object)c && Classes.Alive(item2) && Mathf.Abs(val5.y) < 1f && val5.x * s.DashDir > 0f && Mathf.Abs(val5.x) < 1.4f && Runtime.ShieldCovers(item2, val2))
						{
							s.DashUntil = 0f;
							Classes.Body(c).velocity = new Vector2((0f - s.DashDir) * 14f, 9f);
							Runtime.Flash(Classes.DisplayName(c) + " bounced off a shield");
							break;
						}
					}
					break;
				}
			case ClassId.Stomper:
				if (flag3 && !c.OnGround && !s.Slamming && time >= s.CooldownUntil)
				{
					s.Slamming = true;
					s.DashUntil = time + 3f;
					Plugin.LogVerbose($"[Ability] Player {s.Number}: slam");
				}
				if (s.Slamming)
				{
					foreach (Character item3 in Classes.Players())
					{
						Vector2 val3 = val2 - Vector2.op_Implicit(((Component)item3).transform.position);
						if ((Object)(object)item3 != (Object)(object)c && Classes.Alive(item3) && Classes.Of(item3) == ClassId.Giant && Mathf.Abs(val3.x) < 1.2f && val3.y > 0f && val3.y < 2.3f)
						{
							s.Slamming = false;
							s.DashUntil = 0f;
							s.CooldownUntil = time + 1.5f;
							Classes.Body(c).velocity = new Vector2(0f, 27f);
							Runtime.Flash(Classes.DisplayName(c) + " bounced off the Giant");
							break;
						}
					}
				}
				if (s.Slamming && (c.OnGround || time > s.DashUntil))
				{
					s.Slamming = false;
					s.DashUntil = 0f;
					s.CooldownUntil = time + 1.5f;
					if (c.OnGround)
					{
						Shockwave(c, 3.5f, 16f, 12f);
					}
				}
				break;
			case ClassId.Grappler:
				if (flag3 && !s.UsedThisRound && time >= s.PullUntil)
				{
					Vector2 dir = default(Vector2);
					((Vector2)(ref dir))..ctor(c.right - c.left, c.up - c.down);
					if (((Vector2)(ref dir)).magnitude < 0.3f)
					{
						((Vector2)(ref dir))..ctor((Classes.Facing(c) < 0) ? (-1f) : 1f, 1f);
					}
					((Vector2)(ref dir)).Normalize();
					if (FindGrapplePoint(val2, dir, out var point))
					{
						s.PullTarget = point;
						s.PullUntil = time + 0.7f;
						s.UsedThisRound = true;
						ClassNet.SendEffect(EffectKind.Rope, s.Number, 0, point, 0.7f);
						Plugin.LogVerbose($"[Ability] Player {s.Number}: grapple to {point}");
					}
				}
				if (time < s.PullUntil)
				{
					Vector2 val8 = s.PullTarget - val2;
					if (((Vector2)(ref val8)).magnitude < 0.9f)
					{
						s.PullUntil = 0f;
						ClassNet.SendEffect(EffectKind.Rope, s.Number, 0, s.PullTarget, 0f);
					}
				}
				break;
			case ClassId.Teleporter:
				if (flag3)
				{
					if (!s.HasMark && !s.UsedThisRound)
					{
						s.HasMark = true;
						s.MarkPos = ((Component)c).transform.position;
						s.MarkObj = Visuals.Dot(c, s.MarkPos, new Color(0.3f, 0.9f, 1f, 0.9f), ((Object)(object)Visuals.Art("marker") != (Object)null) ? 1f : 0.5f, "marker");
						Plugin.LogVerbose($"[Ability] Player {s.Number}: mark set");
					}
					else if (s.HasMark)
					{
						c.PositionCharacter(s.MarkPos, false);
						c.ClearVelocity();
						c.LockInputTemporarily(0.7f);
						s.ClearMark();
						s.UsedThisRound = true;
						Plugin.LogVerbose($"[Ability] Player {s.Number}: jumped back to the mark");
					}
				}
				break;
			case ClassId.Shield:
			{
				bool flag4 = flag2 && c.OnGround && !s.ShieldBroken;
				if (flag4 != s.ShieldUp)
				{
					s.ShieldUp = flag4;
					ClassNet.SendEffect(EffectKind.Shield, s.Number, 0, Vector2.zero, flag4 ? 1f : 0f);
				}
				break;
			}
			case ClassId.Shover:
			{
				if (!flag3 || !(time >= s.CooldownUntil))
				{
					break;
				}
				bool flag5 = false;
				foreach (Character item4 in Classes.Players())
				{
					if (!((Object)(object)item4 == (Object)(object)c) && Classes.Alive(item4))
					{
						Vector2 val7 = Vector2.op_Implicit(((Component)item4).transform.position) - val2;
						if (((Vector2)(ref val7)).magnitude <= 1.9f)
						{
							float num5 = ((val7.x < 0f) ? (-1f) : 1f);
							ClassNet.SendEffect(EffectKind.Push, s.Number, item4.networkNumber, new Vector2(num5 * 20f, 9f), 0f);
							c.AddImpulse(new Vector2((0f - num5) * 9f, 5f), 0.1f, false);
							flag5 = true;
						}
					}
				}
				s.CooldownUntil = time + (flag5 ? 3f : 1f);
				Plugin.LogVerbose($"[Ability] Player {s.Number}: shove, hit={flag5}");
				break;
			}
			case ClassId.Screamer:
				if (flag3 && time >= s.CooldownUntil)
				{
					Shockwave(c, 4.5f, 15f, 9f);
					if (Runtime.SlowMoActive)
					{
						ClassNet.SendEffect(EffectKind.SlowMoEnd, s.Number, 0, Vector2.zero, 0f);
					}
					c.LockInputTemporarily(0.8f);
					s.CooldownUntil = time + 8f;
					Plugin.LogVerbose($"[Ability] Player {s.Number}: scream");
				}
				break;
			case ClassId.Swapper:
			{
				if (!flag3 || s.UsedThisRound)
				{
					break;
				}
				List<Character> list = new List<Character>();
				foreach (Character item5 in Classes.Players())
				{
					if ((Object)(object)item5 != (Object)(object)c && Classes.Alive(item5) && !Runtime.ShieldIsUp(item5.networkNumber))
					{
						list.Add(item5);
					}
				}
				if (list.Count > 0)
				{
					Character val6 = list[Random.Range(0, list.Count)];
					Vector3 position = ((Component)val6).transform.position;
					ClassNet.SendEffect(EffectKind.Swap, s.Number, val6.networkNumber, val2, 0f);
					c.PositionCharacter(position, false);
					c.ClearVelocity();
					s.UsedThisRound = true;
					Plugin.LogVerbose($"[Ability] Player {s.Number}: swapped with player {val6.networkNumber}");
				}
				break;
			}
			case ClassId.Carrier:
				if (s.CarryTarget > 0 && time >= s.CarryingUntil)
				{
					s.CarryTarget = 0;
				}
				if (!flag3)
				{
					break;
				}
				if (s.CarryTarget > 0 && Classes.Of(s.CarryTarget) == ClassId.Sticky)
				{
					Runtime.Flash(Classes.DisplayName(c) + " cannot shake off the Sticky player");
				}
				else if (s.CarryTarget > 0)
				{
					ClassNet.SendEffect(EffectKind.Throw, s.Number, s.CarryTarget, new Vector2((float)c.FlipSpriteX * 24f, 14f), 0f);
					s.CarryTarget = 0;
					s.CarryingUntil = 0f;
					s.CooldownUntil = time + 4f;
					Plugin.LogVerbose($"[Ability] Player {s.Number}: throw");
				}
				else
				{
					if (!(time >= s.CooldownUntil))
					{
						break;
					}
					{
						foreach (Character item6 in Classes.Players())
						{
							if ((Object)(object)item6 != (Object)(object)c && Classes.Alive(item6) && Classes.Of(item6) != ClassId.Giant && Vector2.Distance(Vector2.op_Implicit(((Component)item6).transform.position), val2) <= 1.7f && !Runtime.ShieldCovers(item6, val2))
							{
								ClassNet.SendEffect(EffectKind.Carry, s.Number, item6.networkNumber, Vector2.zero, 2.5f);
								s.CarryTarget = item6.networkNumber;
								s.CarryingUntil = time + 2.5f;
								s.CooldownUntil = time + 4f;
								Plugin.LogVerbose($"[Ability] Player {s.Number}: picked up player {item6.networkNumber}");
								break;
							}
						}
						break;
					}
				}
				break;
			case ClassId.Demolitionist:
				if (flag3 && !s.UsedThisRound && s.ExplodeAt <= 0f)
				{
					s.ExplodeAt = Time.unscaledTime + 1.5f;
					s.UsedThisRound = true;
					ClassNet.SendEffect(EffectKind.Fuse, s.Number, 0, Vector2.zero, 1.5f);
					Plugin.LogVerbose($"[Ability] Player {s.Number}: fuse lit");
				}
				if (s.ExplodeAt > 0f && Time.unscaledTime >= s.ExplodeAt)
				{
					s.ExplodeAt = 0f;
					ClassNet.SendEffect(EffectKind.Explode, s.Number, 0, val2, 3.2f);
				}
				break;
			case ClassId.Wrecker:
				if (flag3 && (Runtime.InLobby || Runtime.Round - s.LastWreckRound >= 3))
				{
					Placeable val4 = NearestPiece(val2, 2.5f);
					if ((Object)(object)val4 != (Object)null)
					{
						s.LastWreckRound = Runtime.Round;
						ClassNet.SendEffect(EffectKind.Destroy, s.Number, val4.ID, Vector2.zero, 0f);
						Plugin.LogVerbose($"[Ability] Player {s.Number}: wrecks '{((Object)val4).name}'");
					}
				}
				break;
			case ClassId.SlowMo:
				if (flag3 && !s.UsedThisRound)
				{
					ClassNet.SendEffect(EffectKind.SlowMo, s.Number, 0, Vector2.zero, 2.5f);
					s.UsedThisRound = true;
					Plugin.LogVerbose($"[Ability] Player {s.Number}: slow motion");
				}
				break;
			}
		}

		internal static void After(Character c, PlayerState s)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			Rigidbody2D val = Classes.Body(c);
			if (s.Class == ClassId.Sprinter && time < s.DashUntil)
			{
				val.velocity = new Vector2(s.DashDir * 26f, 0f);
			}
			else if (s.Class == ClassId.Stomper && s.Slamming)
			{
				val.velocity = new Vector2(0f, -42f);
			}
			else if (s.Class == ClassId.Grappler && time < s.PullUntil)
			{
				Vector2 val2 = s.PullTarget - Vector2.op_Implicit(((Component)c).transform.position);
				val.velocity = ((Vector2)(ref val2)).normalized * 28f;
			}
			if (s.CarriedBy > 0)
			{
				Character val3 = Classes.Find(s.CarriedBy);
				if (time >= s.CarriedUntil || !Classes.Alive(val3) || !Classes.Alive(c))
				{
					s.CarriedBy = 0;
					return;
				}
				Vector3 val4 = ((Component)val3).transform.position + new Vector3(0f, 1.25f * ((Component)val3).transform.localScale.y, 0f);
				val.position = Vector2.op_Implicit(val4);
				val.velocity = Vector2.zero;
			}
		}

		private static Placeable NearestPiece(Vector2 pos, float range)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			Placeable result = null;
			float num = range;
			foreach (Placeable allPlaceable in Placeable.AllPlaceables)
			{
				if ((Object)(object)allPlaceable == (Object)null || !allPlaceable.Placed || allPlaceable.inDestructible || allPlaceable.MarkedForDestruction || allPlaceable.placedByPlayerNumber <= 0 || allPlaceable is Coin)
				{
					continue;
				}
				Collider2D[] componentsInChildren = ((Component)allPlaceable).GetComponentsInChildren<Collider2D>();
				foreach (Collider2D val in componentsInChildren)
				{
					if (((Behaviour)val).enabled && !val.isTrigger)
					{
						float num2 = Vector2.Distance(val.ClosestPoint(pos), pos);
						if (num2 < num)
						{
							num = num2;
							result = allPlaceable;
						}
					}
				}
			}
			return result;
		}

		private static void Shockwave(Character c, float radius, float sideways, float upwards)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = Vector2.op_Implicit(((Component)c).transform.position);
			ClassNet.SendEffect(EffectKind.Ring, c.networkNumber, 0, val, radius);
			foreach (Character item in Classes.Players())
			{
				if (!((Object)(object)item == (Object)(object)c) && Classes.Alive(item))
				{
					Vector2 val2 = Vector2.op_Implicit(((Component)item).transform.position) - val;
					if (((Vector2)(ref val2)).magnitude <= radius)
					{
						float num = ((val2.x < 0f) ? (-1f) : 1f);
						ClassNet.SendEffect(EffectKind.Push, c.networkNumber, item.networkNumber, new Vector2(num * sideways, upwards), 0f);
					}
				}
			}
		}

		private static bool FindGrapplePoint(Vector2 origin, Vector2 dir, out Vector2 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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)
			point = origin;
			float num = float.MaxValue;
			RaycastHit2D[] array = Physics2D.RaycastAll(origin, dir, 11f);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit2D val = array[i];
				if (!((Object)(object)((RaycastHit2D)(ref val)).collider == (Object)null) && !((RaycastHit2D)(ref val)).collider.isTrigger && !(((RaycastHit2D)(ref val)).distance < 1f) && !(((RaycastHit2D)(ref val)).distance >= num) && !((Object)(object)((Component)((RaycastHit2D)(ref val)).collider).GetComponentInParent<Character>() != (Object)null))
				{
					num = ((RaycastHit2D)(ref val)).distance;
					point = ((RaycastHit2D)(ref val)).point;
				}
			}
			return num < float.MaxValue;
		}
	}
	internal static class Effects
	{
		internal static void Apply(ClassMsg msg)
		{
			//IL_0537: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: 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_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			if (!Classes.Active)
			{
				return;
			}
			switch ((EffectKind)msg.Kind)
			{
			case EffectKind.Push:
			{
				Character val3 = Classes.Find(msg.Target);
				if ((Object)(object)val3 == (Object)null || !Classes.IsLocal(val3) || !Classes.Alive(val3) || Classes.Of(val3) == ClassId.Giant)
				{
					break;
				}
				Character val4 = Classes.Find(msg.Source);
				if ((Object)(object)val4 != (Object)null && Runtime.ShieldCovers(val3, Vector2.op_Implicit(((Component)val4).transform.position)))
				{
					Runtime.Flash(Classes.DisplayName(val3) + ": shield held");
					break;
				}
				if (Classes.Of(val3) == ClassId.Lucky && Random.value < 0.25f)
				{
					Runtime.Flash(Classes.DisplayName(val3) + ": lucky, the shove missed");
					break;
				}
				Vector2 val5 = default(Vector2);
				((Vector2)(ref val5))..ctor(msg.X, msg.Y);
				if (Classes.Of(val3) == ClassId.Glider && !val3.OnGround)
				{
					((Vector2)(ref val5))..ctor(val5.x * 0.3f, 26f);
				}
				val3.AddImpulse(val5, 0.2f, false);
				Plugin.LogVerbose($"[Effect] Player {msg.Target} knocked away by player {msg.Source}");
				break;
			}
			case EffectKind.Swap:
			{
				Character val2 = Classes.Find(msg.Target);
				if (!((Object)(object)val2 == (Object)null) && Classes.IsLocal(val2) && Classes.Alive(val2))
				{
					if (Classes.Of(val2) == ClassId.Lucky && Random.value < 0.25f)
					{
						Runtime.Flash(Classes.DisplayName(val2) + ": lucky, the swap missed");
						break;
					}
					val2.PositionCharacter(new Vector3(msg.X, msg.Y, ((Component)val2).transform.position.z), false);
					val2.ClearVelocity();
					Plugin.LogVerbose($"[Effect] Player {msg.Target} swapped by player {msg.Source}");
				}
				break;
			}
			case EffectKind.SlowMo:
				Runtime.StartSlowMo(msg.F);
				break;
			case EffectKind.Shield:
				Runtime.ShowShield(msg.Source, msg.F > 0f);
				break;
			case EffectKind.Carry:
			{
				Character val7 = Classes.Find(msg.Target);
				if (!((Object)(object)val7 == (Object)null) && Classes.IsLocal(val7) && Classes.Alive(val7) && Classes.Of(val7) != ClassId.Giant)
				{
					PlayerState playerState4 = Classes.State(msg.Target);
					playerState4.CarriedBy = msg.Source;
					playerState4.CarriedUntil = Time.time + msg.F;
					Plugin.LogVerbose($"[Effect] Player {msg.Target} is carried by player {msg.Source}");
				}
				break;
			}
			case EffectKind.Throw:
			{
				Character val6 = Classes.Find(msg.Target);
				PlayerState playerState3 = Classes.State(msg.Target);
				if (!((Object)(object)val6 == (Object)null) && Classes.IsLocal(val6) && playerState3.CarriedBy == msg.Source)
				{
					playerState3.CarriedBy = 0;
					if (Classes.Of(val6) == ClassId.Tank && !playerState3.TankUsed)
					{
						playerState3.TankUsed = true;
						ClassNet.SendEffect(EffectKind.Status, playerState3.Number, playerState3.CatLives, Vector2.zero, 1f);
						Runtime.Flash(Classes.DisplayName(val6) + ": armour took the throw");
					}
					else
					{
						val6.AddImpulse(new Vector2(msg.X, msg.Y), 0.2f, false);
						Plugin.LogVerbose($"[Effect] Player {msg.Target} thrown by player {msg.Source}");
					}
				}
				break;
			}
			case EffectKind.Steal:
				Runtime.StealCoins(msg.Source, msg.Target);
				break;
			case EffectKind.Fuse:
				Runtime.ShowFuse(msg.Source, msg.F);
				break;
			case EffectKind.Ring:
				Runtime.ShowRing(msg.Source, new Vector2(msg.X, msg.Y), msg.F);
				break;
			case EffectKind.Status:
				if (!Classes.IsLocalNumber(msg.Source))
				{
					PlayerState playerState2 = Classes.State(msg.Source);
					playerState2.CatLives = msg.Target;
					playerState2.TankUsed = msg.F > 0f;
				}
				break;
			case EffectKind.Release:
			{
				Character val = Classes.Find(msg.Target);
				if ((Object)(object)val != (Object)null && Classes.IsLocal(val))
				{
					PlayerState playerState = Classes.State(msg.Target);
					playerState.CarryTarget = 0;
					playerState.CarryingUntil = 0f;
				}
				break;
			}
			case EffectKind.Revenge:
				Classes.State(msg.Source).Mark = 0;
				break;
			case EffectKind.SlowMoEnd:
				Runtime.StopSlowMo();
				break;
			case EffectKind.Haunt:
				Runtime.ShowAttached(msg.Target, "ghost", new Vector3(1.1f, 0.5f, 0f), 1.4f, 0.9f, flip: false);
				break;
			case EffectKind.Dash:
				Runtime.ShowAttached(msg.Source, "dash", new Vector3(-1.2f * msg.X, 0f, 0f), 1.8f, msg.F, msg.X < 0f);
				break;
			case EffectKind.Explode:
				Runtime.Explode(msg.Source, new Vector2(msg.X, msg.Y), msg.F);
				break;
			case EffectKind.Destroy:
				Runtime.DestroyPiece(msg.Source, msg.Target);
				break;
			case EffectKind.Rope:
				Runtime.ShowRope(msg.Source, new Vector2(msg.X, msg.Y), msg.F);
				break;
			}
		}
	}
	internal static class Visuals
	{
		private static Sprite dot;

		private static Material lineMaterial;

		private static bool ropeDrawn;

		private static readonly Dictionary<string, Sprite> art = new Dictionary<string, Sprite>();

		private static Sprite DotSprite()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_00bf: 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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)dot == (Object)null)
			{
				Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
				for (int i = 0; i < 32; i++)
				{
					for (int j = 0; j < 32; j++)
					{
						float num = Vector2.Distance(new Vector2((float)j, (float)i), new Vector2(16f, 16f)) / 16f;
						val.SetPixel(j, i, new Color(1f, 1f, 1f, (num < 0.85f) ? 1f : ((num < 1f) ? ((1f - num) / 0.15f) : 0f)));
					}
				}
				val.Apply();
				dot = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
			}
			return dot;
		}

		internal static LineRenderer Line(Character like, Color color, float width)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			GameObject val = new GameObject("UCHClasses_Line");
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			if ((Object)(object)lineMaterial == (Object)null)
			{
				lineMaterial = new Material(Shader.Find("Sprites/Default"));
				Sprite val3 = Art("rope");
				if ((Object)(object)val3 != (Object)null)
				{
					lineMaterial.mainTexture = (Texture)(object)val3.texture;
					ropeDrawn = true;
				}
			}
			((Renderer)val2).material = lineMaterial;
			if (ropeDrawn)
			{
				color = Color.white;
				width = 0.3f;
				val2.textureMode = (LineTextureMode)0;
			}
			Color startColor = (val2.endColor = color);
			val2.startColor = startColor;
			float startWidth = (val2.endWidth = width);
			val2.startWidth = startWidth;
			val2.positionCount = 2;
			val2.useWorldSpace = true;
			SpriteRenderer val5 = (((Object)(object)like != (Object)null) ? ((Component)like).GetComponentInChildren<SpriteRenderer>() : null);
			if ((Object)(object)val5 != (Object)null)
			{
				val.layer = ((Component)val5).gameObject.layer;
				((Renderer)val2).sortingLayerID = ((Renderer)val5).sortingLayerID;
				((Renderer)val2).sortingOrder = ((Renderer)val5).sortingOrder - 1;
			}
			return val2;
		}

		internal static Sprite Art(string name)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00b5: 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)
			if (art.TryGetValue(name, out var value))
			{
				return value;
			}
			Sprite val = null;
			try
			{
				string path = Path.GetDirectoryName(typeof(Visuals).Assembly.Location) ?? ".";
				string path2 = Path.Combine(Path.Combine(path, "textures"), name + ".png");
				if (!File.Exists(path2))
				{
					path2 = Path.Combine(path, name + ".png");
				}
				if (File.Exists(path2))
				{
					Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, false);
					if (ImageConversion.LoadImage(val2, File.ReadAllBytes(path2)))
					{
						((Texture)val2).wrapMode = (TextureWrapMode)1;
						val = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), (float)Mathf.Max(((Texture)val2).width, ((Texture)val2).height));
						Plugin.Log.LogInfo((object)$"[Art] Own drawing loaded: {name}.png ({((Texture)val2).width} x {((Texture)val2).height})");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Art] Could not load " + name + ".png: " + ex.Message));
			}
			art[name] = val;
			return val;
		}

		internal static GameObject Dot(Character like, Vector3 position, Color color, float diameter, string artName = null)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0011: 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_0068: 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)
			GameObject val = new GameObject("UCHClasses_Dot");
			val.transform.position = position;
			val.transform.localScale = new Vector3(diameter, diameter, 1f);
			SpriteRenderer val2 = val.AddComponent<SpriteRenderer>();
			Sprite val3 = ((artName != null) ? Art(artName) : null);
			val2.sprite = (((Object)(object)val3 != (Object)null) ? val3 : DotSprite());
			val2.color = (((Object)(object)val3 != (Object)null) ? Color.white : color);
			SpriteRenderer val4 = (((Object)(object)like != (Object)null) ? ((Component)like).GetComponentInChildren<SpriteRenderer>() : null);
			if ((Object)(object)val4 != (Object)null)
			{
				val.layer = ((Component)val4).gameObject.layer;
				((Renderer)val2).sortingLayerID = ((Renderer)val4).sortingLayerID;
				((Renderer)val2).sortingOrder = ((Renderer)val4).sortingOrder - 1;
			}
			return val;
		}
	}
	internal enum ClassId
	{
		None,
		Sprinter,
		Glider,
		Climber,
		Hopper,
		Stomper,
		Grappler,
		Dwarf,
		Giant,
		Slider,
		Teleporter,
		Tank,
		Cat,
		Fireproof,
		Shield,
		Shover,
		Screamer,
		Swapper,
		Sticky,
		SlowMo,
		Avenger,
		Underdog,
		Stealth,
		Carrier,
		Thief,
		Doppelganger,
		Ghost,
		Architect,
		Demolitionist,
		Trapper,
		Hoarder,
		Copycat,
		Wrecker,
		TreasureHunter,
		Gambler,
		Lucky
	}
	internal class ClassInfo
	{
		public ClassId Id;

		public string Name;

		public string Ability;

		public string Drawback;

		public bool Active;
	}
	internal static class ClassDefs
	{
		internal static readonly List<ClassInfo> All = new List<ClassInfo>
		{
			new ClassInfo
			{
				Id = ClassId.None,
				Name = "No class",
				Ability = "Plain animal.",
				Drawback = ""
			},
			new ClassInfo
			{
				Id = ClassId.Sprinter,
				Name = "Sprinter",
				Active = true,
				Ability = "Short dash in the direction you hold.",
				Drawback = "Accelerates slower."
			},
			new ClassInfo
			{
				Id = ClassId.Glider,
				Name = "Glider",
				Ability = "Hold jump in the air to fall slowly.",
				Drawback = "Jumps a bit lower."
			},
			new ClassInfo
			{
				Id = ClassId.Climber,
				Name = "Climber",
				Ability = "Does not slide down walls (hold down to slide).",
				Drawback = "Runs a bit slower."
			},
			new ClassInfo
			{
				Id = ClassId.Hopper,
				Name = "Hopper",
				Ability = "Double jump.",
				Drawback = "No wall jump, no wall slide."
			},
			new ClassInfo
			{
				Id = ClassId.Stomper,
				Name = "Stomper",
				Active = true,
				Ability = "In the air: slam down and knock nearby players away.",
				Drawback = "Jumps a bit lower."
			},
			new ClassInfo
			{
				Id = ClassId.Grappler,
				Name = "Grappler",
				Active = true,
				Ability = "Once per round: pull yourself to a block in the direction you hold.",
				Drawback = "Runs a bit slower."
			},
			new ClassInfo
			{
				Id = ClassId.Dwarf,
				Name = "Dwarf",
				Ability = "Smaller: fits through gaps and under projectiles.",
				Drawback = "Jumps a bit lower."
			},
			new ClassInfo
			{
				Id = ClassId.Giant,
				Name = "Giant",
				Ability = "Bigger, jumps higher, cannot be shoved.",
				Drawback = "Easier to hit."
			},
			new ClassInfo
			{
				Id = ClassId.Slider,
				Name = "Slider",
				Ability = "Ice and honey do not affect you.",
				Drawback = "Accelerates much slower."
			},
			new ClassInfo
			{
				Id = ClassId.Teleporter,
				Name = "Teleporter",
				Active = true,
				Ability = "First press sets a mark, second press jumps back to it (once per round).",
				Drawback = "Cannot move for a moment after the jump."
			},
			new ClassInfo
			{
				Id = ClassId.Tank,
				Name = "Tank",
				Ability = "Survives the first hit of every round.",
				Drawback = "No wall jump, no wall slide."
			},
			new ClassInfo
			{
				Id = ClassId.Cat,
				Name = "Cat",
				Ability = "Three extra lives per match.",
				Drawback = "Never gets the bonus for finishing first."
			},
			new ClassInfo
			{
				Id = ClassId.Fireproof,
				Name = "Fireproof",
				Ability = "Immune to the kind of trap that killed you last.",
				Drawback = "Runs a bit slower."
			},
			new ClassInfo
			{
				Id = ClassId.Shield,
				Name = "Shield",
				Active = true,
				Ability = "Hold the button while standing: nothing that hits you from the front can kill you.",
				Drawback = "Cannot move while the shield is up."
			},
			new ClassInfo
			{
				Id = ClassId.Shover,
				Name = "Shover",
				Active = true,
				Ability = "Shove players right next to you.",
				Drawback = "You are pushed back yourself."
			},
			new ClassInfo
			{
				Id = ClassId.Screamer,
				Name = "Screamer",
				Active = true,
				Ability = "Knock back everyone around you.",
				Drawback = "Long cooldown, you cannot move for a moment."
			},
			new ClassInfo
			{
				Id = ClassId.Swapper,
				Name = "Swapper",
				Active = true,
				Ability = "Once per round: swap places with a random living player.",
				Drawback = "You do not know with whom."
			},
			new ClassInfo
			{
				Id = ClassId.Sticky,
				Name = "Sticky",
				Ability = "Leaves a sticky trail that slows other players.",
				Drawback = "Gets stuck in the trails of other Sticky players."
			},
			new ClassInfo
			{
				Id = ClassId.SlowMo,
				Name = "Slow Motion",
				Active = true,
				Ability = "Once per round: the whole game runs at half speed for a moment.",
				Drawback = "It slows you down too."
			},
			new ClassInfo
			{
				Id = ClassId.Avenger,
				Name = "Avenger",
				Ability = "Whoever kills you with a trap is marked. Killing them with your trap gives an extra point.",
				Drawback = "Trap kills on anyone else give no points."
			},
			new ClassInfo
			{
				Id = ClassId.Underdog,
				Name = "Underdog",
				Ability = "Reaching the goal while in last place gives an extra point.",
				Drawback = "No bonus for finishing first while in the lead."
			},
			new ClassInfo
			{
				Id = ClassId.Stealth,
				Name = "Stealth",
				Ability = "The piece you place is invisible to the others for one round.",
				Drawback = ""
			},
			new ClassInfo
			{
				Id = ClassId.Carrier,
				Name = "Carrier",
				Active = true,
				Ability = "Pick up a player next to you, press again to throw them.",
				Drawback = "Slow while carrying."
			},
			new ClassInfo
			{
				Id = ClassId.Thief,
				Name = "Thief",
				Ability = "Touch a player who carries a coin to steal it.",
				Drawback = "Cannot pick up coins from the level."
			},
			new ClassInfo
			{
				Id = ClassId.Doppelganger,
				Name = "Doppelganger",
				Ability = "Looks like another player's animal during the run.",
				Drawback = "Keeps their own hat and name."
			},
			new ClassInfo
			{
				Id = ClassId.Ghost,
				Name = "Ghost",
				Active = true,
				Ability = "Once per round, after dying: knock the nearest living player away.",
				Drawback = "Does nothing while alive."
			},
			new ClassInfo
			{
				Id = ClassId.Architect,
				Name = "Architect",
				Ability = "The pieces you place cannot be blown up.",
				Drawback = ""
			},
			new ClassInfo
			{
				Id = ClassId.Demolitionist,
				Name = "Demolitionist",
				Active = true,
				Ability = "Once per round: light a fuse and explode. Kills everyone close by.",
				Drawback = "Including yourself. Your traps give no points."
			},
			new ClassInfo
			{
				Id = ClassId.Trapper,
				Name = "Trapper",
				Ability = "Projectiles from your traps fly faster.",
				Drawback = "Dying to your own trap costs a point."
			},
			new ClassInfo
			{
				Id = ClassId.Hoarder,
				Name = "Hoarder",
				Ability = "The Party Box holds one more piece while you play.",
				Drawback = ""
			},
			new ClassInfo
			{
				Id = ClassId.Copycat,
				Name = "Copycat",
				Ability = "Gets the class of a random other player every round.",
				Drawback = "Nothing if nobody has a class."
			},
			new ClassInfo
			{
				Id = ClassId.Wrecker,
				Name = "Wrecker",
				Active = true,
				Ability = "Every third round: destroy the piece right next to you.",
				Drawback = ""
			},
			new ClassInfo
			{
				Id = ClassId.TreasureHunter,
				Name = "Treasure Hunter",
				Ability = "Every round a treasure appears that only you can see. Carry it to the goal for a point.",
				Drawback = "Cannot pick up normal coins."
			},
			new ClassInfo
			{
				Id = ClassId.Gambler,
				Name = "Gambler",
				Ability = "Bet on a player in the class menu. If they reach the goal first, you get a point.",
				Drawback = "You cannot bet on yourself."
			},
			new ClassInfo
			{
				Id = ClassId.Lucky,
				Name = "Lucky",
				Ability = "One in four deadly hits misses you.",
				Drawback = "Once per round your left and right are swapped for a moment."
			}
		};

		internal static ClassInfo Get(ClassId id)
		{
			foreach (ClassInfo item in All)
			{
				if (item.Id == id)
				{
					return item;
				}
			}
			return All[0];
		}

		internal static ClassId Step(ClassId id, int dir)
		{
			int num = All.IndexOf(Get(id));
			num = (num + dir + All.Count) % All.Count;
			return All[num].Id;
		}

		internal static bool TryParse(string name, out ClassId id)
		{
			foreach (ClassInfo item in All)
			{
				if (item.Id.ToString() == name)
				{
					id = item.Id;
					return true;
				}
			}
			id = ClassId.None;
			return false;
		}
	}
	internal class PlayerState
	{
		public int Number;

		public ClassId Class;

		public ClassId Chosen;

		public bool Confirmed;

		public int CarriedBy;

		public float CarriedUntil;

		public int CarryTarget;

		public float CarryingUntil;

		public float ExplodeAt;

		public int LastWreckRound = -99;

		public bool HasTreasure;

		public bool CarryTreasure;

		public Vector3 TreasurePos;

		public GameObject TreasureObj;

		public int Bet;

		public bool BetPaid;

		public float MirrorFrom = -1f;

		public bool MirrorShown;

		public float LastDeathTime = -99f;

		public bool ShieldBroken;

		public int LastKiller;

		public int Mark;

		public bool PrevKey;

		public float CooldownUntil;

		public bool UsedThisRound;

		public float DashUntil;

		public float DashDir;

		public bool Slamming;

		public float PullUntil;

		public Vector2 PullTarget;

		public bool HasMark;

		public Vector3 MarkPos;

		public GameObject MarkObj;

		public bool TankUsed;

		public int CatLives = 3;

		public string ImmuneCause;

		public bool ShieldUp;

		public float StuckUntil;

		public bool ReachedGoal;

		public Vector3 LastTrail;

		internal void ResetRound()
		{
			UsedThisRound = false;
			CooldownUntil = 0f;
			DashUntil = 0f;
			Slamming = false;
			PullUntil = 0f;
			TankUsed = false;
			ShieldUp = false;
			StuckUntil = 0f;
			ReachedGoal = false;
			CarriedBy = 0;
			CarriedUntil = 0f;
			CarryTarget = 0;
			CarryingUntil = 0f;
			ExplodeAt = 0f;
			BetPaid = false;
			ShieldBroken = false;
			LastKiller = 0;
			MirrorFrom = -1f;
			MirrorShown = false;
			ClearMark();
			ClearTreasure();
		}

		internal void ClearTreasure()
		{
			HasTreasure = false;
			CarryTreasure = false;
			if ((Object)(object)TreasureObj != (Object)null)
			{
				Object.Destroy((Object)(object)TreasureObj);
				TreasureObj = null;
			}
		}

		internal void ResetMatch()
		{
			ResetRound();
			CatLives = 3;
			ImmuneCause = null;
			Mark = 0;
			LastWreckRound = -99;
			Confirmed = false;
		}

		internal void ClearMark()
		{
			HasMark = false;
			if ((Object)(object)MarkObj != (Object)null)
			{
				Object.Destroy((Object)(object)MarkObj);
				MarkObj = null;
			}
		}
	}
	internal static class Classes
	{
		private static readonly Dictionary<int, PlayerState> states = new Dictionary<int, PlayerState>();

		private static readonly FieldRef<Character, Rigidbody2D> bodyRef = AccessTools.FieldRefAccess<Character, Rigidbody2D>("chrRigidBody");

		private static readonly FieldRef<Character, int> facingRef = AccessTools.FieldRefAccess<Character, int>("facing");

		private static readonly FieldRef<Character, Animator> animatorRef = AccessTools.FieldRefAccess<Character, Animator>("animator");

		internal static bool Active
		{
			get
			{
				if (Plugin.ModEnabled.Value)
				{
					return !ClassNet.OnlineWithoutMod;
				}
				return false;
			}
		}

		internal static IEnumerable<PlayerState> AllStates => states.Values;

		internal static Animator Animator(Character c)
		{
			return animatorRef.Invoke(c);
		}

		internal static int CountClass(ClassId id)
		{
			int num = 0;
			foreach (Character item in Players())
			{
				if (Of(item) == id)
				{
					num++;
				}
			}
			return num;
		}

		internal static PlayerState State(int number)
		{
			if (!states.TryGetValue(number, out var value))
			{
				value = new PlayerState
				{
					Number = number
				};
				states[number] = value;
			}
			return value;
		}

		internal static ClassId Of(int number)
		{
			if (!Active || number <= 0)
			{
				return ClassId.None;
			}
			if (!states.TryGetValue(number, out var value))
			{
				return ClassId.None;
			}
			return value.Class;
		}

		internal static ClassId OfNumber(int number)
		{
			return Of(number);
		}

		internal static ClassId Of(Character c)
		{
			if (!((Object)(object)c == (Object)null) && !c.isReplay)
			{
				return Of(c.networkNumber);
			}
			return ClassId.None;
		}

		internal static Rigidbody2D Body(Character c)
		{
			return bodyRef.Invoke(c);
		}

		internal static int Facing(Character c)
		{
			return facingRef.Invoke(c);
		}

		internal static bool IsLocal(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			GamePlayer associatedGamePlayer = c.AssociatedGamePlayer;
			if ((Object)(object)associatedGamePlayer != (Object)null)
			{
				return associatedGamePlayer.IsLocalPlayer;
			}
			LobbyPlayer associatedLobbyPlayer = c.AssociatedLobbyPlayer;
			if ((Object)(object)associatedLobbyPlayer != (Object)null)
			{
				return associatedLobbyPlayer.IsLocalPlayer;
			}
			return false;
		}

		internal static bool IsLocalNumber(int number)
		{
			return IsLocal(Find(number));
		}

		internal static List<Character> Players()
		{
			List<Character> list = new List<Character>();
			if (Character.AllCharacters == null)
			{
				return list;
			}
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null) && allCharacter.networkNumber > 0 && !allCharacter.isReplay && !allCharacter.isExtraCorpse && (!((Object)(object)allCharacter.AssociatedGamePlayer == (Object)null) || !((Object)(object)allCharacter.AssociatedLobbyPlayer == (Object)null)))
				{
					list.Add(allCharacter);
				}
			}
			return list;
		}

		internal static Character Find(int number)
		{
			foreach (Character item in Players())
			{
				if (item.networkNumber == number)
				{
					return item;
				}
			}
			return null;
		}

		internal static bool Alive(Character c)
		{
			if ((Object)(object)c != (Object)null && c.Enabled && !c.Dead && !c.Dying)
			{
				return !c.Success;
			}
			return false;
		}

		internal static string DisplayName(Character c)
		{
			string text = null;
			if ((Object)(object)c.AssociatedGamePlayer != (Object)null)
			{
				text = c.AssociatedGamePlayer.playerName;
			}
			else if ((Object)(object)c.AssociatedLobbyPlayer != (Object)null)
			{
				text = c.AssociatedLobbyPlayer.playerName;
			}
			string text2 = ((object)Unsafe.As<Animals, Animals>(ref c.CharacterSprite)/*cast due to .constrained prefix*/).ToString();
			text2 = text2.Substring(0, 1) + text2.Substring(1).ToLowerInvariant();
			if (!string.IsNullOrEmpty(text))
			{
				return text + " (" + text2 + ")";
			}
			return text2;
		}

		internal static void SetLocal(Character c, ClassId id)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			PlayerState playerState = State(c.networkNumber);
			if (playerState.Chosen != id)
			{
				playerState.ResetRound();
				ClassNet.SendEffect(EffectKind.Shield, c.networkNumber, 0, Vector2.zero, 0f);
				playerState.Chosen = id;
				playerState.Class = ((id != ClassId.Copycat) ? id : ClassId.None);
				Save();
				ClassNet.SendAssign(c.networkNumber, playerState.Class);
				Plugin.LogVerbose("[Class] " + DisplayName(c) + " is now " + ClassDefs.Get(id).Name);
			}
		}

		internal static void Confirm(Character c)
		{
			PlayerState playerState = State(c.networkNumber);
			playerState.Confirmed = true;
			ClassNet.SendAssign(c.networkNumber, playerState.Class);
			Plugin.LogVerbose("[Class] " + DisplayName(c) + " is ready as " + ClassDefs.Get(playerState.Chosen).Name);
		}

		internal static void ApplyAssign(int number, ClassId id, bool confirmed)
		{
			if (number > 0)
			{
				PlayerState playerState = State(number);
				if (confirmed)
				{
					playerState.Confirmed = true;
				}
				if (playerState.Class != id)
				{
					playerState.Class = id;
					Plugin.LogVerbose($"[Class] Player {number} is now {ClassDefs.Get(id).Name}");
				}
			}
		}

		internal static void RestoreSaved(Character c)
		{
			PlayerState playerState = State(c.networkNumber);
			if (playerState.Chosen != ClassId.None)
			{
				return;
			}
			string[] array = Plugin.SavedClasses.Value.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '=' });
				if (array2.Length == 2 && array2[0] == c.localNumber.ToString() && ClassDefs.TryParse(array2[1], out var id))
				{
					playerState.Chosen = id;
					playerState.Class = ((id != ClassId.Copycat) ? id : ClassId.None);
					ClassNet.SendAssign(c.networkNumber, playerState.Class);
					break;
				}
			}
		}

		private static void Save()
		{
			Dictionary<int, ClassId> dictionary = new Dictionary<int, ClassId>();
			string[] array = Plugin.SavedClasses.Value.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '=' });
				if (array2.Length == 2 && int.TryParse(array2[0], out var result) && ClassDefs.TryParse(array2[1], out var id))
				{
					dictionary[result] = id;
				}
			}
			foreach (Character item in Players())
			{
				if (IsLocal(item))
				{
					dictionary[item.localNumber] = State(item.networkNumber).Chosen;
				}
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<int, ClassId> item2 in dictionary)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(item2.Key).Append('=').Append(item2.Value);
			}
			Plugin.SavedClasses.Value = stringBuilder.ToString();
		}
	}
	internal class ClassMenu : MonoBehaviour
	{
		private class Pointer : InputReceiver
		{
			public Character Character;

			public Controller Controller;

			public bool Keyboard;

			public Vector2 Pos;

			public bool Click;

			public float LastActive;

			public int Index;

			private float up;

			private float down;

			private float left;

			private float right;

			private Vector3 lastMouse;

			public void ReceiveEvent(InputEvent e)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected I4, but got Unknown
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Invalid comparison between Unknown and I4
				InputKey key = e.Key;
				switch ((int)key)
				{
				default:
					if ((int)key != 21)
					{
						return;
					}
					break;
				case 0:
					up = e.Valuef;
					return;
				case 1:
					down = e.Valuef;
					return;
				case 2:
					left = e.Valuef;
					return;
				case 3:
					right = e.Valuef;
					return;
				case 8:
					break;
				case 4:
				case 5:
				case 6:
				case 7:
					return;
				}
				if (e.Valueb && e.Changed)
				{
					Click = true;
				}
			}

			public void Move(float speed)
			{
				//IL_0031: 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)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: 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_006e: 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_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(right - left, down - up);
				if (((Vector2)(ref val)).sqrMagnitude > 0.02f)
				{
					Pos += Vector2.ClampMagnitude(val, 1f) * speed * Time.unscaledDeltaTime;
					LastActive = Time.unscaledTime;
				}
				if (Keyboard)
				{
					Vector3 mousePosition = Input.mousePosition;
					if (mousePosition != lastMouse)
					{
						lastMouse = mousePosition;
						Pos = new Vector2(mousePosition.x, (float)Screen.height - mousePosition.y);
						LastActive = Time.unscaledTime;
					}
				}
				Pos.x = Mathf.Clamp(Pos.x, 0f, (float)Screen.width);
				Pos.y = Mathf.Clamp(Pos.y, 0f, (float)Screen.height);
			}
		}

		private const int Columns = 4;

		private static readonly Color[] Palette = (Color[])(object)new Color[8]
		{
			new Color(0.78f, 0.22f, 0.18f),
			new Color(0.16f, 0.38f, 0.72f),
			new Color(0.18f, 0.55f, 0.27f),
			new Color(0.55f, 0.27f, 0.68f),
			new Color(0.85f, 0.48f, 0.1f),
			new Color(0.1f, 0.55f, 0.58f),
			new Color(0.8f, 0.3f, 0.55f),
			new Color(0.45f, 0.33f, 0.2f)
		};

		private static readonly Color Paper = new Color(0.95f, 0.92f, 0.85f);

		private readonly List<Pointer> pointers = new List<Pointer>();

		private bool open;

		private float styleScale = -1f;

		private GUIStyle title;

		private GUIStyle chip;

		private GUIStyle cell;

		private GUIStyle cellOn;

		private GUIStyle body;

		private GUIStyle hint;

		private GUIStyle hintRight;

		private GUIStyle button;

		private Texture2D solid;

		private Material pointerMaterial;

		private Material arrowMaterial;

		private bool Showing
		{
			get
			{
				if (Classes.Active)
				{
					if (!open)
					{
						return Runtime.Selecting;
					}
					return true;
				}
				return false;
			}
		}

		private static bool Locked
		{
			get
			{
				if (!Runtime.InLobby)
				{
					return Runtime.AbilitiesAllowed;
				}
				return false;
			}
		}

		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)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Invalid comparison between Unknown and I4
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.MenuKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && !Runtime.Selecting)
			{
				open = !open;
			}
			if (!Showing)
			{
				DropPointers();
				return;
			}
			List<Character> list = Locals();
			for (int num = pointers.Count - 1; num >= 0; num--)
			{
				Pointer pointer = pointers[num];
				Controller val = (((Object)(object)pointer.Character != (Object)null && pointer.Character.LocalPlayer != null) ? pointer.Character.LocalPlayer.UseController : null);
				if ((Object)(object)pointer.Character == (Object)null || !list.Contains(pointer.Character) || (Object)(object)val != (Object)(object)pointer.Controller)
				{
					if ((Object)(object)pointer.Controller != (Object)null)
					{
						pointer.Controller.RemoveReceiver((InputReceiver)(object)pointer);
					}
					pointers.RemoveAt(num);
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				Character c = list[i];
				if (!pointers.Exists((Pointer p) => (Object)(object)p.Character == (Object)(object)c) && c.LocalPlayer != null && !((Object)(object)c.LocalPlayer.UseController == (Object)null))
				{
					Controller useController = c.LocalPlayer.UseController;
					Pointer pointer2 = new Pointer
					{
						Character = c,
						Controller = useController,
						Keyboard = ((int)useController.GetControllerType() == 0),
						Pos = new Vector2((float)Screen.width / 2f + ((float)i - (float)(list.Count - 1) / 2f) * 90f, (float)Screen.height / 2f),
						Index = i
					};
					useController.AddReceiver((InputReceiver)(object)pointer2);
					pointers.Add(pointer2);
					Plugin.LogVerbose("[Menu] Pointer for " + Classes.DisplayName(c) + " (" + (pointer2.Keyboard ? "mouse" : "controller") + ")");
				}
			}
			float speed = 950f * Mathf.Clamp((float)Screen.height / 1080f, 0.6f, 2.5f);
			foreach (Pointer pointer3 in pointers)
			{
				pointer3.Index = list.IndexOf(pointer3.Character);
				pointer3.Move(speed);
			}
		}

		private void DropPointers()
		{
			foreach (Pointer pointer in pointers)
			{
				if ((Object)(object)pointer.Controller != (Object)null)
				{
					pointer.Controller.RemoveReceiver((InputReceiver)(object)pointer);
				}
			}
			pointers.Clear();
		}

		private void OnDestroy()
		{
			DropPointers();
		}

		private static List<Character> Locals()
		{
			List<Character> list = new List<Character>();
			foreach (Character item in Classes.Players())
			{
				if (Classes.IsLocal(item))
				{
					list.Add(item);
				}
			}
			list.Sort((Character a, Character b) => a.networkNumber.CompareTo(b.networkNumber));
			return list;
		}

		private static int NextBet(Character self, int current)
		{
			List<int> list = new List<int>();
			foreach (Character item in Classes.Players())
			{
				if ((Object)(object)item != (Object)(object)self && !list.Contains(item.networkNumber))
				{
					list.Add(item.networkNumber);
				}
			}
			if (list.Count == 0)
			{
				return 0;
			}
			list.Sort();
			int num = list.IndexOf(current);
			return list[(num + 1) % list.Count];
		}

		private void BuildStyles(float scale)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: 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_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Expected O, but got Unknown
			styleScale = scale;
			PanelSkin.Load();
			if ((Object)(object)solid == (Object)null)
			{
				solid = new Texture2D(1, 1);
				solid.SetPixel(0, 0, Color.white);
				solid.Apply();
			}
			bool hasTexture = PanelSkin.HasTexture;
			Color textColor = (hasTexture ? PanelSkin.TextColor : Color.white);
			Color textColor2 = (Color)(hasTexture ? PanelSkin.HintColor : new Color(0.75f, 0.78f, 0.85f));
			title = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(30f * scale),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)3,
				wordWrap = false
			};
			title.normal.textColor = (Color)(hasTexture ? PanelSkin.TitleColor : new Color(1f, 0.82f, 0.25f));
			chip = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(16f * scale),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4,
				wordWrap = false,
				clipping = (TextClipping)1
			};
			chip.normal.textColor = Paper;
			cell = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(18f * scale),
				alignment = (TextAnchor)4,
				wordWrap = false
			};
			cell.normal.textColor = textColor;
			cellOn = new GUIStyle(cell)
			{
				fontStyle = (FontStyle)1
			};
			cellOn.normal.textColor = Paper;
			body = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(17f * scale),
				alignment = (TextAnchor)0,
				wordWrap = true
			};
			body.normal.textColor = textColor;
			hint = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.RoundToInt(14f * scale),
				alignment = (TextAnchor)3,
				wordWrap = false
			};
			hint.normal.textColor = textColor2;
			hintRight = new GUIStyle(hint)
			{
				alignment = (TextAnchor)5,
				fontSize = Mathf.RoundToInt(17f * scale)
			};
			button = new GUIStyle(cellOn)
			{
				fontSize = Mathf.RoundToInt(20f * scale)
			};
			Font val = FontPicker.Get();
			if ((Object)(object)val != (Object)null)
			{
				GUIStyle[] array = (GUIStyle[])(object)new GUIStyle[8] { title, chip, cell, cellOn, body, hint, hintRight, button };
				for (int i = 0; i < array.Length; i++)
				{
					array[i].font = val;
				}
			}
		}

		private void Fill(Rect r, Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = c;
			GUI.DrawTexture(r, (Texture)(object)solid);
			GUI.color = color;
		}

		private void Frame(Rect r, Color c, float t)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			Fill(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width, t), c);
			Fill(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).yMax - t, ((Rect)(ref r)).width, t), c);
			Fill(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), c);
			Fill(new Rect(((Rect)(ref r)).xMax - t, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), c);
		}

		private static Color ColorOf(int index)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return Palette[(index % Palette.Length + Palette.Length) % Palette.Length];
		}

		private List<Pointer> Over(Rect r, bool clickedOnly)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			List<Pointer> list = new List<Pointer>();
			foreach (Pointer pointer in pointers)
			{
				if (((Rect)(ref r)).Contains(pointer.Pos) && (!clickedOnly || pointer.Click))
				{
					list.Add(pointer);
				}
			}
			return list;
		}

		private void OnGUI()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0073: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0784: Unknown result type (might be due to invalid IL or missing references)
			//IL_0786: Unknown result type (might be due to invalid IL or missing references)
			//IL_078c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0792: Unknown result type (might be due to invalid IL or missing references)
			//IL_0799: 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_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0479: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0748: Unknown result type (might be due to invalid IL or missing references)
			//IL_0722: Unknown result type (might be due to invalid IL or missing references)
			//IL_0585: Unknown result type (might be due to invalid IL or missing references)
			//IL_0571: Unknown result type (might be due to invalid IL or missing references)
			//IL_0939: Unknown result type (might be due to invalid IL or missing references)
			//IL_093b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0941: Unknown result type (might be due to invalid IL or missing references)
			//IL_0947: Unknown result type (might be due to invalid IL or missing references)
			//IL_094e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ad0: Unknown result type (might be due to invalid IL or missing references)
			//IL_096a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0974: Unknown result type (might be due to invalid IL or missing references)
			//IL_099d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b4d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b21: Unknown result type (might be due to invalid IL or missing references)
			if (!Showing || (int)Event.current.type != 7)
			{
				return;
			}
			float num = Mathf.Clamp((float)Screen.height / 1080f, 0.6f, 2.5f);
			if (title == null || !Mathf.Approximately(num, styleScale))
			{
				BuildStyles(num);
			}
			bool selecting = Runtime.Selecting;
			bool hasTexture = PanelSkin.HasTexture;
			Color val = (Color)(hasTexture ? PanelSkin.TitleColor : new Color(1f, 0.82f, 0.25f));
			List<Character> list = Locals();
			float num2 = (hasTexture ? PanelSkin.Padding : 28f) * num;
			float num3 = 36f * num;
			int num4 = Mathf.CeilToInt((float)ClassDefs.All.Count / 4f);
			float num5 = 1240f * num;
			float num6 = num2 * 2f + 50f * num + 48f * num + (float)num4 * num3 + 16f * num + 84f * num + 56f * num + 26f * num;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(((float)Screen.width - num5) / 2f, Mathf.Max(0f, ((float)Screen.height - num6) / 2f), num5, num6);
			if (hasTexture)
			{
				PanelSkin.Draw(val2);
			}
			else
			{
				Fill(val2, new Color(0.08f, 0.09f, 0.12f, 0.95f));
			}
			float num7 = ((Rect)(ref val2)).x + num2;
			float num8 = num5 - num2 * 2f;
			float num9 = ((Rect)(ref val2)).y + num2;
			GUI.Label(new Rect(num7, num9, num8, 40f * num), selecting ? "CHOOSE YOUR CLASS" : "CLASSES", title);
			if (selecting)
			{
				GUI.Label(new Rect(num7, num9, num8, 40f * num), $"The match starts when everyone is ready, or in {Mathf.CeilToInt(Runtime.SelectTimeLeft)} s", hintRight);
			}
			num9 += 50f * num;
			if (list.Count == 0)
			{
				GUI.Label(new Rect(num7, num9, num8, 40f * num), "No local player yet.", body);
			}
			float num10 = Mathf.Min(300f * num, num8 / (float)Mathf.Max(1, list.Count));
			Rect val3 = default(Rect);
			for (int i = 0; i < list.Count; i++)
			{
				PlayerState playerState = Classes.State(list[i].networkNumber);
				string text = ((object)Unsafe.As<Animals, Animals>(ref list[i].CharacterSprite)/*cast due to .constrained prefix*/).ToString();
				text = text.Substring(0, 1) + text.Substring(1).ToLowerInvariant();
				string text2 = text + ": " + ClassDefs.Get(playerState.Chosen).Name + ((selecting && playerState.Confirmed) ? "  (ready)" : "");
				((Rect)(ref val3))..ctor(num7 + (float)i * num10, num9, num10 - 8f * num, 38f * num);
				Fill(val3, ColorOf(i));
				GUI.Label(val3, text2, chip);
			}
			num9 += 48f * num;
			Pointer pointer = null;
			foreach (Pointer pointer2 in pointers)
			{
				if (pointer == null || pointer2.LastActive > pointer.LastActive)
				{
					pointer = pointer2;
				}
			}
			ClassInfo classInfo = null;
			float num11 = num8 / 4f;
			Rect val4 = default(Rect);
			for (int j = 0; j < ClassDefs.All.Count; j++)
			{
				ClassInfo classInfo2 = ClassDefs.All[j];
				((Rect)(ref val4))..ctor(num7 + (float)(j % 4) * num11 + 3f * num, num9 + (float)(j / 4) * num3 + 2f * num, num11 - 6f * num, num3 - 4f * num);
				List<int> list2 = new List<int>();
				for (int k = 0; k < list.Count; k++)
				{
					if (Classes.State(list[k].networkNumber).Chosen == classInfo2.Id)
					{
						list2.Add(k);
					}
				}
				for (int l = 0; l < list2.Count; l++)
				{
					float num12 = ((Rect)(ref val4)).width / (float)list2.Count;
					Fill(new Rect(((Rect)(ref val4)).x + (float)l * num12, ((Rect)(ref val4)).y, num12, ((Rect)(ref val4)).height), ColorOf(list2[l]));
				}
				foreach (Pointer item in Over(val4, clickedOnly: false))
				{
					Frame(val4, ColorOf(item.Index), 3f * num);
					if (item == pointer)
					{
						classInfo = classInfo2;
					}
				}
				GUI.Label(val4, classInfo2.Name, (list2.Count > 0) ? cellOn : cell);
				Sprite val5 = ((classInfo2.Id != ClassId.None) ? Visuals.Art("icon_" + classInfo2.Id.ToString().ToLowerInvariant()) : null);
				if ((Object)(object)val5 != (Object)null)
				{
					float num13 = ((Rect)(ref val4)).height + 4f * num;
					GUI.DrawTexture(new Rect(((Rect)(ref val4)).x + 6f * num, ((Rect)(ref val4)).y + (((Rect)(ref val4)).height - num13) / 2f, num13, num13), (Texture)(object)val5.texture, (ScaleMode)2, true);
				}
				foreach (Pointer item2 in Over(val4, clickedOnly: true))
				{
					PlayerState playerState2 = Classes.State(item2.Character.networkNumber);
					if (!Locked && (!selecting || !playerState2.Confirmed))
					{
						Classes.SetLocal(item2.Character, classInfo2.Id);
					}
				}
			}
			num9 += (float)num4 * num3 + 16f * num;
			ClassInfo classInfo3 = classInfo;
			if (classInfo3 == null && pointer != null)
			{
				classInfo3 = ClassDefs.Get(Classes.State(pointer.Character.networkNumber).Chosen);
			}
			if (classInfo3 != null)
			{
				string text3 = classInfo3.Name.ToUpperInvariant() + (classInfo3.Active ? "  (uses the ability button)" : "") + "\n" + classInfo3.Ability + (string.IsNullOrEmpty(classInfo3.Drawback) ? "" : ("\nDrawback: " + classInfo3.Drawback));
				Sprite val6 = ((classInfo3.Id != ClassId.None) ? Visuals.Art("icon_" + classInfo3.Id.ToString().ToLowerInvariant()) : null);
				float num14 = 0f;
				if ((Object)(object)val6 != (Object)null)
				{
					num14 = 92f * num;
					GUI.DrawTexture(new Rect(num7, num9 - 4f * num, 84f * num, 84f * num), (Texture)(object)val6.texture, (ScaleMode)2, true);
				}
				GUI.Label(new Rect(num7 + num14, num9, num8 - num14, 84f * num), text3, body);
			}
			num9 += 84f * num;
			float num15 = num7;
			Rect val7 = default(Rect);
			((Rect)(ref val7))..ctor(num15, num9, 200f * num, 44f * num);
			Fill(val7, new Color(val.r, val.g, val.b, (Over(val7, clickedOnly: false).Count > 0) ? 1f : 0.88f));
			GUI.Label(val7, selecting ? "READY" : "CLOSE", button);
			foreach (Pointer item3 in Over(val7, clickedOnly: true))
			{
				if (selecting)
				{
					if (!Classes.State(item3.Character.networkNumber).Confirmed)
					{
						Classes.Confirm(item3.Character);
					}
				}
				else
				{
					open = false;
				}
			}
			num15 += 212f * num;
			bool flag = false;
			foreach (Character item4 in list)
			{
				flag |= Classes.State(item4.networkNumber).Chosen == ClassId.Gambler;
			}
			if (flag)
			{
				List<string> list3 = new List<string>();
				foreach (Character item5 in list)
				{
					PlayerState playerState3 = Classes.State(item5.networkNumber);
					if (playerState3.Chosen == ClassId.Gambler)
					{
						Character val8 = Classes.Find(playerState3.Bet);
						list3.Add(((Object)(object)val8 != (Object)null && (Object)(object)val8 != (Object)(object)item5) ? Classes.DisplayName(val8) : "nobody");
					}
				}
				Rect val9 = default(Rect);
				((Rect)(ref val9))..ctor(num15, num9, 400f * num, 44f * num);
				Fill(val9, new Color(val.r, val.g, val.b, (Over(val9, clickedOnly: false).Count > 0) ? 1f : 0.88f));
				GUI.Label(val9, "Bet on: " + string.Join(" / ", list3.ToArray()), button);
				foreach (Pointer item6 in Over(val9, clickedOnly: true))
				{
					PlayerState playerState4 = Classes.State(item6.Character.networkNumber);
					if (playerState4.Chosen == ClassId.Gambler)
					{
						playerState4.Bet = NextBet(item6.Character, playerState4.Bet);
					}
				}
				num15 += 412f * num;
			}
			List<string> list4 = new List<string>();
			foreach (Character item7 in Classes.Players())
			{
				if (!Classes.IsLocal(item7))
				{
					PlayerState playerState5 = Classes.State(item7.networkNumber);
					list4.Add(Classes.DisplayName(item7) + ": " + ClassDefs.Get(playerState5.Class).Name + ((selecting && playerState5.Confirmed) ? " (ready)" : ""));
				}
			}
			if (list4.Count > 0)
			{
				GUI.Label(new Rect(num15 + 10f * num, num9, num7 + num8 - num15 - 10f * num, 44f * num), string.Join("   ", list4.ToArray()), hint);
			}
			num9 += 56f * num;
			string text4 = (Locked ? "A run is in progress. Classes can be changed again afterwards." : ((pointers.Count < list.Count) ? "A player without a controller has no pointer here." : $"Stick or mouse moves your pointer, jump or click picks.  Ability button in the run: {Plugin.AbilityKey.Value} or R1."));
			GUI.Label(new Rect(num7, num9, num8, 24f * num), text4, hint);
			foreach (Pointer pointer3 in pointers)
			{
				DrawPointer(pointer3, num);
				pointer3.Click = false;
			}
		}

		private void DrawPointer(Pointer p, float scale)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			//IL_0233: 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_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: 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_0295: 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_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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)
			//IL_007e: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			float num = scale * 1.25f;
			Vector2 pos = p.Pos;
			try
			{
				Sprite val = CharacterSpriteManager.GetInstance().GetCharacterSprites(p.Character.CharacterSprite)?.OKCursor;
				if ((Object)(object)val != (Object)null && (Object)(object)val.texture != (Object)null && val.triangles.Length != 0)
				{
					if ((Object)(object)pointerMaterial == (Object)null)
					{
						pointerMaterial = new Material(Shader.Find("Sprites/Default"));
					}
					pointerMaterial.mainTexture = (Texture)(object)val.texture;
					Bounds bounds = val.bounds;
					float num2 = 52f * scale / Mathf.Max(0.01f, Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.y));
					float num3 = pos.x + 16f * num;
					float num4 = pos.y + 18f * num;
					Vector2[] vertices = val.vertices;
					Vector2[] uv = val.uv;
					ushort[] triangles = val.triangles;
					pointerMaterial.SetPass(0);
					GL.PushMatrix();
					GL.LoadPixelMatrix(0f, (float)Screen.width, (float)Screen.height, 0f);
					GL.Begin(4);
					GL.Color(Color.white);
					for (int i = 0; i < triangles.Length; i++)
					{
						Vector2 val2 = vertices[triangles[i]];
						Vector2 val3 = uv[triangles[i]];
						GL.TexCoord2(val3.x, val3.y);
						GL.Vertex3(num3 + (val2.x - ((Bounds)(ref bounds)).min.x) * num2, num4 + (((Bounds)(ref bounds)).max.y - val2.y) * num2, 0f);
					}
					GL.End();
					GL.PopMatrix();
				}
			}
			catch (Exception)
			{
			}
			if ((Object)(object)arrowMaterial == (Object)null)
			{
				arrowMaterial = new Material(Shader.Find("Sprites/Default"));
				arrowMaterial.mainTexture = (Texture)(object)solid;
			}
			arrowMaterial.SetPass(0);
			GL.PushMatrix();
			GL.LoadPixelMatrix(0f, (float)Screen.width, (float)Screen.height, 0f);
			GL.Begin(4);
			Triangle(pos, new Vector2(-3f, -6f), new Vector2(-3f, 31f), new Vector2(24f, 19f), num, new Color(0.12f, 0.11f, 0.1f));
			Triangle(pos, new Vector2(0f, 0f), new Vector2(0f, 25f), new Vector2(17f, 17f), num, ColorOf(p.Index));
			GL.End();
			GL.PopMatrix();
		}

		private static void Triangle(Vector2 origin, Vector2 a, Vector2 b, Vector2 c, float unit, Color color)
		{
			//IL_0000: 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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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)
			GL.Color(color);
			GL.TexCoord2(0.5f, 0.5f);
			GL.Vertex3(origin.x + a.x * unit, origin.y + a.y * unit, 0f);
			GL.Vertex3(origin.x + b.x * unit, origin.y + b.y * unit, 0f);
			GL.Vertex3(origin.x + c.x * unit, origin.y + c.y * unit, 0f);
		}
	}
	internal enum EffectKind
	{
		Push = 1,
		Swap,
		SlowMo,
		Shield,
		Rope,
		Carry,
		Throw,
		Steal,
		Fuse,
		Explode,
		Destroy,
		Ring,
		Haunt,
		Dash,
		Status,
		Release,
		Revenge,
		SlowMoEnd
	}
	internal class ClassNet : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static NetworkMessageDelegate <0>__OnAssign;

			public static NetworkMessageDelegate <1>__OnEffect;

			public static NetworkMessageDelegate <2>__OnAssignReq;

			public static NetworkMessageDelegate <3>__OnEffectReq;
		}

		private const short MsgAssignReq = 20201;

		private const short MsgAssign = 20202;

		private const short MsgEffectReq = 20203;

		private const short MsgEffect = 20204;

		private const string PresenceKey = "uchclasses";

		private const float TickInterval = 1f;

		private static bool netEnabled;

		private static string reason = "no lobby";

		private float nextTick;

		private int tickCount;

		private string lastError = "";

		internal static bool NetEnabled => netEnabled;

		internal static string Status
		{
			get
			{
				if (!netEnabled)
				{
					return "local (" + reason + ")";
				}
				return "synced with all players";
			}
		}

		private static bool IsHost
		{
			get
			{
				LobbyManager instance = LobbyManager.instance;
				if ((Object)(object)instance != (Object)null)
				{
					return instance.IsHost;
				}
				return false;
			}
		}

		internal static bool OnlineWithoutMod
		{
			get
			{
				LobbyManager instance = LobbyManager.instance;
				if ((Object)(object)instance != (Object)null && !netEnabled)
				{
					if (instance.IsHost)
					{
						return instance.CountClients() > 0;
					}
					return true;
				}
				return false;
			}
		}

		private void Update()
		{
			if (Time.unscaledTime < nextTick)
			{
				return;
			}
			nextTick = Time.unscaledTime + 1f;
			try
			{
				Tick();
			}
			catch (Exception ex)
			{
				if (ex.Message != lastError)
				{
					lastError = ex.Message;
					Plugin.Log.LogWarning((object)$"[Net] Error while syncing, classes run locally: {ex}");
				}
				SetEnabled(value: false, "error");
			}
		}

		private void Tick()
		{
			//IL_0037: 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_0046: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00ca: 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: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			LobbyManager instance = LobbyManager.instance;
			if ((Object)(object)instance == (Object)null || !Plugin.NetSync.Value)
			{
				SetEnabled(value: false, ((Object)(object)instance == (Object)null) ? "no lobby" : "off in the config");
				return;
			}
			CSteamID val = FindSteamLobby();
			if (((CSteamID)(ref val)).IsValid() && SteamMatchmaking.GetLobbyMemberData(val, SteamUser.GetSteamID(), "uchclasses") != "0.5.0")
			{
				SteamMatchmaking.SetLobbyMemberData(val, "uchclasses", "0.5.0");
				Plugin.LogVerbose("[Net] Reported version 0.5.0 in the Steam lobby");
			}
			if (((NetworkManager)instance).client != null)
			{
				NetworkClient client = ((NetworkManager)instance).client;
				object obj = <>O.<0>__OnAssign;
				if (obj == null)
				{
					NetworkMessageDelegate val2 = OnAssign;
					<>O.<0>__OnAssign = val2;
					obj = (object)val2;
				}
				client.RegisterHandler((short)20202, (NetworkMessageDelegate)obj);
				NetworkClient client2 = ((NetworkManager)instance).client;
				object obj2 = <>O.<1>__OnEffect;
				if (obj2 == null)
				{
					NetworkMessageDelegate val3 = OnEffect;
					<>O.<1>__OnEffect = val3;
					obj2 = (object)val3;
				}
				client2.RegisterHandler((short)20204, (NetworkMessageDelegate)obj2);
			}
			if (instance.IsHost && NetworkServer.active)
			{
				object obj3 = <>O.<2>__OnAssignReq;
				if (obj3 == null)
				{
					NetworkMessageDelegate val4 = OnAssignReq;
					<>O.<2>__OnAssignReq = val4;
					obj3 = (object)val4;
				}
				NetworkServer.RegisterHandler((short)20201, (NetworkMessageDelegate)obj3);
				object obj4 = <>O.<3>__OnEffectReq;
				if (obj4 == null)
				{
					NetworkMessageDelegate val5 = OnEffectReq;
					<>O.<3>__OnEffectReq = val5;
					obj4 = (object)val5;
				}
				NetworkServer.RegisterHandler((short)20203, (NetworkMessageDelegate)obj4);
			}
			SetEnabled(AllHaveMod(val, out var why), why);
			tickCount++;
			if (!netEnabled || tickCount % 3 != 0)
			{
				return;
			}
			foreach (Character item in Classes.Players())
			{
				if (Classes.IsLocal(item))
				{
					SendAssign(item.networkNumber, Classes.State(item.networkNumber).Class);
				}
			}
		}

		private static void SetEnabled(bool value, string why)
		{
			if (value != netEnabled || why != reason)
			{
				netEnabled = value;
				reason = why;
				Plugin.Log.LogInfo((object)("[Net] Classes: " + Status));
			}
		}

		private static CSteamID FindSteamLobby()
		{
			//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)
			SteamMatchmaker val = Object.FindObjectOfType<SteamMatchmaker>();
			if ((Object)(object)val == (Object)null || val.SteamLobby == null || !((MatchmakingLobby)val.SteamLobby).IsValid())
			{
				return CSteamID.Nil;
			}
			return val.SteamLobby.LobbyID;
		}

		private static bool AllHaveMod(CSteamID lobby, out string why)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!((CSteamID)(ref lobby)).IsValid())
			{
				why = "no Steam lobby";
				return false;
			}
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(lobby);
			if (numLobbyMembers < 2)
			{
				why = "no other players";
				return false;
			}
			for (int i = 0; i < numLobbyMembers; i++)
			{
				CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(lobby, i);
				string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(lobby, lobbyMemberByIndex, "uchclasses");
				if (lobbyMemberData != "0.5.0")
				{
					string friendPersonaName = SteamFriends.GetFriendPersonaName(lobbyMemberByIndex);
					why = (string.IsNullOrEmpty(lobbyMemberData) ? ("'" + friendPersonaName + "' does not have the mod") : ("'" + friendPersonaName + "' has version " + lobbyMemberData + " instead of 0.5.0"));
					return false;
				}
			}
			why = "";
			return true;
		}

		private static void Broadcast(short id, MessageBase msg)
		{
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection != null && connection.hostId != -1)
				{
					connection.Send(id, msg);
				}
			}
		}

		internal static void SendAssign(int number, ClassId id)
		{
			if (!netEnabled)
			{
				return;
			}
			ClassMsg classMsg = new ClassMsg
			{
				Source = number,
				Kind = (int)id,
				Target = (Classes.State(number).Confirmed ? 1 : 0)
			};
			if (IsHost)
			{
				Broadcast(20202, (MessageBase)(object)classMsg);
				return;
			}
			LobbyManager instance = LobbyManager.instance;
			if ((Object)(object)instance != (Object)null && ((NetworkManager)instance).client != null)
			{
				((NetworkManager)instance).client.Send((short)20201, (MessageBase)(object)classMsg);
			}
		}

		internal static void SendEffect(EffectKind kind, int source, int target, Vector2 v, float f)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			ClassMsg classMsg = new ClassMsg
			{
				Kind = (int)kind,
				Source = source,
				Target = target,
				X = v.x,
				Y = v.y,
				F = f
			};
			if (!netEnabled || IsHost)
			{
				Effects.Apply(classMsg);
				if (netEnabled)
				{
					Broadcast(20204, (MessageBase)(object)classMsg);
				}
			}
			else
			{
				LobbyManager instance = LobbyManager.instance;
				if ((Object)(object)instance != (Object)null && ((NetworkManager)instance).client != null)
				{
					((NetworkManager)instance).client.Send((short)20203, (MessageBase)(object)classMsg);
				}
			}
		}

		private static void OnAssignReq(NetworkMessage netMsg)
		{
			ClassMsg classMsg = netMsg.ReadMessage<ClassMsg>();
			Classes.ApplyAssign(classMsg.Source, (ClassId)classMsg.Kind, classMsg.Target == 1);
			Broadcast(20202, (MessageBase)(object)classMsg);
		}

		private static void OnAssign(NetworkMessage netMsg)
		{
			ClassMsg classMsg = netMsg.ReadMessage<ClassMsg>();
			if (!IsHost && !Classes.IsLocalNumber(classMsg.Source))
			{
				Classes.ApplyAssign(classMsg.Source, (ClassId)classMsg.Kind, classMsg.Target == 1);
			}
		}

		private static void OnEffectReq(NetworkMessage netMsg)
		{
			ClassMsg msg = netMsg.ReadMessage<ClassMsg>();
			Effects.Apply(msg);
			Broadcast(20204, (MessageBase)(object)msg);
		}

		private static void OnEffect(NetworkMessage netMsg)
		{
			ClassMsg msg = netMsg.ReadMessage<ClassMsg>();
			if (!IsHost)
			{
				Effects.Apply(msg);
			}
		}
	}
	internal class ClassMsg : MessageBase
	{
		public int Kind;

		public int Source;

		public int Target;

		public float X;

		public float Y;

		public float F;

		public override void Serialize(NetworkWriter writer)
		{
			writer.Write(Kind);
			writer.Write(Source);
			writer.Write(Target);
			writer.Write(X);
			writer.Write(Y);
			writer.Write(F);
		}

		public override void Deserialize(NetworkReader reader)
		{
			Kind = reader.ReadInt32();
			Source = reader.ReadInt32();
			Target = reader.ReadInt32();
			X = reader.ReadSingle();
			Y = reader.ReadSingle();
			F = reader.ReadSingle();
		}
	}
	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)