Decompiled source of PlayerLevels v0.0.12

PlayerLevels.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Autodesk.Fbx")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")]
[assembly: IgnoresAccessChecksTo("Klattersynth")]
[assembly: IgnoresAccessChecksTo("Photon3Unity3D")]
[assembly: IgnoresAccessChecksTo("PhotonChat")]
[assembly: IgnoresAccessChecksTo("PhotonRealtime")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.API")]
[assembly: IgnoresAccessChecksTo("PhotonVoice")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Utilities")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("websocket-sharp")]
[assembly: AssemblyCompany("WAAAAGH")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.7")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerLevels")]
[assembly: AssemblyTitle("PlayerLevels")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.7.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 PlayerLevels
{
	[BepInPlugin("WAAAAGH.PlayerLevels", "PlayerLevels", "0.0.12")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PlayerLevels : BaseUnityPlugin
	{
		public static ConfigEntry<int> NumberOfUpgradesPerLevel;

		public static ConfigEntry<int> MaxStaminaGain;

		public static ConfigEntry<int> MaxHealthGain;

		public static ConfigEntry<int> MaxStrengthGain;

		public static ConfigEntry<int> MaxRangeGain;

		public static ConfigEntry<int> MaxSpeedGain;

		public static ConfigEntry<int> MaxJumpGain;

		public static ConfigEntry<int> MaxTumbleLaunchGain;

		public static ConfigEntry<float> DelayBeforeRegen;

		public static ConfigEntry<float> StaminaRegenPerLevel;

		public static ConfigEntry<float> HealthRegenPerLevel;

		public static ConfigEntry<int> BaseStaminaLevel;

		public static ConfigEntry<int> BaseHealthLevel;

		public static ConfigEntry<int> TumbleLevel1Damage;

		public static ConfigEntry<int> TumbleLevel2Damage;

		public static ConfigEntry<int> TumbleLevel3Damage;

		public static ConfigEntry<int> TumbleLevel4Damage;

		public static ConfigEntry<int> TumbleLevelNDamage;

		public static ConfigEntry<int> ExpGainedAnimal;

		public static ConfigEntry<int> ExpGainedRobe;

		public static ConfigEntry<int> ExpGainedUpscream;

		public static ConfigEntry<int> ExpGainedGnome;

		public static ConfigEntry<int> ExpGainedBang;

		public static ConfigEntry<int> ExpGainedHunter;

		public static ConfigEntry<int> ExpGainedBowtie;

		public static ConfigEntry<int> ExpGainedDuck;

		public static ConfigEntry<int> ExpGainedBeamer;

		public static ConfigEntry<int> ExpGainedTumbler;

		public static ConfigEntry<int> ExpGainedFloater;

		public static ConfigEntry<int> ExpGainedHidden;

		public static ConfigEntry<int> ExpGainedRunner;

		public static ConfigEntry<int> ExpGainedSlowMouth;

		public static ConfigEntry<int> ExpGainedSlowWalker;

		public static ConfigEntry<int> ExpGainedThinman;

		public static ConfigEntry<int> ExpGainedValuableThrower;

		public static ConfigEntry<int> ExpGainedCeilingEye;

		public static ConfigEntry<int> ExpGainedHeadman;

		public static ConfigEntry<int> ExpNeededPerLevel;

		public static ConfigEntry<int> ExpNeededScaling;

		public static ConfigEntry<bool> ShowPlayerLeaveEvents;

		public static Dictionary<string, int> KillCounts = new Dictionary<string, int>();

		public static int PlayerCurrentLevel = 0;

		public static ConfigEntry<string> CustomEnemies;

		public static Dictionary<string, ConfigEntry<int>> ExpGainedCustomEnemies = new Dictionary<string, ConfigEntry<int>>();

		internal static PlayerLevels Instance { get; private set; } = null;


		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		internal void AddCustomEnemyExpGained(string name, int defaultExpGained)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			ExpGainedCustomEnemies.Add(name, ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains (Custom enemies)", name + " Kill Exp", defaultExpGained, new ConfigDescription("Amount of exp gained for killing " + name, (AcceptableValueBase)null, Array.Empty<object>())));
		}

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Expected O, but got Unknown
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Expected O, but got Unknown
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Expected O, but got Unknown
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Expected O, but got Unknown
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Expected O, but got Unknown
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Expected O, but got Unknown
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Expected O, but got Unknown
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Expected O, but got Unknown
			//IL_0448: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Expected O, but got Unknown
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Expected O, but got Unknown
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Expected O, but got Unknown
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d6: Expected O, but got Unknown
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Expected O, but got Unknown
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Expected O, but got Unknown
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_055a: Expected O, but got Unknown
			//IL_057c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0586: Expected O, but got Unknown
			//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Expected O, but got Unknown
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05de: Expected O, but got Unknown
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Expected O, but got Unknown
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0636: Expected O, but got Unknown
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Expected O, but got Unknown
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_0690: Expected O, but got Unknown
			//IL_0751: Unknown result type (might be due to invalid IL or missing references)
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0759: Expected O, but got Unknown
			//IL_075e: Expected O, but got Unknown
			NumberOfUpgradesPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Upgrades received per level up", 2, new ConfigDescription("How many upgrades a player receives when they level up", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxStaminaGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max stamina gain", 10, new ConfigDescription("Maximum Stamina Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxHealthGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max health gain", 6, new ConfigDescription("Maximum Health Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxStrengthGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max strength gain", 5, new ConfigDescription("Maximum Strength Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxRangeGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max range gain", 4, new ConfigDescription("Maximum Range Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxSpeedGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max speed gain", 3, new ConfigDescription("Maximum Speed Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxJumpGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max jump gain", 4, new ConfigDescription("Maximum Jump Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			MaxTumbleLaunchGain = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Max tumble launch gain", 8, new ConfigDescription("Maximum Tumble Launch Upgrades you can receive at max level", (AcceptableValueBase)null, Array.Empty<object>()));
			DelayBeforeRegen = ((BaseUnityPlugin)this).Config.Bind<float>("Levelling", "Delay before regen", 5f, new ConfigDescription("Delay before regen", (AcceptableValueBase)null, Array.Empty<object>()));
			StaminaRegenPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Levelling", "Stamina regen per level", 0.25f, new ConfigDescription("Stamina regen per Stamina Upgrade", (AcceptableValueBase)null, Array.Empty<object>()));
			HealthRegenPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Levelling", "Health regen per level", 0.1f, new ConfigDescription("Health regen per Health Upgrade", (AcceptableValueBase)null, Array.Empty<object>()));
			BaseStaminaLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Base stamina level", 2, new ConfigDescription("Base stamina level (for base regen calculation)", (AcceptableValueBase)null, Array.Empty<object>()));
			BaseHealthLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Levelling", "Base health level", 1, new ConfigDescription("Base health level (for base regen calculation)", (AcceptableValueBase)null, Array.Empty<object>()));
			TumbleLevel1Damage = ((BaseUnityPlugin)this).Config.Bind<int>("Tumble Damage", "Level 1 Tumble Damage", 15, (ConfigDescription)null);
			TumbleLevel2Damage = ((BaseUnityPlugin)this).Config.Bind<int>("Tumble Damage", "Level 2 Tumble Damage", 25, (ConfigDescription)null);
			TumbleLevel3Damage = ((BaseUnityPlugin)this).Config.Bind<int>("Tumble Damage", "Level 3 Tumble Damage", 35, (ConfigDescription)null);
			TumbleLevel4Damage = ((BaseUnityPlugin)this).Config.Bind<int>("Tumble Damage", "Level 4 Tumble Damage", 45, (ConfigDescription)null);
			TumbleLevelNDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Tumble Damage", "Tumble Damage foreach level after 4", 5, (ConfigDescription)null);
			ExpGainedAnimal = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Animal Kill Exp", 25, new ConfigDescription("Experience gained for killing an Animal enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedRobe = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Robe Kill Exp", 50, new ConfigDescription("Experience gained for killing a Robe enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedUpscream = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Upscream Kill Exp", 25, new ConfigDescription("Experience gained for killing an Upscream enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedGnome = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Gnome Kill Exp", 5, new ConfigDescription("Experience gained for killing a Gnome enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedBang = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Bang Kill Exp", 5, new ConfigDescription("Experience gained for killing a Bang enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedHunter = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Hunter Kill Exp", 50, new ConfigDescription("Experience gained for killing a Hunter enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedBowtie = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Bowtie Kill Exp", 50, new ConfigDescription("Experience gained for killing a Bowtie enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedDuck = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Duck Kill Exp", 25, new ConfigDescription("Experience gained for killing a Duck enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedBeamer = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Beamer Kill Exp", 25, new ConfigDescription("Experience gained for killing a Beamer enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedTumbler = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Tumbler Kill Exp", 20, new ConfigDescription("Experience gained for killing a Tumbler enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedFloater = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Floater Kill Exp", 25, new ConfigDescription("Experience gained for killing a Floater enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedHidden = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Hidden Kill Exp", 35, new ConfigDescription("Experience gained for killing a Hidden enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedRunner = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Runner Kill Exp", 25, new ConfigDescription("Experience gained for killing a Runner enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedSlowMouth = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "SlowMouth Kill Exp", 15, new ConfigDescription("Experience gained for killing a SlowMouth enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedSlowWalker = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "SlowWalker Kill Exp", 100, new ConfigDescription("Experience gained for killing a SlowWalker enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedThinman = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Thinman Kill Exp", 35, new ConfigDescription("Experience gained for killing a Thinman enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedValuableThrower = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "ValuableThrower Kill Exp", 25, new ConfigDescription("Experience gained for killing a ValuableThrower enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedCeilingEye = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "CeilingEye Kill Exp", 40, new ConfigDescription("Experience gained for killing a CeilingEye enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpGainedHeadman = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Headman Kill Exp", 75, new ConfigDescription("Experience gained for killing a Headman enemy", (AcceptableValueBase)null, Array.Empty<object>()));
			ExpNeededPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Experience Gains", "Exp needed to level", 100, new ConfigDescription("Experience needed to level up", (AcceptableValueBase)null, Array.Empty<object>()));
			ShowPlayerLeaveEvents = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show player leave notifications", true, new ConfigDescription("Show player leave notifications", (AcceptableValueBase)null, Array.Empty<object>()));
			CustomEnemies = ((BaseUnityPlugin)this).Config.Bind<string>("Custom Enemies Registry", "Registered custom enemies", "", new ConfigDescription("List of comma ',' delimited enemy names", (AcceptableValueBase)null, Array.Empty<object>()));
			string value = CustomEnemies.Value;
			List<string> list = (from enemy in value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select enemy.Trim() into enemy
				where !string.IsNullOrEmpty(enemy)
				select enemy).ToList();
			foreach (string item in list)
			{
				AddCustomEnemyExpGained(item, 100);
			}
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}

		public static int GetExpForEnemyType(string enemyType)
		{
			switch (enemyType)
			{
			case "Animal":
				return ExpGainedAnimal.Value;
			case "Robe":
				return ExpGainedRobe.Value;
			case "Upscream":
				return ExpGainedUpscream.Value;
			case "Gnome":
				return ExpGainedGnome.Value;
			case "Banger":
				return ExpGainedBang.Value;
			case "Huntsman":
				return ExpGainedHunter.Value;
			case "Bowtie":
				return ExpGainedBowtie.Value;
			case "Apex Predator":
				return ExpGainedDuck.Value;
			case "Clown":
				return ExpGainedBeamer.Value;
			case "Chef":
				return ExpGainedTumbler.Value;
			case "Mentalist":
				return ExpGainedFloater.Value;
			case "Hidden":
				return ExpGainedHidden.Value;
			case "Reaper":
				return ExpGainedRunner.Value;
			case "Spewer":
				return ExpGainedSlowMouth.Value;
			case "Trudge":
				return ExpGainedSlowWalker.Value;
			case "Shadow Child":
				return ExpGainedThinman.Value;
			case "Rugrat":
				return ExpGainedValuableThrower.Value;
			case "Peeper":
				return ExpGainedCeilingEye.Value;
			case "Headman":
				return ExpGainedHeadman.Value;
			default:
				if (!ExpGainedCustomEnemies.ContainsKey(enemyType))
				{
					Debug.LogWarning((object)("No exp value for enemy: $" + enemyType + ", enemy is not registered or recognized"));
					return 100;
				}
				return ExpGainedCustomEnemies[enemyType].Value;
			}
		}

		public static int GetExpGainedFromKills()
		{
			int num = 0;
			foreach (KeyValuePair<string, int> killCount in KillCounts)
			{
				num += killCount.Value * GetExpForEnemyType(killCount.Key);
			}
			return num;
		}

		public static int GetExpRequiredForLevelUp(int currentLevel)
		{
			return 0;
		}
	}
	public static class CoroutimeManager
	{
	}
	public class PlayerAttributes
	{
		private Dictionary<string, int> attributes;

		public int Stamina
		{
			get
			{
				return attributes["Stamina"];
			}
			set
			{
				attributes["Stamina"] = value;
			}
		}

		public int Health
		{
			get
			{
				return attributes["Health"];
			}
			set
			{
				attributes["Health"] = value;
			}
		}

		public int Strength
		{
			get
			{
				return attributes["Strength"];
			}
			set
			{
				attributes["Strength"] = value;
			}
		}

		public int Range
		{
			get
			{
				return attributes["Range"];
			}
			set
			{
				attributes["Range"] = value;
			}
		}

		public int Speed
		{
			get
			{
				return attributes["Speed"];
			}
			set
			{
				attributes["Speed"] = value;
			}
		}

		public int TumbleLaunch
		{
			get
			{
				return attributes["Launch"];
			}
			set
			{
				attributes["Launch"] = value;
			}
		}

		public int ExtraJump
		{
			get
			{
				return attributes["Extra Jump"];
			}
			set
			{
				attributes["Extra Jump"] = value;
			}
		}

		public PlayerAttributes()
		{
			attributes = new Dictionary<string, int>
			{
				{ "Extra Jump", 0 },
				{ "Range", 0 },
				{ "Strength", 0 },
				{ "Health", 0 },
				{ "Speed", 0 },
				{ "Stamina", 0 },
				{ "Launch", 0 }
			};
		}

		public PlayerAttributes(Dictionary<string, int> existingAttributes)
		{
			attributes = new Dictionary<string, int>(existingAttributes);
		}

		public Dictionary<string, int> GetRawAttributes()
		{
			return new Dictionary<string, int>(attributes);
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar))]
	public static class PlayerSpawnPatch
	{
		private static bool canUpgrade = false;

		private static int expCurrent = 0;

		private static int expPrev = 0;

		private static int levelsGainedLastRound = 0;

		private static List<Level> BLACK_LISTED_LEVELS = new List<Level>
		{
			RunManager.instance.levelLobby,
			RunManager.instance.levelLobbyMenu,
			RunManager.instance.levelMainMenu,
			RunManager.instance.levelShop,
			RunManager.instance.levelTutorial
		};

		private static string WeightedRandomSelection(Dictionary<string, int> remaining)
		{
			int num = remaining.Values.Sum();
			if (num == 0)
			{
				return "";
			}
			int num2 = Random.Range(0, num);
			int num3 = 0;
			foreach (KeyValuePair<string, int> item in remaining)
			{
				num3 += item.Value;
				if (num2 < num3)
				{
					return item.Key;
				}
			}
			return "";
		}

		private static Dictionary<string, int> PickRandomUpgrades(Dictionary<string, int> currentUpgrades, Dictionary<string, int> maximumUpgrades, int numberOfUpgrades)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (string key in maximumUpgrades.Keys)
			{
				int num = maximumUpgrades[key];
				int num2 = (currentUpgrades.ContainsKey(key) ? currentUpgrades[key] : 0);
				int num3 = num - num2;
				dictionary[key] = ((num3 > 0) ? num3 : 0);
			}
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			foreach (string key2 in maximumUpgrades.Keys)
			{
				dictionary2[key2] = 0;
			}
			for (int i = 0; i < numberOfUpgrades; i++)
			{
				if (dictionary.Values.Sum() == 0)
				{
					break;
				}
				string text = WeightedRandomSelection(dictionary);
				if (text == null)
				{
					break;
				}
				dictionary2[text]++;
				dictionary[text]--;
			}
			return dictionary2;
		}

		public static string? GetSteamID()
		{
			try
			{
				PlayerAvatar val = SemiFunc.PlayerAvatarGetFromPhotonID(SemiFunc.PhotonViewIDPlayerAvatarLocal());
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				return SemiFunc.PlayerGetSteamID(SemiFunc.PlayerAvatarGetFromPhotonID(SemiFunc.PhotonViewIDPlayerAvatarLocal()));
			}
			catch (Exception)
			{
				Debug.Log((object)"Error while retrieving steamID");
				return null;
			}
		}

		public static Dictionary<string, int>? GetCurrentStats()
		{
			string steamID = GetSteamID();
			if (steamID == null)
			{
				Debug.Log((object)"No valid steamID found, unable to retrieve current stats");
				return null;
			}
			return StatsManager.instance.FetchPlayerUpgrades(steamID);
		}

		private static Dictionary<string, int> GetMaximumStats()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			dictionary["Health"] = PlayerLevels.MaxHealthGain.Value;
			dictionary["Stamina"] = PlayerLevels.MaxStaminaGain.Value;
			dictionary["Strength"] = PlayerLevels.MaxStrengthGain.Value;
			dictionary["Range"] = PlayerLevels.MaxRangeGain.Value;
			dictionary["Speed"] = PlayerLevels.MaxSpeedGain.Value;
			dictionary["Extra Jump"] = PlayerLevels.MaxJumpGain.Value;
			dictionary["Launch"] = PlayerLevels.MaxTumbleLaunchGain.Value;
			return dictionary;
		}

		private static bool ApplyUpgrades(Dictionary<string, int> stats)
		{
			string steamID = GetSteamID();
			if (steamID == null)
			{
				return false;
			}
			int num = 0;
			bool flag = false;
			foreach (KeyValuePair<string, int> stat in stats)
			{
				string key = stat.Key;
				int value = stat.Value;
				num += value;
				for (int i = 0; i < value; i++)
				{
					switch (key)
					{
					case "Health":
						PunManager.instance.UpgradePlayerHealth(steamID);
						flag = true;
						break;
					case "Stamina":
						PunManager.instance.UpgradePlayerEnergy(steamID);
						flag = true;
						break;
					case "Strength":
						PunManager.instance.UpgradePlayerGrabStrength(steamID);
						flag = true;
						break;
					case "Range":
						PunManager.instance.UpgradePlayerGrabRange(steamID);
						flag = true;
						break;
					case "Speed":
						PunManager.instance.UpgradePlayerSprintSpeed(steamID);
						flag = true;
						break;
					case "Extra Jump":
						PunManager.instance.UpgradePlayerExtraJump(steamID);
						flag = true;
						break;
					case "Launch":
						PunManager.instance.UpgradePlayerTumbleLaunch(steamID);
						flag = true;
						break;
					default:
						Debug.Log((object)("Unknown upgrade: " + key));
						break;
					}
				}
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> stat2 in stats)
			{
				if (stat2.Value >= 1)
				{
					list.Add($"{stat2.Key} +{stat2.Value}");
				}
			}
			if (list.Count > 0)
			{
				((MonoBehaviour)UpgradeCoroutineManager.Instance).StartCoroutine(DisplayExperiencedGained(list));
			}
			return num == 0 || flag;
		}

		public static bool LevelUp()
		{
			Debug.Log((object)"Player has levelled up!");
			Dictionary<string, int> currentStats = GetCurrentStats();
			if (currentStats == null)
			{
				return false;
			}
			Dictionary<string, int> maximumStats = GetMaximumStats();
			int value = PlayerLevels.NumberOfUpgradesPerLevel.Value;
			int expGainedFromKills = PlayerLevels.GetExpGainedFromKills();
			int num = expGainedFromKills + expCurrent;
			levelsGainedLastRound = num / Mathf.Max(PlayerLevels.ExpNeededPerLevel.Value, 1);
			expPrev = expCurrent;
			expCurrent = num % PlayerLevels.ExpNeededPerLevel.Value;
			Debug.Log((object)$"Gained {expGainedFromKills} from kills (+{levelsGainedLastRound} additional levels)");
			int num2 = (RunManager.instance.levelsCompleted - 1) * PlayerLevels.NumberOfUpgradesPerLevel.Value;
			Dictionary<string, int> currentStats2 = GetCurrentStats();
			int num3 = 0;
			foreach (KeyValuePair<string, int> item in currentStats2)
			{
				num3 += item.Value;
			}
			int num4 = Mathf.Max(0, num2 - num3);
			Debug.Log((object)$"{num4} upgrades desynched");
			value += num4 + levelsGainedLastRound * PlayerLevels.NumberOfUpgradesPerLevel.Value;
			Dictionary<string, int> dictionary = PickRandomUpgrades(currentStats, maximumStats, value);
			Debug.Log((object)$"Picking {value} random upgrades");
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				if (item2.Value != 0)
				{
					Debug.Log((object)$"    {item2.Key} +{item2.Value} (Max={maximumStats[item2.Key]})");
				}
			}
			return ApplyUpgrades(dictionary);
		}

		private static IEnumerator DisplayExperiencedGained(List<string> appliedUpgrades)
		{
			while (!SemiFunc.RunIsLevel() || (Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2)
			{
				yield return (object)new WaitForSeconds(0.5f);
			}
			int totalExperiencedGained = PlayerLevels.GetExpGainedFromKills();
			if (totalExperiencedGained > 0)
			{
				REPOPopupPage page = MenuAPI.CreateREPOPopupPage("Experience gained", (PresetSide)1, false, false, 1.5f);
				page.OpenPage(true);
				yield return (object)new WaitForSeconds(1f);
				int j = 0;
				foreach (KeyValuePair<string, int> kvp in PlayerLevels.KillCounts)
				{
					if (kvp.Value != 0)
					{
						string enemyName = kvp.Key;
						int kills = kvp.Value;
						_ = kills * PlayerLevels.GetExpForEnemyType(enemyName);
						float x2 = 420f + (float)j * 0f;
						float y3 = 270f + (float)j * -25f;
						string fullText = $"{enemyName} x {kills}";
						page.AddElement((BuilderDelegate)delegate(Transform parent)
						{
							//IL_0013: Unknown result type (might be due to invalid IL or missing references)
							REPOLabel label2 = MenuAPI.CreateREPOLabel("", parent, new Vector2(x2, y3));
							UpgradeCoroutineManager.Instance.AnimateText(label2, fullText);
						});
						yield return (object)new WaitForSeconds(0.5f);
						j++;
					}
				}
				Coroutine animCoroutine = null;
				string fullText2 = "{0} experienced gained";
				float x3 = 420f + (float)j * 0f - 20f;
				float y2 = 270f + (float)j * -25f - 15f;
				page.AddElement((BuilderDelegate)delegate(Transform parent)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					REPOLabel label = MenuAPI.CreateREPOLabel("", parent, new Vector2(x3, y2));
					animCoroutine = UpgradeCoroutineManager.Instance.AnimateValue(label, expPrev, expPrev + totalExperiencedGained, fullText2, 3f);
				});
				if (animCoroutine != null)
				{
					yield return animCoroutine;
					j++;
					float x = 420f + (float)j * 0f - 20f;
					float y = 270f + (float)j * -25f - 15f;
					if (levelsGainedLastRound > 0)
					{
						page.AddElement((BuilderDelegate)delegate(Transform parent)
						{
							//IL_0022: Unknown result type (might be due to invalid IL or missing references)
							REPOLabel val = MenuAPI.CreateREPOLabel($"+{levelsGainedLastRound} levels", parent, new Vector2(x, y));
						});
					}
				}
				PlayerLevels.KillCounts.Clear();
				yield return (object)new WaitForSeconds(1f);
				page.ClosePage(true);
			}
			yield return (object)new WaitForNextFrameUnit();
			((MonoBehaviour)UpgradeCoroutineManager.Instance).StartCoroutine(DisplayUIPopoutText(appliedUpgrades));
		}

		private static IEnumerator DisplayUIPopoutText(List<string> upgradesReceived)
		{
			List<string> upgradesReceived2 = upgradesReceived;
			SemiFunc.PlayerAvatarLocal();
			string message = "Upgrades received: " + string.Join(", ", upgradesReceived2);
			Debug.Log((object)message);
			REPOPopupPage page = MenuAPI.CreateREPOPopupPage("Upgrades received", (PresetSide)1, false, false, 1.5f);
			upgradesReceived2.Sort();
			page.OpenPage(true);
			yield return (object)new WaitForNextFrameUnit();
			for (int i = 0; i < upgradesReceived2.Count; i++)
			{
				string upgrade = upgradesReceived2[i];
				float x = 420f + (float)i * 0f;
				float y = 270f + (float)i * -25f;
				float _x = x;
				float _y = y;
				page.AddElement((BuilderDelegate)delegate(Transform parent)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					REPOLabel label = MenuAPI.CreateREPOLabel("", parent, new Vector2(_x, _y));
					UpgradeCoroutineManager.Instance.AnimateText(label, upgrade);
				});
				yield return (object)new WaitForSeconds(0.5f);
			}
			page.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				REPOButton val = MenuAPI.CreateREPOButton("OK", (Action)delegate
				{
					page.ClosePage(true);
				}, parent, new Vector2(420f + (float)upgradesReceived2.Count * 0f, 270f + (float)upgradesReceived2.Count * -25f * 1.25f));
			});
		}

		private static IEnumerator WaitPlayerReadyLevelup()
		{
			yield return (object)new WaitForEndOfFrameUnit();
			canUpgrade = LevelUp();
		}

		[HarmonyPatch("SpawnRPC")]
		[HarmonyPostfix]
		private static void SpawnRPC_Postfix(PhotonView __instance)
		{
			if (BLACK_LISTED_LEVELS.Contains(RunManager.instance.levelCurrent) || RunManager.instance.levelsCompleted == 0)
			{
				Debug.Log((object)$"Skipping level up: blackListedLevel:{BLACK_LISTED_LEVELS.Contains(RunManager.instance.levelCurrent)}, levelsCompleted:{RunManager.instance.levelsCompleted}");
				canUpgrade = true;
				return;
			}
			if (!canUpgrade)
			{
				Debug.Log((object)$"Skipping level up: canUpgrade:{canUpgrade}");
				return;
			}
			canUpgrade = false;
			UpgradeCoroutineManager instance = UpgradeCoroutineManager.Instance;
			Debug.Log((object)$"Attemtping to level up: managerInstance:{(Object)(object)instance != (Object)null}");
			if ((Object)(object)instance != (Object)null)
			{
				if (instance.waitPlayerReadyCoroutine != null)
				{
					((MonoBehaviour)instance).StopCoroutine(instance.waitPlayerReadyCoroutine);
				}
				instance.waitPlayerReadyCoroutine = ((MonoBehaviour)instance).StartCoroutine(WaitPlayerReadyLevelup());
			}
		}
	}
	[HarmonyPatch(typeof(NetworkManager))]
	public static class NetworkManagerPatch
	{
		[HarmonyPatch("OnPlayerLeftRoom")]
		[HarmonyPrefix]
		public static void OnPlayerLeftRoom_Prefix(Player otherPlayer)
		{
			if (!GameManager.Multiplayer())
			{
				Debug.Log((object)"OnPlayerLeftRoom_Prefix but we are not in multiplayer");
			}
			else if (PlayerLevels.ShowPlayerLeaveEvents.Value)
			{
				RoundDirectorPatch.PlayerLeftNotice(otherPlayer.nickName);
			}
		}
	}
	public class UpgradeCoroutineManager : MonoBehaviour
	{
		public struct Keyframe
		{
			public Vector2 Position;

			public float LerpTime;

			public Keyframe(Vector2 position, float lerpTime)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				Position = position;
				LerpTime = lerpTime;
			}
		}

		public enum LerpType
		{
			Linear,
			Exponential,
			Easing
		}

		public Coroutine? waitPlayerReadyCoroutine = null;

		private static UpgradeCoroutineManager? _instance;

		public static UpgradeCoroutineManager Instance
		{
			get
			{
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = ((Component)StatsManager.instance).GetComponent<UpgradeCoroutineManager>();
					if ((Object)(object)_instance == (Object)null)
					{
						_instance = ComponentHolderProtocol.AddComponent<UpgradeCoroutineManager>((Object)(object)StatsManager.instance);
					}
				}
				return _instance;
			}
		}

		public Coroutine AnimateText(REPOLabel label, string fullText, float delayBetweenChars = 0.03f)
		{
			return ((MonoBehaviour)this).StartCoroutine(AnimateTextCoroutine(label, fullText, delayBetweenChars));
		}

		private IEnumerator AnimateTextCoroutine(REPOLabel label, string fullText, float delayBetweenChars)
		{
			string currentText = "";
			for (int i = 0; i < fullText.Length; i++)
			{
				currentText += fullText[i];
				((TMP_Text)label.labelTMP).text = currentText;
				yield return (object)new WaitForSeconds(delayBetweenChars);
			}
		}

		public Coroutine AnimateValue(REPOLabel label, int start, int end, string format, float duration = 1f, Action onComplete = null, int easingType = 1)
		{
			return ((MonoBehaviour)this).StartCoroutine(AnimateValueCoroutine(label, start, end, format, duration, onComplete, easingType));
		}

		private IEnumerator AnimateValueCoroutine(REPOLabel label, int start, int end, string format, float duration, Action onComplete, int easingType)
		{
			float elapsed = 0f;
			while (elapsed < duration)
			{
				elapsed += Time.deltaTime;
				float normalizedTime = Mathf.Clamp01(elapsed / duration);
				if (easingType == 1)
				{
					normalizedTime = EaseInOut(normalizedTime);
				}
				int currentValue = (int)Mathf.Lerp((float)start, (float)end, normalizedTime);
				((TMP_Text)label.labelTMP).text = string.Format(format, currentValue);
				yield return null;
			}
			((TMP_Text)label.labelTMP).text = string.Format(format, end);
			onComplete?.Invoke();
		}

		private float EaseInOut(float t)
		{
			return (t < 0.5f) ? (4f * t * t * t) : (1f - Mathf.Pow(-2f * t + 2f, 3f) / 2f);
		}

		public Coroutine AnimateLabel(REPOLabel label, Keyframe[] keyframes, bool hideAfterAnimationDone = false, LerpType lerpType = LerpType.Linear)
		{
			if (keyframes == null || keyframes.Length < 2)
			{
				Debug.LogError((object)"AnimateLabel requires at least 2 keyframes");
				return null;
			}
			return ((MonoBehaviour)this).StartCoroutine(AnimateLabelCoroutine(label, keyframes, hideAfterAnimationDone, lerpType));
		}

		private IEnumerator AnimateLabelCoroutine(REPOLabel label, Keyframe[] keyframes, bool hideAfterAnimationDone, LerpType lerpType)
		{
			((Component)label).gameObject.SetActive(true);
			((Transform)((REPOElement)label).rectTransform).localPosition = Vector2.op_Implicit(keyframes[0].Position);
			for (int i = 0; i < keyframes.Length - 1; i++)
			{
				Keyframe current = keyframes[i];
				Keyframe next = keyframes[i + 1];
				float duration = current.LerpTime;
				float elapsed = 0f;
				Debug.Log((object)$"Animating notification label ({i}/{keyframes.Length} keyframes)");
				while (elapsed < duration && (Object)(object)label != (Object)null && (Object)(object)((REPOElement)label).rectTransform != (Object)null)
				{
					elapsed += Time.deltaTime;
					float normalizedTime = Mathf.Clamp01(elapsed / duration);
					switch (lerpType)
					{
					case LerpType.Linear:
						((Transform)((REPOElement)label).rectTransform).localPosition = Vector2.op_Implicit(Vector2.Lerp(current.Position, next.Position, normalizedTime));
						break;
					case LerpType.Exponential:
					{
						float exponentialT = normalizedTime * normalizedTime;
						((Transform)((REPOElement)label).rectTransform).localPosition = Vector2.op_Implicit(Vector2.Lerp(current.Position, next.Position, exponentialT));
						break;
					}
					case LerpType.Easing:
					{
						float easedT = EaseInOut(normalizedTime);
						((Transform)((REPOElement)label).rectTransform).localPosition = Vector2.op_Implicit(Vector2.Lerp(current.Position, next.Position, easedT));
						break;
					}
					}
					yield return null;
				}
				((Transform)((REPOElement)label).rectTransform).localPosition = Vector2.op_Implicit(next.Position);
			}
			if (hideAfterAnimationDone)
			{
				((Component)label).gameObject.SetActive(false);
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerEnergy")]
	public static class UpgradePlayerEnergyPatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerEnergyRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeStamina[_steamID]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerExtraJump")]
	public static class UpgradePlayerExtraJumpPatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerExtraJumpRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeExtraJump[_steamID]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerGrabRange")]
	public static class UpgradePlayerGrabRangePatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerGrabRangeRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeRange[_steamID]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerGrabStrength")]
	public static class UpgradePlayerGrabStrengthPatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerGrabStrengthRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeStrength[_steamID]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerHealth")]
	public static class UpgradePlayerHealthPatch
	{
		private static void Postfix(string playerName, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerHealthRPC", (RpcTarget)1, new object[2]
				{
					playerName,
					___statsManager.playerUpgradeHealth[playerName]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerSprintSpeed")]
	public static class UpgradePlayerSprintSpeedPatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerSprintSpeedRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeSpeed[_steamID]
				});
			}
		}
	}
	[HarmonyPatch(typeof(PunManager))]
	[HarmonyPatch("UpgradePlayerTumbleLaunch")]
	public static class UpgradePlayerTumbleLaunchPatch
	{
		private static void Postfix(string _steamID, PhotonView ___photonView, StatsManager ___statsManager)
		{
			if (!SemiFunc.IsMasterClient() && GameManager.Multiplayer())
			{
				___photonView.RPC("UpgradePlayerTumbleLaunchRPC", (RpcTarget)1, new object[2]
				{
					_steamID,
					___statsManager.playerUpgradeLaunch[_steamID]
				});
			}
		}
	}
	public static class PLAYER_STATS_ENUM
	{
		public const string HEALTH_KEY = "Health";

		public const string STAMINA_KEY = "Stamina";

		public const string GRAB_STRENGTH_KEY = "Strength";

		public const string GRAB_RANGE_KEY = "Range";

		public const string SPRINT_SPEED_KEY = "Speed";

		public const string TUMBLE_LAUNCH_KEY = "Launch";

		public const string EXTRA_JUMP_KEY = "Extra Jump";
	}
	public static class ENEMY_TYPE_ENUM
	{
		public const string ANIMAL_KEY = "Animal";

		public const string BANG_KEY = "Banger";

		public const string BEAMER_KEY = "Clown";

		public const string BOWTIE_KEY = "Bowtie";

		public const string CEILING_EYE_KEY = "Peeper";

		public const string DUCK_KEY = "Apex Predator";

		public const string FLOATER_KEY = "Mentalist";

		public const string GNOME_KEY = "Gnome";

		public const string HIDDEN_KEY = "Hidden";

		public const string HUNTER_KEY = "Huntsman";

		public const string ROBE_KEY = "Robe";

		public const string RUNNER_KEY = "Reaper";

		public const string SLOW_MOUTH_KEY = "Spewer";

		public const string SLOW_WALKER_KEY = "Trudge";

		public const string THINMAN_KEY = "Shadow Child";

		public const string TUMBLER_KEY = "Chef";

		public const string UPSCREAM_KEY = "Upscream";

		public const string VALUABLE_THROWER_KEY = "Rugrat";

		public const string HEADMAN_KEY = "Headman";

		public static string[] GetAllTypes()
		{
			return new string[19]
			{
				"Animal", "Robe", "Gnome", "Apex Predator", "Upscream", "Banger", "Clown", "Rugrat", "Huntsman", "Bowtie",
				"Chef", "Mentalist", "Hidden", "Reaper", "Spewer", "Trudge", "Shadow Child", "Peeper", "Headman"
			};
		}
	}
	[HarmonyPatch(typeof(PlayerController))]
	public static class PlayerControllerPatch
	{
		public static float timeSinceSprintStop;

		public static float culmulatedHealthRegenerated;

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		public static void Update_Postfix(PlayerController __instance)
		{
			if (__instance.sprinting)
			{
				timeSinceSprintStop = 0f;
				return;
			}
			timeSinceSprintStop += Time.deltaTime;
			if (timeSinceSprintStop > PlayerLevels.DelayBeforeRegen.Value)
			{
				string steamID = PlayerSpawnPatch.GetSteamID();
				float num = 0f;
				if (steamID != null && StatsManager.instance.playerUpgradeStamina.ContainsKey(steamID))
				{
					num = StatsManager.instance.playerUpgradeStamina[steamID];
				}
				__instance.EnergyCurrent += ((float)PlayerLevels.BaseStaminaLevel.Value + num) * Time.deltaTime * PlayerLevels.StaminaRegenPerLevel.Value;
				__instance.EnergyCurrent = Mathf.Clamp(__instance.EnergyCurrent, 0f, __instance.EnergyStart);
				int num2 = 0;
				if (steamID != null && StatsManager.instance.playerUpgradeHealth.ContainsKey(steamID))
				{
					num2 = StatsManager.instance.playerUpgradeHealth[steamID];
				}
				culmulatedHealthRegenerated += (float)(PlayerLevels.BaseHealthLevel.Value + num2) * Time.deltaTime * PlayerLevels.HealthRegenPerLevel.Value;
				if (culmulatedHealthRegenerated >= 1f)
				{
					__instance.playerAvatarScript.playerHealth.Heal((int)culmulatedHealthRegenerated, false);
					culmulatedHealthRegenerated -= (int)culmulatedHealthRegenerated;
					culmulatedHealthRegenerated = Mathf.Max(culmulatedHealthRegenerated, 0f);
				}
			}
		}
	}
	public static class Utilities
	{
		public static void DebugGameObjectHierarchy(GameObject? go, int level = 0, string indent = "  ")
		{
			if (!((Object)(object)go == (Object)null))
			{
				string text = "";
				for (int i = 0; i < level; i++)
				{
					text += " ";
				}
				text += level;
				Debug.Log((object)(text + ": name=" + ((Object)go).name + ", tags=" + go.tag));
				if ((Object)(object)go.transform.parent != (Object)null)
				{
					DebugGameObjectHierarchy(((Component)go.transform.parent).gameObject, level + 1);
				}
			}
		}
	}
	[HarmonyPatch(typeof(HurtCollider))]
	public static class HurtColliderPatch
	{
		private static int CalculateTubleDamage(int tumbleLevel)
		{
			return tumbleLevel switch
			{
				0 => 15, 
				1 => PlayerLevels.TumbleLevel1Damage.Value, 
				2 => PlayerLevels.TumbleLevel2Damage.Value, 
				3 => PlayerLevels.TumbleLevel3Damage.Value, 
				4 => PlayerLevels.TumbleLevel4Damage.Value, 
				_ => PlayerLevels.TumbleLevel4Damage.Value + PlayerLevels.TumbleLevelNDamage.Value * (tumbleLevel - 4), 
			};
		}

		[HarmonyPatch("EnemyHurt")]
		[HarmonyPrefix]
		public static void EnemyHurt_Prefix(HurtCollider __instance)
		{
			PlayerTumble componentInParent = ((Component)__instance).GetComponentInParent<PlayerTumble>();
			if ((Object)(object)componentInParent != (Object)null && __instance.enemyDamage > 0)
			{
				Dictionary<string, int> currentStats = PlayerSpawnPatch.GetCurrentStats();
				if (currentStats == null)
				{
					Debug.Log((object)"Unable to get player stats");
					return;
				}
				int tumbleLevel = currentStats["Launch"];
				__instance.enemyDamage = CalculateTubleDamage(tumbleLevel);
			}
		}

		[HarmonyPatch("EnemyHurt")]
		[HarmonyPostfix]
		public static void EnemyHurt_Postfix(HurtCollider __instance)
		{
			PlayerTumble componentInParent = ((Component)__instance).GetComponentInParent<PlayerTumble>();
			if ((Object)(object)componentInParent != (Object)null && __instance.enemyDamage > 0)
			{
				__instance.enemyDamage = 15;
			}
		}
	}
	[HarmonyPatch(typeof(EnemyHealth))]
	internal static class EnemyHealthPatch
	{
		[HarmonyPatch("Death")]
		[HarmonyPrefix]
		public static void Death_Prefix(EnemyHealth __instance)
		{
			string text = __instance.enemy.EnemyParent.enemyName;
			if (text == null)
			{
				Debug.LogWarning((object)"EnemyHealth instance does not have a valid enemyName");
				text = "???";
			}
			if (!PlayerLevels.KillCounts.ContainsKey(text))
			{
				PlayerLevels.KillCounts[text] = 0;
			}
			PlayerLevels.KillCounts[text]++;
			Debug.Log((object)("Killed " + text));
		}
	}
	[HarmonyPatch(typeof(RoundDirector))]
	public static class RoundDirectorPatch
	{
		public static Transform? gameHUD;

		public static REPOLabel? noticeLabel;

		public static Vector2 LABEL_VISIBLE_POSITION = new Vector2(146f, -140f);

		public static Vector2 LABEL_OFFSCREEN_POSITION = new Vector2(146f, -2000f);

		public static Coroutine? playerLeaveNotificationCoroutine;

		public static Queue<string> playerLeaveQueue = new Queue<string>();

		public static bool isProcessingQueue = false;

		public static bool TryGetNotificationLabel()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("Game Hud");
			if ((Object)(object)gameHUD == (Object)null)
			{
				Debug.Log((object)"Searching for 'Game Hud' game object");
				gameHUD = ((val != null) ? val.transform : null);
			}
			if ((Object)(object)gameHUD != (Object)null && (Object)(object)noticeLabel == (Object)null)
			{
				Debug.Log((object)"gameHUD found! Creating notification label");
				noticeLabel = MenuAPI.CreateREPOLabel("", gameHUD, LABEL_OFFSCREEN_POSITION);
				((Component)noticeLabel).gameObject.SetActive(false);
			}
			return (Object)(object)gameHUD != (Object)null && (Object)(object)noticeLabel != (Object)null;
		}

		[HarmonyPatch(typeof(LoadingUI), "StopLoading")]
		[HarmonyPostfix]
		public static void StopLoading_Postfix(LoadingUI __instance)
		{
			Debug.Log((object)"Resetting notification label");
			TryGetNotificationLabel();
			playerLeaveQueue.Clear();
			isProcessingQueue = false;
			if (playerLeaveNotificationCoroutine != null)
			{
				Debug.Log((object)"Stopping player notification coroutine");
				((MonoBehaviour)UpgradeCoroutineManager.Instance).StopCoroutine(playerLeaveNotificationCoroutine);
			}
		}

		public static void UpdateNoticeLabel(string text)
		{
			if (!TryGetNotificationLabel())
			{
				Debug.LogWarning((object)"No Game HUD or Label found");
			}
			else
			{
				((TMP_Text)noticeLabel.labelTMP).text = text;
			}
		}

		public static void ToggleNoticeLabelVisibility(bool visible)
		{
			if (!TryGetNotificationLabel())
			{
				Debug.LogWarning((object)"No Label found");
			}
			else
			{
				((Component)noticeLabel).gameObject.SetActive(visible);
			}
		}

		public static void PlayerLeftNotice(string playerName)
		{
			playerLeaveQueue.Enqueue(playerName);
			Debug.Log((object)"Queued player leave event!");
			if (!isProcessingQueue)
			{
				Debug.Log((object)"Starting notification coroutine");
				isProcessingQueue = true;
				playerLeaveNotificationCoroutine = ((MonoBehaviour)UpgradeCoroutineManager.Instance).StartCoroutine(ProcessPlayerLeaveQueue());
			}
		}

		private static IEnumerator ProcessPlayerLeaveQueue()
		{
			while (playerLeaveQueue.Count > 0)
			{
				string playerName = playerLeaveQueue.Dequeue();
				string msg = playerName + "\nHas left!";
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null)
				{
					msg += $"\n({currentRoom.PlayerCount} remaining)";
				}
				Debug.Log((object)("Processing player " + playerName + " leave event notification"));
				UpdateNoticeLabel(msg);
				ToggleNoticeLabelVisibility(visible: true);
				if ((Object)(object)noticeLabel == (Object)null)
				{
					TryGetNotificationLabel();
					if ((Object)(object)noticeLabel == (Object)null)
					{
						Debug.LogError((object)"Could not process playerLeave notification because the label could not be created");
						playerLeaveQueue.Clear();
						break;
					}
				}
				((Transform)((REPOElement)noticeLabel).rectTransform).localPosition = Vector2.op_Implicit(LABEL_OFFSCREEN_POSITION);
				UpgradeCoroutineManager.Keyframe[] keyframes = new UpgradeCoroutineManager.Keyframe[4]
				{
					new UpgradeCoroutineManager.Keyframe(LABEL_OFFSCREEN_POSITION, 2f),
					new UpgradeCoroutineManager.Keyframe(LABEL_VISIBLE_POSITION, 5f),
					new UpgradeCoroutineManager.Keyframe(LABEL_VISIBLE_POSITION, 2f),
					new UpgradeCoroutineManager.Keyframe(LABEL_OFFSCREEN_POSITION, 1f)
				};
				yield return UpgradeCoroutineManager.Instance.AnimateLabel(noticeLabel, keyframes, hideAfterAnimationDone: true);
			}
			yield return (object)new WaitForSeconds(0.5f);
			isProcessingQueue = false;
		}
	}
}