Decompiled source of ModClasses v1.0.0

ModClasses.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModClasses
{
	internal static class ClassController
	{
		private static readonly Dictionary<PlayerControllerB, float> BaseSpeed = new Dictionary<PlayerControllerB, float>();

		private static float _healReadyAt;

		private static float _nextNoiseAt;

		public static void BeforeUpdate(PlayerControllerB p)
		{
			if (!BaseSpeed.TryGetValue(p, out var value))
			{
				value = p.movementSpeed;
				BaseSpeed[p] = value;
			}
			p.movementSpeed = value * ClassInfo.SpeedMultiplier(ClassManager.Get(p), p.isSprinting);
		}

		public static void AfterUpdate(PlayerControllerB p, float sprintMeterBefore)
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			PlayerClass playerClass = ClassManager.Get(p);
			float num = sprintMeterBefore - p.sprintMeter;
			float num2 = ClassInfo.StaminaDrainMultiplier(playerClass);
			if (num > 0f && num2 != 1f)
			{
				p.sprintMeter = Mathf.Clamp01(sprintMeterBefore - num * num2);
			}
			HudSlots.Apply(p.ItemSlots.Length, Mathf.Min(ClassInfo.UsableSlots(playerClass), p.ItemSlots.Length));
			Overlay.Tick(p, playerClass);
			if (p.isPlayerDead || !p.isPlayerControlled)
			{
				return;
			}
			if (playerClass == PlayerClass.Speedrunner && p.isSprinting && Time.time >= _nextNoiseAt)
			{
				_nextNoiseAt = Time.time + 0.5f;
				bool insideClosedShip = p.isInHangarShipRoom && StartOfRound.Instance.hangarDoorsClosed;
				Net.MakeNoise(((Component)p).transform.position, insideClosedShip);
			}
			if (IsBusy(p) || Keyboard.current == null)
			{
				return;
			}
			if (((ButtonControl)Keyboard.current[Plugin.TabletKey.Value]).wasPressedThisFrame && playerClass == PlayerClass.Technicien)
			{
				Overlay.ToggleTablet();
			}
			if (((ButtonControl)Keyboard.current[Plugin.AbilityKey.Value]).wasPressedThisFrame)
			{
				switch (playerClass)
				{
				case PlayerClass.Medecin:
					TryHeal(p);
					break;
				case PlayerClass.Technicien:
					TechAbility(p);
					break;
				}
			}
		}

		private static bool IsBusy(PlayerControllerB p)
		{
			if (!p.isTypingChat && !p.inTerminalMenu)
			{
				if ((Object)(object)p.quickMenuManager != (Object)null)
				{
					return p.quickMenuManager.isMenuOpen;
				}
				return false;
			}
			return true;
		}

		private static void TryHeal(PlayerControllerB p)
		{
			//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_0098: 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)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _healReadyAt)
			{
				Tip("Soin", $"Pas encore prêt ({Mathf.CeilToInt(_healReadyAt - Time.time)}s).");
				return;
			}
			Transform transform = ((Component)p.gameplayCamera).transform;
			PlayerControllerB val = null;
			float num = Plugin.HealRange.Value;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val2 in allPlayerScripts)
			{
				if (!((Object)(object)val2 == (Object)(object)p) && val2.isPlayerControlled && !val2.isPlayerDead)
				{
					Vector3 val3 = ((Component)val2).transform.position + Vector3.up - transform.position;
					float magnitude = ((Vector3)(ref val3)).magnitude;
					if (magnitude < num && Vector3.Dot(transform.forward, ((Vector3)(ref val3)).normalized) > 0.75f)
					{
						num = magnitude;
						val = val2;
					}
				}
			}
			if (val == null)
			{
				val = p;
			}
			if ((Object)(object)val == (Object)(object)p && p.health >= 100)
			{
				Tip("Soin", "Vise un joueur blessé pour le soigner.");
				return;
			}
			_healReadyAt = Time.time + Plugin.HealCooldown.Value;
			Net.RequestHeal((int)val.playerClientId);
			Tip("Soin", ((Object)(object)val == (Object)(object)p) ? "Tu te soignes." : ("Tu soignes " + val.playerUsername + "."));
		}

		private static void TechAbility(PlayerControllerB p)
		{
			if (Overlay.TabletOpen)
			{
				StartOfRound.Instance.mapScreen.SwitchRadarTargetForward(true);
				return;
			}
			Transform transform = ((Component)p.gameplayCamera).transform;
			float value = Plugin.TechDoorRange.Value;
			DoorLock val = Closest<DoorLock>(Object.FindObjectsOfType<DoorLock>(), (Func<DoorLock, bool>)((DoorLock d) => d.isLocked), transform, value);
			if ((Object)(object)val != (Object)null)
			{
				val.UnlockDoorSyncWithServer();
				Tip("Technicien", "Porte déverrouillée.");
				return;
			}
			TerminalAccessibleObject val2 = Closest<TerminalAccessibleObject>(Object.FindObjectsOfType<TerminalAccessibleObject>(), (Func<TerminalAccessibleObject, bool>)((TerminalAccessibleObject t) => t.isBigDoor), transform, value + 2f);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.CallFunctionFromTerminal();
				Tip("Technicien", "Porte blindée activée.");
			}
			else
			{
				Tip("Technicien", "Aucune porte à proximité.");
			}
		}

		private static T Closest<T>(T[] candidates, Func<T, bool> filter, Transform cam, float range) where T : Component
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			T result = default(T);
			float num = range;
			foreach (T val in candidates)
			{
				if (!((Object)(object)val == (Object)null) && filter(val))
				{
					Vector3 val2 = ((Component)val).transform.position - cam.position;
					float magnitude = ((Vector3)(ref val2)).magnitude;
					if (magnitude < num && Vector3.Dot(cam.forward, ((Vector3)(ref val2)).normalized) > 0.2f)
					{
						num = magnitude;
						result = val;
					}
				}
			}
			return result;
		}

		private static void Tip(string header, string body)
		{
			HUDManager instance = HUDManager.Instance;
			if (instance != null)
			{
				instance.DisplayTip(header, body, false, false, "");
			}
		}
	}
	internal static class ClassManager
	{
		private static readonly Dictionary<int, PlayerClass> Classes = new Dictionary<int, PlayerClass>();

		private static readonly HashSet<PlayerControllerB> Expanded = new HashSet<PlayerControllerB>();

		public static IEnumerable<KeyValuePair<int, PlayerClass>> All => Classes;

		public static PlayerControllerB LocalPlayer
		{
			get
			{
				if (!((Object)(object)GameNetworkManager.Instance != (Object)null))
				{
					return null;
				}
				return GameNetworkManager.Instance.localPlayerController;
			}
		}

		public static PlayerClass Get(int playerIndex)
		{
			if (!Classes.TryGetValue(playerIndex, out var value))
			{
				return PlayerClass.Aucune;
			}
			return value;
		}

		public static PlayerClass Get(PlayerControllerB p)
		{
			if (!((Object)(object)p == (Object)null))
			{
				return Get((int)p.playerClientId);
			}
			return PlayerClass.Aucune;
		}

		public static bool IsLocal(PlayerControllerB p)
		{
			if ((Object)(object)p != (Object)null)
			{
				return (Object)(object)p == (Object)(object)LocalPlayer;
			}
			return false;
		}

		public static void ResetAll()
		{
			Classes.Clear();
			Expanded.Clear();
		}

		public static void Apply(int playerIndex, PlayerClass c)
		{
			PlayerClass playerClass = Get(playerIndex);
			if (c == PlayerClass.Aucune)
			{
				Classes.Remove(playerIndex);
			}
			else
			{
				Classes[playerIndex] = c;
			}
			PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null);
			if (array == null || playerIndex < 0 || playerIndex >= array.Length)
			{
				return;
			}
			PlayerControllerB val = array[playerIndex];
			EnforceSlots(val);
			if (playerClass == c)
			{
				return;
			}
			if (IsLocal(val))
			{
				HUDManager instance = HUDManager.Instance;
				if (instance != null)
				{
					instance.DisplayTip("Classe : " + ClassInfo.DisplayName(c), ClassInfo.Description(c), false, false, "");
				}
			}
			else if (val.isPlayerControlled)
			{
				Plugin.Log.LogInfo((object)(val.playerUsername + " est maintenant " + ClassInfo.DisplayName(c)));
			}
		}

		public static void EnforceSlots(PlayerControllerB p)
		{
			if ((Object)(object)p == (Object)null || p.ItemSlots == null)
			{
				return;
			}
			int num = ClassInfo.InventorySize(Get(p));
			if (num > p.ItemSlots.Length)
			{
				GrabbableObject[] array = p.ItemSlots;
				Array.Resize(ref array, num);
				p.ItemSlots = array;
				Expanded.Add(p);
			}
			else
			{
				if (num >= p.ItemSlots.Length || !Expanded.Contains(p))
				{
					return;
				}
				for (int i = num; i < p.ItemSlots.Length; i++)
				{
					if ((Object)(object)p.ItemSlots[i] != (Object)null)
					{
						return;
					}
				}
				GrabbableObject[] array2 = p.ItemSlots;
				Array.Resize(ref array2, num);
				p.ItemSlots = array2;
				if (p.currentItemSlot >= num)
				{
					p.currentItemSlot = 0;
				}
				Expanded.Remove(p);
			}
		}

		public static bool InventoryEmpty(PlayerControllerB p)
		{
			GrabbableObject[] itemSlots = p.ItemSlots;
			for (int i = 0; i < itemSlots.Length; i++)
			{
				if ((Object)(object)itemSlots[i] != (Object)null)
				{
					return false;
				}
			}
			return true;
		}

		public static void ReceiveHeal(int amount, int healerIndex)
		{
			PlayerControllerB localPlayer = LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null || localPlayer.isPlayerDead || !localPlayer.isPlayerControlled)
			{
				return;
			}
			localPlayer.health = Mathf.Clamp(localPlayer.health + amount, 0, 100);
			HUDManager instance = HUDManager.Instance;
			if (instance != null)
			{
				instance.UpdateHealthUI(localPlayer.health, false);
			}
			if (localPlayer.health >= 10)
			{
				localPlayer.bleedingHeavily = false;
				if (localPlayer.criticallyInjured)
				{
					localPlayer.MakeCriticallyInjured(false);
				}
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			string arg = ((healerIndex >= 0 && healerIndex < allPlayerScripts.Length) ? allPlayerScripts[healerIndex].playerUsername : "?");
			if (healerIndex != (int)localPlayer.playerClientId)
			{
				HUDManager instance2 = HUDManager.Instance;
				if (instance2 != null)
				{
					instance2.DisplayTip("Soigné !", $"{arg} t'a rendu {amount} PV.", false, false, "");
				}
			}
		}
	}
	internal static class HudSlots
	{
		private static HUDManager _hud;

		private static Image[] _origFrames;

		private static Image[] _origIcons;

		private static readonly List<GameObject> Spawned = new List<GameObject>();

		private static int _total = -1;

		private static int _visible = -1;

		public static void Apply(int total, int visible)
		{
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: 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_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)instance != (Object)(object)_hud)
			{
				_hud = instance;
				_origFrames = instance.itemSlotIconFrames;
				_origIcons = instance.itemSlotIcons;
				Spawned.Clear();
				_total = (_visible = -1);
			}
			if (_origFrames == null || _origFrames.Length == 0 || (total == _total && visible == _visible))
			{
				return;
			}
			_total = total;
			_visible = visible;
			foreach (GameObject item in Spawned)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			Spawned.Clear();
			int num = _origFrames.Length;
			if (total <= num)
			{
				instance.itemSlotIconFrames = _origFrames;
				instance.itemSlotIcons = _origIcons;
			}
			else
			{
				Image[] array = (Image[])(object)new Image[total];
				Image[] array2 = (Image[])(object)new Image[total];
				Array.Copy(_origFrames, array, num);
				Array.Copy(_origIcons, array2, num);
				PlayerControllerB localPlayer = ClassManager.LocalPlayer;
				int num2 = (((Object)(object)localPlayer != (Object)null) ? localPlayer.currentItemSlot : 0);
				Sprite sprite = _origFrames[(num2 + 1) % num].sprite;
				for (int i = num; i < total; i++)
				{
					int num3 = i % num;
					int num4 = i / num;
					Image val = _origFrames[num3];
					Image val2 = _origIcons[num3];
					RectTransform val3 = (RectTransform)((Component)val).transform;
					Rect rect = val3.rect;
					float num5 = (((Rect)(ref rect)).height * Mathf.Abs(((Transform)val3).localScale.y) + 10f) * (float)num4;
					GameObject val4 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
					((Object)val4).name = "ModClasses_Slot" + i;
					((RectTransform)val4.transform).anchoredPosition = val3.anchoredPosition + new Vector2(0f, num5);
					Spawned.Add(val4);
					array[i] = val4.GetComponent<Image>();
					array[i].sprite = sprite;
					Image component;
					if (((Component)val2).transform.IsChildOf(((Component)val).transform))
					{
						component = ((Component)val4.transform.Find(RelativePath(((Component)val).transform, ((Component)val2).transform))).GetComponent<Image>();
					}
					else
					{
						GameObject val5 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent);
						((RectTransform)val5.transform).anchoredPosition = ((RectTransform)((Component)val2).transform).anchoredPosition + new Vector2(0f, num5);
						Spawned.Add(val5);
						component = val5.GetComponent<Image>();
					}
					component.sprite = null;
					((Behaviour)component).enabled = false;
					array2[i] = component;
				}
				instance.itemSlotIconFrames = array;
				instance.itemSlotIcons = array2;
			}
			for (int j = 0; j < instance.itemSlotIconFrames.Length; j++)
			{
				bool active = j < visible;
				((Component)instance.itemSlotIconFrames[j]).gameObject.SetActive(active);
				if (!((Component)instance.itemSlotIcons[j]).transform.IsChildOf(((Component)instance.itemSlotIconFrames[j]).transform))
				{
					((Component)instance.itemSlotIcons[j]).gameObject.SetActive(active);
				}
			}
		}

		private static string RelativePath(Transform root, Transform child)
		{
			string text = ((Object)child).name;
			Transform parent = child.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)root)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	internal static class Net
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnSetClass;

			public static HandleNamedMessageDelegate <1>__OnRequestSync;

			public static HandleNamedMessageDelegate <2>__OnHeal;

			public static HandleNamedMessageDelegate <3>__OnNoise;

			public static HandleNamedMessageDelegate <4>__OnClass;

			public static HandleNamedMessageDelegate <5>__OnSync;

			public static HandleNamedMessageDelegate <6>__OnHealTarget;
		}

		private const string P = "ModClasses_";

		private const string MsgSetClass = "ModClasses_SetClass";

		private const string MsgRequestSync = "ModClasses_RequestSync";

		private const string MsgHeal = "ModClasses_Heal";

		private const string MsgNoise = "ModClasses_Noise";

		private const string MsgClass = "ModClasses_Class";

		private const string MsgSync = "ModClasses_Sync";

		private const string MsgHealTarget = "ModClasses_HealTarget";

		private static CustomMessagingManager _registeredOn;

		private static NetworkManager NM => NetworkManager.Singleton;

		public static bool IsServer
		{
			get
			{
				if ((Object)(object)NM != (Object)null)
				{
					return NM.IsServer;
				}
				return false;
			}
		}

		public static void EnsureRegistered()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00ac: 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_00b7: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			if (!((Object)(object)NM == (Object)null) && NM.CustomMessagingManager != null && _registeredOn != NM.CustomMessagingManager)
			{
				_registeredOn = NM.CustomMessagingManager;
				ClassManager.ResetAll();
				CustomMessagingManager customMessagingManager = NM.CustomMessagingManager;
				object obj = <>O.<0>__OnSetClass;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnSetClass;
					<>O.<0>__OnSetClass = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_SetClass", (HandleNamedMessageDelegate)obj);
				object obj2 = <>O.<1>__OnRequestSync;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnRequestSync;
					<>O.<1>__OnRequestSync = val2;
					obj2 = (object)val2;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_RequestSync", (HandleNamedMessageDelegate)obj2);
				object obj3 = <>O.<2>__OnHeal;
				if (obj3 == null)
				{
					HandleNamedMessageDelegate val3 = OnHeal;
					<>O.<2>__OnHeal = val3;
					obj3 = (object)val3;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_Heal", (HandleNamedMessageDelegate)obj3);
				object obj4 = <>O.<3>__OnNoise;
				if (obj4 == null)
				{
					HandleNamedMessageDelegate val4 = OnNoise;
					<>O.<3>__OnNoise = val4;
					obj4 = (object)val4;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_Noise", (HandleNamedMessageDelegate)obj4);
				object obj5 = <>O.<4>__OnClass;
				if (obj5 == null)
				{
					HandleNamedMessageDelegate val5 = OnClass;
					<>O.<4>__OnClass = val5;
					obj5 = (object)val5;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_Class", (HandleNamedMessageDelegate)obj5);
				object obj6 = <>O.<5>__OnSync;
				if (obj6 == null)
				{
					HandleNamedMessageDelegate val6 = OnSync;
					<>O.<5>__OnSync = val6;
					obj6 = (object)val6;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_Sync", (HandleNamedMessageDelegate)obj6);
				object obj7 = <>O.<6>__OnHealTarget;
				if (obj7 == null)
				{
					HandleNamedMessageDelegate val7 = OnHealTarget;
					<>O.<6>__OnHealTarget = val7;
					obj7 = (object)val7;
				}
				customMessagingManager.RegisterNamedMessageHandler("ModClasses_HealTarget", (HandleNamedMessageDelegate)obj7);
			}
		}

		public static void RequestClass(PlayerClass c)
		{
			PlayerControllerB localPlayer = ClassManager.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (IsServer)
			{
				ServerSetClass((int)localPlayer.playerClientId, c);
				return;
			}
			SendToServer("ModClasses_SetClass", 8, delegate(FastBufferWriter w)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				int num = (int)c;
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref num, default(ForPrimitives));
			});
		}

		public static void RequestSync()
		{
			if (!IsServer)
			{
				SendToServer("ModClasses_RequestSync", 8, delegate
				{
				});
			}
		}

		public static void RequestHeal(int targetIndex)
		{
			PlayerControllerB localPlayer = ClassManager.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (IsServer)
			{
				ServerHeal((int)localPlayer.playerClientId, targetIndex);
				return;
			}
			SendToServer("ModClasses_Heal", 8, delegate(FastBufferWriter w)
			{
				//IL_000a: 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)
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref targetIndex, default(ForPrimitives));
			});
		}

		public static void MakeNoise(Vector3 pos, bool insideClosedShip)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			PlayNoise(pos, insideClosedShip);
			if (!IsServer)
			{
				SendToServer("ModClasses_Noise", 32, delegate(FastBufferWriter w)
				{
					//IL_0017: Unknown result type (might be due to invalid IL or missing references)
					//IL_001d: Unknown result type (might be due to invalid IL or missing references)
					((FastBufferWriter)(ref w)).WriteValueSafe(ref pos);
					((FastBufferWriter)(ref w)).WriteValueSafe<bool>(ref insideClosedShip, default(ForPrimitives));
				});
			}
		}

		private static void ServerSetClass(int playerIndex, PlayerClass c)
		{
			if (Enum.IsDefined(typeof(PlayerClass), c))
			{
				ClassManager.Apply(playerIndex, c);
				SendToAllClients("ModClasses_Class", 16, delegate(FastBufferWriter w)
				{
					//IL_000a: 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_0023: Unknown result type (might be due to invalid IL or missing references)
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref playerIndex, default(ForPrimitives));
					int num = (int)c;
					((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				});
			}
		}

		private static void ServerHeal(int healerIndex, int targetIndex)
		{
			if (ClassManager.Get(healerIndex) != PlayerClass.Medecin)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			if (targetIndex < 0 || targetIndex >= allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB val = allPlayerScripts[targetIndex];
			if (!val.isPlayerControlled || val.isPlayerDead)
			{
				return;
			}
			int amount = Plugin.HealAmount.Value;
			if (ClassManager.IsLocal(val))
			{
				ClassManager.ReceiveHeal(amount, healerIndex);
				return;
			}
			SendTo(val.actualClientId, "ModClasses_HealTarget", 16, delegate(FastBufferWriter w)
			{
				//IL_000a: 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_0020: 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)
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref amount, default(ForPrimitives));
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref healerIndex, default(ForPrimitives));
			});
		}

		private static void PlayNoise(Vector3 pos, bool insideClosedShip)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			RoundManager instance = RoundManager.Instance;
			if (instance != null)
			{
				instance.PlayAudibleNoise(pos, Plugin.SpeedrunnerNoiseRange.Value, 0.8f, 0, insideClosedShip, 0);
			}
		}

		private static void OnSetClass(ulong sender, FastBufferReader reader)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer)
			{
				int c = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref c, default(ForPrimitives));
				int num = PlayerIndexOf(sender);
				if (num >= 0)
				{
					ServerSetClass(num, (PlayerClass)c);
				}
			}
		}

		private static void OnRequestSync(ulong sender, FastBufferReader reader)
		{
			if (!IsServer)
			{
				return;
			}
			List<(int, int)> entries = new List<(int, int)>();
			foreach (KeyValuePair<int, PlayerClass> item in ClassManager.All)
			{
				entries.Add((item.Key, (int)item.Value));
			}
			SendTo(sender, "ModClasses_Sync", 8 + entries.Count * 8, delegate(FastBufferWriter w)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: 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_005f: Unknown result type (might be due to invalid IL or missing references)
				int count = entries.Count;
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref count, default(ForPrimitives));
				foreach (var item2 in entries)
				{
					var (num, num2) = item2;
					((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref num2, default(ForPrimitives));
				}
			});
		}

		private static void OnHeal(ulong sender, FastBufferReader reader)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer)
			{
				int targetIndex = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref targetIndex, default(ForPrimitives));
				int num = PlayerIndexOf(sender);
				if (num >= 0)
				{
					ServerHeal(num, targetIndex);
				}
			}
		}

		private static void OnNoise(ulong sender, FastBufferReader reader)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer)
			{
				Vector3 pos = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref pos);
				bool insideClosedShip = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref insideClosedShip, default(ForPrimitives));
				if (ClassManager.Get(PlayerIndexOf(sender)) == PlayerClass.Speedrunner)
				{
					PlayNoise(pos, insideClosedShip);
				}
			}
		}

		private static void OnClass(ulong sender, FastBufferReader reader)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				int playerIndex = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref playerIndex, default(ForPrimitives));
				int c = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref c, default(ForPrimitives));
				ClassManager.Apply(playerIndex, (PlayerClass)c);
			}
		}

		private static void OnSync(ulong sender, FastBufferReader reader)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_002a: 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)
			if (!IsServer)
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				int playerIndex = default(int);
				int c = default(int);
				for (int i = 0; i < num; i++)
				{
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref playerIndex, default(ForPrimitives));
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref c, default(ForPrimitives));
					ClassManager.Apply(playerIndex, (PlayerClass)c);
				}
			}
		}

		private static void OnHealTarget(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			int amount = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref amount, default(ForPrimitives));
			int healerIndex = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref healerIndex, default(ForPrimitives));
			ClassManager.ReceiveHeal(amount, healerIndex);
		}

		private static int PlayerIndexOf(ulong clientId)
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance != (Object)null) || !instance.ClientPlayerList.TryGetValue(clientId, out var value))
			{
				return -1;
			}
			return value;
		}

		private static void SendToServer(string name, int size, Action<FastBufferWriter> write)
		{
			SendTo(0uL, name, size, write);
		}

		private unsafe static void SendTo(ulong clientId, string name, int size, Action<FastBufferWriter> write)
		{
			//IL_0025: 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)
			if ((Object)(object)NM == (Object)null || NM.CustomMessagingManager == null)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(size, (Allocator)2, -1);
			try
			{
				write(val);
				NM.CustomMessagingManager.SendNamedMessage(name, clientId, val, (NetworkDelivery)2);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void SendToAllClients(string name, int size, Action<FastBufferWriter> write)
		{
			if ((Object)(object)NM == (Object)null)
			{
				return;
			}
			foreach (ulong connectedClientsId in NM.ConnectedClientsIds)
			{
				if (connectedClientsId != 0L)
				{
					SendTo(connectedClientsId, name, size, write);
				}
			}
		}
	}
	internal static class Overlay
	{
		private static GameObject _root;

		private static TextMeshProUGUI _classLabel;

		private static GameObject _tablet;

		private static RawImage _screen;

		private static TextMeshProUGUI _tabletLabel;

		public static bool TabletOpen
		{
			get
			{
				if ((Object)(object)_tablet != (Object)null)
				{
					return _tablet.activeSelf;
				}
				return false;
			}
		}

		public static void ToggleTablet()
		{
			if (!((Object)(object)_tablet == (Object)null))
			{
				_tablet.SetActive(!_tablet.activeSelf);
			}
		}

		public static void Tick(PlayerControllerB p, PlayerClass c)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			((TMP_Text)_classLabel).text = ((c == PlayerClass.Aucune) ? "" : ("Classe : " + ClassInfo.DisplayName(c)));
			if (c != PlayerClass.Technicien || p.isPlayerDead)
			{
				if (_tablet.activeSelf)
				{
					_tablet.SetActive(false);
				}
			}
			else
			{
				if (!TabletOpen)
				{
					return;
				}
				ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen;
				if (!((Object)(object)mapScreen == (Object)null) && !((Object)(object)mapScreen.cam == (Object)null))
				{
					_screen.texture = (Texture)(object)mapScreen.cam.targetTexture;
					string arg = "";
					if (mapScreen.radarTargets != null && mapScreen.targetTransformIndex >= 0 && mapScreen.targetTransformIndex < mapScreen.radarTargets.Count)
					{
						arg = mapScreen.radarTargets[mapScreen.targetTransformIndex].name;
					}
					((TMP_Text)_tabletLabel).text = $"CAMÉRA : {arg}   <size=70%>[{Plugin.AbilityKey.Value}] suivante  [{Plugin.TabletKey.Value}] fermer</size>";
				}
			}
		}

		private static void Build()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_007d: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: 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_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			HUDManager instance = HUDManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				object obj;
				if (!((Object)(object)instance.HUDContainer != (Object)null))
				{
					obj = null;
				}
				else
				{
					TextMeshProUGUI componentInChildren = instance.HUDContainer.GetComponentInChildren<TextMeshProUGUI>(true);
					obj = ((componentInChildren != null) ? ((TMP_Text)componentInChildren).font : null);
				}
				TMP_FontAsset font = (TMP_FontAsset)obj;
				_root = new GameObject("ModClasses_Overlay");
				Canvas obj2 = _root.AddComponent<Canvas>();
				obj2.renderMode = (RenderMode)0;
				obj2.sortingOrder = 50;
				CanvasScaler obj3 = _root.AddComponent<CanvasScaler>();
				obj3.uiScaleMode = (ScaleMode)1;
				obj3.referenceResolution = new Vector2(1920f, 1080f);
				obj3.matchWidthOrHeight = 0.5f;
				_classLabel = MakeText(_root.transform, font, 22f, (TextAlignmentOptions)1025);
				RectTransform rectTransform = ((TMP_Text)_classLabel).rectTransform;
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(0f, 0f);
				rectTransform.pivot = val;
				Vector2 anchorMin = (rectTransform.anchorMax = val);
				rectTransform.anchorMin = anchorMin;
				rectTransform.anchoredPosition = new Vector2(24f, 24f);
				rectTransform.sizeDelta = new Vector2(500f, 40f);
				((Graphic)_classLabel).color = new Color(1f, 0.55f, 0.2f, 0.9f);
				_tablet = new GameObject("Tablet", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				_tablet.transform.SetParent(_root.transform, false);
				RectTransform val3 = (RectTransform)_tablet.transform;
				((Vector2)(ref val))..ctor(1f, 0.5f);
				val3.pivot = val;
				anchorMin = (val3.anchorMax = val);
				val3.anchorMin = anchorMin;
				val3.anchoredPosition = new Vector2(-40f, 40f);
				val3.sizeDelta = new Vector2(640f, 600f);
				((Graphic)_tablet.GetComponent<Image>()).color = new Color(0.08f, 0.08f, 0.08f, 0.95f);
				GameObject val5 = new GameObject("Screen", new Type[2]
				{
					typeof(RectTransform),
					typeof(RawImage)
				});
				val5.transform.SetParent(_tablet.transform, false);
				RectTransform val6 = (RectTransform)val5.transform;
				val6.anchorMin = new Vector2(0f, 0f);
				val6.anchorMax = new Vector2(1f, 1f);
				val6.offsetMin = new Vector2(16f, 16f);
				val6.offsetMax = new Vector2(-16f, -56f);
				_screen = val5.GetComponent<RawImage>();
				((Graphic)_screen).color = Color.white;
				_tabletLabel = MakeText(_tablet.transform, font, 22f, (TextAlignmentOptions)4097);
				RectTransform rectTransform2 = ((TMP_Text)_tabletLabel).rectTransform;
				rectTransform2.anchorMin = new Vector2(0f, 1f);
				rectTransform2.anchorMax = new Vector2(1f, 1f);
				rectTransform2.pivot = new Vector2(0.5f, 1f);
				rectTransform2.offsetMin = new Vector2(20f, -52f);
				rectTransform2.offsetMax = new Vector2(-20f, -8f);
				((Graphic)_tabletLabel).color = new Color(0.4f, 1f, 0.4f);
				_tablet.SetActive(false);
			}
		}

		private static TextMeshProUGUI MakeText(Transform parent, TMP_FontAsset font, float size, TextAlignmentOptions align)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val2).font = font;
			}
			((TMP_Text)val2).fontSize = size;
			((TMP_Text)val2).alignment = align;
			((TMP_Text)val2).enableWordWrapping = false;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class PlayerPatches
	{
		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static void UpdatePrefix(PlayerControllerB __instance, out float __state)
		{
			__state = __instance.sprintMeter;
			if (ClassManager.IsLocal(__instance))
			{
				ClassController.BeforeUpdate(__instance);
			}
		}

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void UpdatePostfix(PlayerControllerB __instance, float __state)
		{
			ClassManager.EnforceSlots(__instance);
			if (ClassManager.IsLocal(__instance))
			{
				ClassController.AfterUpdate(__instance, __state);
			}
		}

		[HarmonyPatch("ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		private static void ConnectPostfix()
		{
			Net.EnsureRegistered();
			Net.RequestSync();
			if (Plugin.DefaultClass.Value != PlayerClass.Aucune)
			{
				Net.RequestClass(Plugin.DefaultClass.Value);
			}
		}

		[HarmonyPatch("DamagePlayer")]
		[HarmonyPrefix]
		private static void DamagePrefix(PlayerControllerB __instance, ref int damageNumber)
		{
			if (((NetworkBehaviour)__instance).IsOwner && damageNumber > 0)
			{
				float num = ClassInfo.DamageMultiplier(ClassManager.Get(__instance));
				if (num != 1f)
				{
					damageNumber = Mathf.Max(1, Mathf.RoundToInt((float)damageNumber * num));
				}
			}
		}

		[HarmonyPatch("FirstEmptyItemSlot")]
		[HarmonyPostfix]
		private static void FirstEmptyPostfix(PlayerControllerB __instance, ref int __result)
		{
			int num = ClassInfo.UsableSlots(ClassManager.Get(__instance));
			if (num >= __instance.ItemSlots.Length || __result < num)
			{
				return;
			}
			__result = -1;
			if (__instance.currentItemSlot < num && (Object)(object)__instance.ItemSlots[__instance.currentItemSlot] == (Object)null)
			{
				__result = __instance.currentItemSlot;
				return;
			}
			for (int i = 0; i < num; i++)
			{
				if ((Object)(object)__instance.ItemSlots[i] == (Object)null)
				{
					__result = i;
					break;
				}
			}
		}

		[HarmonyPatch("NextItemSlot")]
		[HarmonyPostfix]
		private static void NextItemSlotPostfix(PlayerControllerB __instance, bool forward, ref int __result)
		{
			int num = ClassInfo.UsableSlots(ClassManager.Get(__instance));
			if (num < __instance.ItemSlots.Length)
			{
				int currentItemSlot = __instance.currentItemSlot;
				if (currentItemSlot >= num)
				{
					__result = 0;
				}
				else
				{
					__result = (forward ? ((currentItemSlot + 1) % num) : ((currentItemSlot - 1 + num) % num));
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatches
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix()
		{
			Net.EnsureRegistered();
		}

		[HarmonyPatch("OnPlayerDC")]
		[HarmonyPostfix]
		private static void OnPlayerDCPostfix(int playerObjectNumber)
		{
			ClassManager.Apply(playerObjectNumber, PlayerClass.Aucune);
		}
	}
	[HarmonyPatch(typeof(ManualCameraRenderer), "Update")]
	internal static class MapCameraPatch
	{
		private static void Postfix(ManualCameraRenderer __instance)
		{
			if (Overlay.TabletOpen && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)__instance != (Object)(object)StartOfRound.Instance.mapScreen) && (Object)(object)__instance.cam != (Object)null)
			{
				((Behaviour)__instance.cam).enabled = true;
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
	internal static class ChatPatch
	{
		private static void Prefix(HUDManager __instance)
		{
			string text = __instance.chatTextField.text?.Trim() ?? "";
			string text2 = text.ToLowerInvariant().TrimStart('/', '!');
			string text3;
			if (text2.StartsWith("classe"))
			{
				text3 = text.TrimStart('/', '!').Substring(6);
			}
			else
			{
				if (!text2.StartsWith("class"))
				{
					return;
				}
				text3 = text.TrimStart('/', '!').Substring(5);
			}
			__instance.chatTextField.text = "";
			HandleCommand(text3.Trim());
		}

		private static void HandleCommand(string arg)
		{
			PlayerControllerB localPlayer = ClassManager.LocalPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				PlayerClass c;
				if (string.IsNullOrEmpty(arg))
				{
					Tip("Classe actuelle : " + ClassInfo.DisplayName(ClassManager.Get(localPlayer)), "/classe tank | speedrunner | medecin | technicien | mule | aucune");
				}
				else if (!ClassInfo.TryParse(arg, out c))
				{
					Tip("Classe inconnue", "tank, speedrunner, medecin, technicien, mule, aucune");
				}
				else if (Plugin.ChangeOnlyInOrbit.Value && !StartOfRound.Instance.inShipPhase)
				{
					Tip("Impossible", "Tu ne peux changer de classe qu'en orbite.");
				}
				else if (!ClassManager.InventoryEmpty(localPlayer))
				{
					Tip("Impossible", "Vide ton inventaire avant de changer de classe.");
				}
				else
				{
					Net.RequestClass(c);
				}
			}
		}

		private static void Tip(string header, string body)
		{
			HUDManager.Instance.DisplayTip(header, body, false, false, "");
		}
	}
	public enum PlayerClass
	{
		Aucune,
		Tank,
		Speedrunner,
		Medecin,
		Technicien,
		Mule
	}
	internal static class ClassInfo
	{
		public const int VanillaSlots = 4;

		public static string DisplayName(PlayerClass c)
		{
			return c switch
			{
				PlayerClass.Tank => "Tank", 
				PlayerClass.Speedrunner => "Speedrunner", 
				PlayerClass.Medecin => "Médecin", 
				PlayerClass.Technicien => "Technicien", 
				PlayerClass.Mule => "La Mule", 
				_ => "Aucune", 
			};
		}

		public static string Description(PlayerClass c)
		{
			//IL_0038: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			return c switch
			{
				PlayerClass.Tank => "2x plus de vie, mais l'endurance se vide 2x plus vite.", 
				PlayerClass.Speedrunner => "Sprinte 2x plus vite, mais 1/3 de vie. Ton sprint fait du bruit (les chiens t'entendent).", 
				PlayerClass.Medecin => $"Seulement 2 slots. [{Plugin.AbilityKey.Value}] pour soigner le joueur visé (ou toi-même).", 
				PlayerClass.Technicien => $"[{Plugin.TabletKey.Value}] tablette caméras. [{Plugin.AbilityKey.Value}] ouvre les portes verrouillées et les portes blindées.", 
				PlayerClass.Mule => "8 slots d'inventaire, mais 2x plus lent.", 
				_ => "Aucun bonus ni malus.", 
			};
		}

		public static int InventorySize(PlayerClass c)
		{
			if (c != PlayerClass.Mule)
			{
				return 4;
			}
			return 8;
		}

		public static int UsableSlots(PlayerClass c)
		{
			return c switch
			{
				PlayerClass.Medecin => 2, 
				PlayerClass.Mule => 8, 
				_ => 4, 
			};
		}

		public static float DamageMultiplier(PlayerClass c)
		{
			return c switch
			{
				PlayerClass.Tank => 0.5f, 
				PlayerClass.Speedrunner => 3f, 
				_ => 1f, 
			};
		}

		public static float StaminaDrainMultiplier(PlayerClass c)
		{
			if (c != PlayerClass.Tank)
			{
				return 1f;
			}
			return 2f;
		}

		public static float SpeedMultiplier(PlayerClass c, bool sprinting)
		{
			switch (c)
			{
			case PlayerClass.Speedrunner:
				if (sprinting)
				{
					return 2f;
				}
				break;
			case PlayerClass.Mule:
				return 0.5f;
			}
			return 1f;
		}

		public static bool TryParse(string s, out PlayerClass c)
		{
			s = s.Trim().ToLowerInvariant().Replace("é", "e")
				.Replace("è", "e")
				.Replace(" ", "");
			switch (s)
			{
			case "tank":
				c = PlayerClass.Tank;
				return true;
			case "speed":
			case "coureur":
			case "runner":
			case "speedrunner":
				c = PlayerClass.Speedrunner;
				return true;
			case "medic":
			case "medecin":
			case "doc":
			case "soigneur":
				c = PlayerClass.Medecin;
				return true;
			case "tech":
			case "techno":
			case "technicien":
				c = PlayerClass.Technicien;
				return true;
			case "mule":
			case "lamule":
				c = PlayerClass.Mule;
				return true;
			case "rien":
			case "none":
			case "aucune":
				c = PlayerClass.Aucune;
				return true;
			default:
				if (Enum.TryParse<PlayerClass>(s, ignoreCase: true, out c))
				{
					return Enum.IsDefined(typeof(PlayerClass), c);
				}
				return false;
			}
		}
	}
	[BepInPlugin("emeric.modclasses", "ModClasses", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "emeric.modclasses";

		public const string Name = "ModClasses";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<Key> AbilityKey;

		internal static ConfigEntry<Key> TabletKey;

		internal static ConfigEntry<PlayerClass> DefaultClass;

		internal static ConfigEntry<bool> ChangeOnlyInOrbit;

		internal static ConfigEntry<int> HealAmount;

		internal static ConfigEntry<float> HealCooldown;

		internal static ConfigEntry<float> HealRange;

		internal static ConfigEntry<float> SpeedrunnerNoiseRange;

		internal static ConfigEntry<float> TechDoorRange;

		private void Awake()
		{
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			AbilityKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Touches", "Pouvoir", (Key)22, "Médecin : soigner le joueur visé (ou soi-même). Technicien : ouvrir la porte devant soi / changer de caméra si la tablette est ouverte.");
			TabletKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Touches", "Tablette", (Key)24, "Technicien : ouvrir/fermer la tablette.");
			DefaultClass = ((BaseUnityPlugin)this).Config.Bind<PlayerClass>("General", "ClasseParDefaut", PlayerClass.Aucune, "Classe choisie automatiquement en rejoignant une partie.");
			ChangeOnlyInOrbit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ChangementSeulementEnOrbite", true, "Si vrai, on ne peut changer de classe que lorsque le vaisseau est en orbite.");
			HealAmount = ((BaseUnityPlugin)this).Config.Bind<int>("Medecin", "Soin", 25, "PV rendus par soin (valeur de l'hôte utilisée).");
			HealCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Medecin", "Cooldown", 6f, "Secondes entre deux soins.");
			HealRange = ((BaseUnityPlugin)this).Config.Bind<float>("Medecin", "Portee", 3.5f, "Distance max pour soigner un joueur.");
			SpeedrunnerNoiseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Speedrunner", "PorteeBruit", 25f, "Portée du bruit fait en sprintant (attire les chiens).");
			TechDoorRange = ((BaseUnityPlugin)this).Config.Bind<float>("Technicien", "PorteePortes", 4f, "Distance max pour ouvrir une porte.");
			new Harmony("emeric.modclasses").PatchAll();
			Log.LogInfo((object)"ModClasses 1.0.0 chargé.");
		}
	}
}