Decompiled source of CookieProgression v0.1.2

CookieProgression.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using CookieFx;
using CookieFx.Client;
using CookieFx.Network;
using CookieFx.Network.Payloads;
using CookieFx.Platform;
using CookieFx.Players;
using CookieFx.Server;
using CookieFx.Skills;
using CookieProgression;
using CookieProgression.Experience;
using CookieProgression.Patches;
using CookieProgression.Payloads;
using CookieProgression.Skills;
using CookieProgression.UI;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CookieSylvia")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2")]
[assembly: AssemblyProduct("CookieProgression")]
[assembly: AssemblyTitle("CookieProgression")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.2.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 CookieFx.Skills
{
	public enum SkillFormat
	{
		Modifier,
		Mulitply,
		SubtractSeconds,
		Value
	}
}
namespace CookieFx.Patches
{
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class DoorLockPatch
	{
		[HarmonyPatch(typeof(DoorLock), "Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnUpdate(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo lockPickTimeLeft = AccessTools.DeclaredField(typeof(DoorLock), "lockPickTimeLeft");
			MethodInfo deltaTime = AccessTools.DeclaredPropertyGetter(typeof(Time), "deltaTime");
			MethodInfo getMul = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Func<SkillType, double>>>)(() => SkillManager.GetTeamMultiplier));
			int step = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				yield return instruction;
				if (CodeInstructionExtensions.IsLdarg(instruction, (int?)0))
				{
					step = 1;
					continue;
				}
				if (step == 1 && CodeInstructionExtensions.LoadsField(instruction, lockPickTimeLeft, false))
				{
					step = 2;
					continue;
				}
				if (step == 2 && CodeInstructionExtensions.Calls(instruction, deltaTime))
				{
					yield return new CodeInstruction(OpCodes.Ldc_I4, (object)18);
					yield return new CodeInstruction(OpCodes.Call, (object)getMul);
					yield return new CodeInstruction(OpCodes.Conv_R4, (object)null);
					yield return new CodeInstruction(OpCodes.Ldc_R4, (object)1f);
					yield return new CodeInstruction(OpCodes.Add, (object)null);
					yield return new CodeInstruction(OpCodes.Mul, (object)null);
				}
				step = 0;
			}
		}
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class ExpPatches
	{
		[HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnQuotaChange(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, int, int>>>)(() => ((TimeOfDay)null).SyncNewProfitQuotaClientRpc));
			MethodInfo target = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<TimeOfDay, int, int, int>>>)(() => OnQuotaChangeRedirect));
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)target);
					found = true;
				}
				else
				{
					yield return instruction;
				}
			}
			if (!found)
			{
				Logger.Error("[Patch] Unable to patch quota change.");
			}
		}

		private static void OnQuotaChangeRedirect(TimeOfDay script, int newProfitQuota, int overtimeBonus, int fulfilledQuota)
		{
			int num = overtimeBonus;
			try
			{
				num = (int)((double)overtimeBonus * (1.0 + SkillManager.GetTeamMultiplier(SkillType.OvertimeBonus)));
			}
			finally
			{
				script.SyncNewProfitQuotaClientRpc(newProfitQuota, num, fulfilledQuota);
			}
		}
	}
}
namespace CookieProgression
{
	internal static class Config
	{
		private record BoundSkill(ConfigEntry<bool> Enabled, ConfigEntry<int> MaxLevel, ConfigEntry<int> Multiplier);

		private record BoundEnemy(ConfigEntry<EnemyExpType> ExpType, ConfigEntry<int> Range, ConfigEntry<int> BaseExp);

		public enum EnemyExpType
		{
			Disabled,
			AoE,
			Attacker
		}

		private static readonly Dictionary<SkillType, BoundSkill> SkillBindings = new Dictionary<SkillType, BoundSkill>();

		private static readonly Dictionary<Type, BoundEnemy> EnemyBindings = new Dictionary<Type, BoundEnemy>();

		private static bool s_dirty = false;

		internal static void Setup(ConfigFile file)
		{
			Guard.NotNull<ConfigFile>(file, "file");
			foreach (BoundSkill value in SkillBindings.Values)
			{
				value.Enabled.SettingChanged -= OnSkillChanged;
				value.MaxLevel.SettingChanged -= OnSkillChanged;
				value.Multiplier.SettingChanged -= OnSkillChanged;
			}
			SkillBindings.Clear();
			SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType));
			foreach (SkillType skill in array)
			{
				BindSkill(file, skill);
			}
			foreach (BoundSkill value2 in SkillBindings.Values)
			{
				value2.Enabled.SettingChanged += OnSkillChanged;
				value2.MaxLevel.SettingChanged += OnSkillChanged;
				value2.Multiplier.SettingChanged += OnSkillChanged;
			}
			EnemyBindings.Clear();
			foreach (Type item in (from type in Reflect.AllTypesAssignableTo(typeof(EnemyAI))
				where type != typeof(EnemyAI)
				select type).OrderBy(GetEnemyFriendlyName))
			{
				BindEnemy(file, item);
			}
		}

		private static void OnSkillChanged(object? sender, EventArgs e)
		{
			if (!Networking.IsConnected || !Networking.Instance.IsServer)
			{
				return;
			}
			s_dirty = true;
			Networking.EnqueueTask((Action<Networking>)delegate(Networking instance)
			{
				if (!s_dirty || !instance.IsServer)
				{
					return;
				}
				s_dirty = false;
				AbstractServer server = instance.Server;
				SkillManager skills = default(SkillManager);
				foreach (ServerPlayer player in server.Players)
				{
					if (((AbstractPlayer)player).TryGet<SkillManager>(ref skills))
					{
						SetSkills(skills);
					}
				}
			});
		}

		internal static void SetSkills(SkillManager manager)
		{
			manager.SetDefinitions(from x in SkillBindings
				where x.Value.Enabled.Value
				select (x.Key, Math.Clamp(x.Value.MaxLevel.Value, 1, 99999), Math.Clamp(x.Value.Multiplier.Value, 1, 1000000)));
		}

		internal static (EnemyExpType, int Range, int BaseExp) GetEnemyExp(Type enemy)
		{
			if (EnemyBindings.TryGetValue(enemy, out BoundEnemy value))
			{
				return (value.ExpType.Value, Math.Max(value.Range.Value, 0), Math.Max(value.BaseExp.Value, 0));
			}
			Logger.Warning("Enemy [" + enemy.FullName + "] doesn't have a bound config entry.");
			return (EnemyExpType.Disabled, 0, 0);
		}

		private static void BindSkill(ConfigFile file, SkillType skill)
		{
			string name = skill.GetName();
			Logger.Info("Found skill type [" + name + "]");
			int defaultMaxLevel = skill.GetDefaultMaxLevel();
			int defaultMultiplier = skill.GetDefaultMultiplier();
			ConfigEntry<bool> enabled = file.Bind<bool>(name, "Enable " + name, true, "Enable the " + name + " skill.");
			ConfigEntry<int> maxLevel = file.Bind<int>(name, name + " Max Level", defaultMaxLevel, "Maximum level for " + name);
			ConfigEntry<int> multiplier = file.Bind<int>(name, name + " Multiplier", defaultMultiplier, $"How much does the {name} skill increase per level? ({10000:N0} = 100% or 100s)");
			SkillBindings[skill] = new BoundSkill(enabled, maxLevel, multiplier);
		}

		private static void BindEnemy(ConfigFile file, Type enemy)
		{
			string enemyFriendlyName = GetEnemyFriendlyName(enemy);
			Logger.Info("Found enemy type [" + enemyFriendlyName + "] (aka. " + enemy.FullName + ")");
			string text = default(string);
			string text2 = (PluginUtils.TryGetPluginId(enemy.Assembly, ref text) ? ("Internal: " + enemy.FullName + "\nModded Enemy from " + text + "\n\n") : ((!(enemy.Assembly == typeof(EnemyAI).Assembly)) ? ("Internal: " + enemy.FullName + "\nUnknown Enemy in " + enemy.Assembly.FullName + "\n\n") : ("Internal: " + enemy.FullName + "\nVanilla Enemy\n\n")));
			ConfigEntry<EnemyExpType> expType = file.Bind<EnemyExpType>(enemyFriendlyName, enemyFriendlyName + " Mode", GetDefaultEnemyMode(enemy), text2 + "Exp distribution from killing " + enemyFriendlyName + ".\n\nDisabled = Does not award exp.\nAoE = Awards exp within a range.\nAttacker = Awards exp to the attacker.");
			ConfigEntry<int> range = file.Bind<int>(enemyFriendlyName, enemyFriendlyName + " Range", GetDefaultEnemyExpRange(enemy), text2 + "Exp distribution range in units, only used if mode is [AoE]");
			ConfigEntry<int> baseExp = file.Bind<int>(enemyFriendlyName, enemyFriendlyName + " Base Exp", GetDefaultEnemyBaseExp(enemy), text2 + "The base exp that " + enemyFriendlyName + " awards when killed.");
			EnemyBindings[enemy] = new BoundEnemy(expType, range, baseExp);
		}

		internal static string GetEnemyFriendlyName(Type type)
		{
			string fullName = type.FullName;
			if (1 == 0)
			{
			}
			string result = fullName switch
			{
				"BaboonBirdAI" => "Baboon Hawk", 
				"BushWolfEnemy" => "Kidnapper Fox", 
				"ButlerBeesEnemyAI" => "Butler Bees", 
				"ButlerEnemyAI" => "Butler", 
				"CaveDwellerAI" => "Maneater", 
				"ClaySurgeonAI" => "Barber", 
				"DocileLocustBeesAI" => "Roaming Locust", 
				"DoublewingAI" => "Manticoil", 
				"FlowerSnakeEnemy" => "Tulip Snake", 
				"JesterAI" => "Jester", 
				"LassoManAI" => "Lasso (Unused)", 
				"MaskedPlayerEnemy" => "Masked", 
				"NutcrackerEnemyAI" => "Nutcracker", 
				"PufferAI" => "Puffer", 
				"RadMechAI" => "Old Bird", 
				"SandSpiderAI" => "Spider", 
				"SandWormAI" => "Earth Leviathan", 
				"BlobAI" => "Hygrodere", 
				"CentipedeAI" => "Snare Flea", 
				"CrawlerAI" => "Thumper", 
				"RedLocustBees" => "Circuit Bee", 
				"DressGirlAI" => "Ghost Girl", 
				"FlowermanAI" => "Bracken", 
				"ForestGiantAI" => "Forest Keeper", 
				"HoarderBugAI" => "Hoarding Bug", 
				"MouthDogAI" => "Eyeless Dog", 
				"SpringManAI" => "Coil-Head", 
				"TestEnemy" => "Test (Unused)", 
				"Kittenji.HerobrineMod.HerobrineAI" => "Herobrine", 
				"LethalCompanyVileVendingMachine.VileVendingMachineServer" => "Vile Vending Machine", 
				"BaldiEnemy.BaldiEnemy" => "Baldi", 
				"LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => "Harp Ghost", 
				"LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => "Enforcer Ghost", 
				"LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => "Bagpipes Ghost", 
				"ScarletMansion.KnightGhostVariant" => "Knight (Ghost)", 
				"ScarletMansion.KnightVariant" => "Knight", 
				"ScarletMansion.GamePatch.Enemies.KnightV2Variant" => "Knight (v2)", 
				"ScarletMansion.GamePatch.Enemies.MaidVariant" => "Sakuya (Maid)", 
				"ImmortalSnail.SnailAI" => "Immortal Snail", 
				"HarbingerBehaviour.AICode.HarbingerAI" => "Harbinger", 
				"ShyGuy.AI.ShyGuyAI" => "Shy Guy", 
				"DontTouchMe.DTMEntityAI" => "Dont Touch Me", 
				"Moonswept.CleanerAI" => "Cleaner", 
				"Moonswept.MobileTurretAI" => "Mobile Turret", 
				"LCOffice.Patches.ShrimpEnemyAI" => "Shrimp (Enemy)", 
				"LCOffice.Patches.ShrimpAI" => "Shrimp", 
				"SmallfryEnemy.SmallfryEnemy" => "Smallfry", 
				"LCPeeper.PeeperAI" => "Peeper", 
				"Menstalker_ybdkSKB.Menstalker_ybdkSKB" => "Menstalker", 
				"Locker.MonoBehaviours.LockerAI" => "Locker", 
				"LethalThings.RoombaAI" => "Roomba", 
				"LethalThings.MonoBehaviours.FishFriend" => "Fish Friend", 
				"LethalThings.MonoBehaviours.Maggie" => "Maggie", 
				"LethalThings.MonoBehaviours.RobotAI" => "Robot", 
				"NightmareFoxyLC.FoxyAi" => "Nightmare Foxy", 
				"NightmareFreddy.NightmareFreddy.NightmareFreddyAi" => "Nightmare Freddy", 
				"NightmareFreddy.Freddles.FreddlesAi" => "Freddles", 
				"GiantSpecimens.Enemy.DriftwoodGiantAI" => "Driftwood Giant", 
				"GiantSpecimens.Enemy.PinkGiantAI" => "Pink Giant", 
				"GiantSpecimens.Enemy.StellarSovereignAI" => "Stellar Sovereign", 
				_ => type.Name, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		internal static int GetDefaultEnemyBaseExp(Type type)
		{
			string fullName = type.FullName;
			if (1 == 0)
			{
			}
			int result = fullName switch
			{
				"BaboonBirdAI" => 30, 
				"BushWolfEnemy" => 75, 
				"ButlerEnemyAI" => 75, 
				"CaveDwellerAI" => 250, 
				"DoublewingAI" => 20, 
				"FlowerSnakeEnemy" => 10, 
				"MaskedPlayerEnemy" => 40, 
				"NutcrackerEnemyAI" => 80, 
				"SandSpiderAI" => 60, 
				"CentipedeAI" => 30, 
				"CrawlerAI" => 75, 
				"FlowermanAI" => 80, 
				"ForestGiantAI" => 200, 
				"HoarderBugAI" => 30, 
				"MouthDogAI" => 120, 
				"LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => 60, 
				"LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => 175, 
				"LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => 100, 
				"SmallfryEnemy.SmallfryEnemy" => 30, 
				"LCPeeper.PeeperAI" => 10, 
				"LethalThings.RoombaAI" => 50, 
				"NightmareFreddy.Freddles.FreddlesAi" => 15, 
				_ => 0, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		internal static int GetDefaultEnemyExpRange(Type type)
		{
			string fullName = type.FullName;
			if (1 == 0)
			{
			}
			int result = fullName switch
			{
				"ForestGiantAI" => 20, 
				"LCPeeper.PeeperAI" => 1, 
				"LethalThings.RoombaAI" => 15, 
				"NightmareFreddy.Freddles.FreddlesAi" => 15, 
				"SmallfryEnemy.SmallfryEnemy" => 5, 
				_ => (GetDefaultEnemyMode(type) == EnemyExpType.AoE) ? 10 : 0, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		internal static EnemyExpType GetDefaultEnemyMode(Type type)
		{
			string fullName = type.FullName;
			if (1 == 0)
			{
			}
			EnemyExpType result = fullName switch
			{
				"BaboonBirdAI" => EnemyExpType.AoE, 
				"BushWolfEnemy" => EnemyExpType.AoE, 
				"ButlerEnemyAI" => EnemyExpType.AoE, 
				"CaveDwellerAI" => EnemyExpType.AoE, 
				"DoublewingAI" => EnemyExpType.Attacker, 
				"FlowerSnakeEnemy" => EnemyExpType.Attacker, 
				"MaskedPlayerEnemy" => EnemyExpType.AoE, 
				"NutcrackerEnemyAI" => EnemyExpType.AoE, 
				"SandSpiderAI" => EnemyExpType.AoE, 
				"CentipedeAI" => EnemyExpType.AoE, 
				"CrawlerAI" => EnemyExpType.AoE, 
				"FlowermanAI" => EnemyExpType.AoE, 
				"ForestGiantAI" => EnemyExpType.AoE, 
				"HoarderBugAI" => EnemyExpType.AoE, 
				"MouthDogAI" => EnemyExpType.AoE, 
				"LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => EnemyExpType.AoE, 
				"LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => EnemyExpType.AoE, 
				"LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => EnemyExpType.AoE, 
				"SmallfryEnemy.SmallfryEnemy" => EnemyExpType.AoE, 
				"LCPeeper.PeeperAI" => EnemyExpType.AoE, 
				"LethalThings.RoombaAI" => EnemyExpType.AoE, 
				"NightmareFreddy.Freddles.FreddlesAi" => EnemyExpType.AoE, 
				_ => EnemyExpType.Disabled, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
	internal static class Logger
	{
		private static ILogger s_logger = (ILogger)(object)Unity.Shared;

		public static ILogger Source
		{
			get
			{
				return s_logger;
			}
			[param: AllowNull]
			set
			{
				s_logger = (ILogger)(((object)value) ?? ((object)Unity.Shared));
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Debug(object message)
		{
			Source.Debug(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Info(object message)
		{
			Source.Info(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Warning(object message)
		{
			Source.Warning(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Error(object message)
		{
			Source.Error(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Fatal(object message)
		{
			Source.Fatal(message);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("CookieProgression", "CookieProgression", "0.1.2")]
	public sealed class Plugin : BaseUnityPlugin, ICookieDependency
	{
		private static AssetBundle? s_menuBundle;

		public static AssetBundle MenuBundle => s_menuBundle ?? throw new InvalidOperationException("Use before initialize.");

		bool ICookieDependency.TrackOtherClients => false;

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Logger.Source = (ILogger)new BepInLoggerSource(((BaseUnityPlugin)this).Logger);
			using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("CookieProgression.res.skillmenu") ?? throw new InvalidOperationException("Embedded resource returned null.");
			s_menuBundle = AssetBundle.LoadFromStream(stream);
			new Harmony("CookieProgression").PatchAll(typeof(Plugin).Assembly);
			PluginUtils.Register((ICookieDependency)(object)this);
			Config.Setup(((BaseUnityPlugin)this).Config);
			SkillManager.Bootstrap();
			for (int i = 1; i <= 20; i++)
			{
				int experience = ExperienceGroups.Lethal.GetExperience(i);
				int level = ExperienceGroups.Lethal.GetLevel(experience);
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Lvl. {level} = {experience}");
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CookieProgression v0.1.2 loaded.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Icon, Ideas and Game Balance by Kaede");
			GameClient.OnShutdown += delegate
			{
				SkillMenu.OnDestroy();
			};
		}

		void ICookieDependency.OnPlayerTracked(AbstractPlayer player)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Started tracking {player}");
			player.Attach<SkillManager>(new SkillManager(player));
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "CookieProgression";

		public const string Name = "CookieProgression";

		public const string Version = "0.1.2";
	}
}
namespace CookieProgression.UI
{
	[HarmonyPatch]
	[HarmonyWrapSafe]
	public sealed class SkillMenu
	{
		internal static bool IsMenuOpen;

		internal static SkillMenu? Instance;

		private readonly GameObject _mainPanel;

		private readonly GameObject _infoPanel;

		private readonly List<GameObject> _skillButtons = new List<GameObject>();

		public SkillManager Manager { get; }

		internal static void OnInitialize(SkillManager client)
		{
			if (IsMenuOpen)
			{
				try
				{
					Instance?.OnBackButton();
				}
				catch
				{
				}
				IsMenuOpen = false;
			}
			Instance = new SkillMenu(client);
		}

		internal static void OnDestroy()
		{
			if (Instance != null && IsMenuOpen)
			{
				try
				{
					Instance.OnBackButton();
				}
				catch
				{
				}
				IsMenuOpen = false;
			}
			Instance = null;
		}

		public void OpenSkillMenu()
		{
			if (!Object.op_Implicit((Object)(object)_mainPanel))
			{
				OnDestroy();
				return;
			}
			IsMenuOpen = true;
			_mainPanel.SetActive(true);
		}

		private SkillMenu(SkillManager manager)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00c7: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			Guard.NotNull<SkillManager>(manager, "manager");
			Guard.IsTrue(manager.Player.IsClient, (string)null, "manager.Player.IsClient");
			Manager = manager;
			_mainPanel = Object.Instantiate<GameObject>(Plugin.MenuBundle.LoadAsset<GameObject>("SkillMenu"));
			((Object)_mainPanel).name = "SkillMenu";
			_mainPanel.SetActive(false);
			_infoPanel = ((Component)_mainPanel.transform.GetChild(1)).gameObject;
			_infoPanel.SetActive(false);
			GameObject gameObject = ((Component)_mainPanel.transform.GetChild(4)).gameObject;
			Button component = gameObject.GetComponent<Button>();
			ButtonClickedEvent val = new ButtonClickedEvent();
			ButtonClickedEvent val2 = val;
			component.onClick = val;
			ButtonClickedEvent val3 = val2;
			((UnityEvent)val3).AddListener(new UnityAction(OnBackButton));
			foreach (SkillDefinition definition in manager.Definitions)
			{
				Logger.Info($"Creating button for {definition.Type}.");
				GameObject val4 = SetupUpgradeButton(definition);
				if (val4 != null)
				{
					_skillButtons.Add(val4);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(QuickMenuManager), "Update")]
		private static void OnUpdate()
		{
			if (Instance != null && Object.op_Implicit((Object)(object)Instance._mainPanel))
			{
				if (!IsMenuOpen)
				{
					Instance._mainPanel.SetActive(false);
					return;
				}
				Instance.UpdateUnspec();
				Instance._mainPanel.SetActive(true);
				GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons");
				val.SetActive(false);
				GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/PlayerList");
				val2.SetActive(false);
				GameObject gameObject = ((Component)Instance._mainPanel.transform.GetChild(2)).gameObject;
				gameObject = ((Component)gameObject.transform.GetChild(1)).gameObject;
				TextMeshProUGUI component = gameObject.GetComponent<TextMeshProUGUI>();
				((TMP_Text)component).SetText(Instance.Manager.UnusedSkillPoints.ToString(), true);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")]
		private static void OnClose()
		{
			IsMenuOpen = false;
		}

		internal void OnBackButton()
		{
			IsMenuOpen = false;
			_mainPanel.SetActive(false);
			GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons");
			val.SetActive(true);
			GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/PlayerList");
			val2.SetActive(true);
		}

		private void UpdateUnspec()
		{
			GameObject gameObject = ((Component)_infoPanel.transform.GetChild(6)).gameObject;
			GameObject gameObject2 = ((Component)_infoPanel.transform.GetChild(7)).gameObject;
			GameObject gameObject3 = ((Component)_infoPanel.transform.GetChild(8)).gameObject;
			GameObject gameObject4 = ((Component)_infoPanel.transform.GetChild(9)).gameObject;
			gameObject4.SetActive(false);
			StartOfRound instance = StartOfRound.Instance;
			if (instance != null && instance.inShipPhase)
			{
				EndOfGameStats gameStats = instance.gameStats;
				if (gameStats != null && gameStats.daysSpent == 0)
				{
					gameObject4.SetActive(false);
					gameObject.SetActive(true);
					gameObject2.SetActive(true);
					gameObject3.SetActive(true);
					return;
				}
			}
			gameObject4.SetActive(true);
			((TMP_Text)gameObject4.GetComponent<TextMeshProUGUI>()).SetText("Unspec on first day in orbit.", true);
			gameObject.SetActive(false);
			gameObject2.SetActive(false);
			gameObject3.SetActive(false);
		}

		private GameObject? SetupUpgradeButton(SkillDefinition definition)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_00f4: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			GameObject gameObject = ((Component)_mainPanel.transform.GetChild(0)).gameObject;
			if (!Object.op_Implicit((Object)(object)gameObject))
			{
				Logger.Error("Couldn't find template button!");
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(gameObject);
			((Object)val).name = definition.Type.ToString();
			GameObject gameObject2 = ((Component)_mainPanel.transform.GetChild(3)).gameObject;
			GameObject gameObject3 = ((Component)gameObject2.transform.GetChild(1)).gameObject;
			val.transform.SetParent(gameObject3.transform, false);
			GameObject gameObject4 = ((Component)val.transform.GetChild(0)).gameObject;
			((TMP_Text)gameObject4.GetComponent<TextMeshProUGUI>()).SetText(definition.ShortName, true);
			LoadSkillData(definition, val);
			val.SetActive(true);
			Button component = val.GetComponent<Button>();
			ButtonClickedEvent val2 = new ButtonClickedEvent();
			ButtonClickedEvent val3 = val2;
			component.onClick = val2;
			ButtonClickedEvent val4 = val3;
			SkillType type = definition.Type;
			((UnityEvent)val4).AddListener((UnityAction)delegate
			{
				UpdateSkillPanel(type);
			});
			return val;
		}

		public void LoadAllSkillData()
		{
			foreach (SkillDefinition definition in Manager.Definitions)
			{
				GameObject val = _skillButtons.Find((GameObject x) => string.Equals(((Object)x).name, definition.Type.ToString(), StringComparison.Ordinal));
				if (val != null)
				{
					LoadSkillData(definition, val);
				}
			}
		}

		public void LoadSkillData(SkillDefinition definition)
		{
			foreach (GameObject skillButton in _skillButtons)
			{
				if (string.Equals(((Object)skillButton).name, definition.Type.ToString(), StringComparison.Ordinal))
				{
					LoadSkillData(definition, skillButton);
				}
			}
		}

		private void LoadSkillData(SkillDefinition definition, GameObject button)
		{
			SkillType type = definition.Type;
			string text = Manager.GetAllocated(definition.Type).ToString();
			GameObject gameObject = ((Component)button.transform.GetChild(1)).gameObject;
			((TMP_Text)gameObject.GetComponent<TextMeshProUGUI>()).SetText(text, true);
			GameObject gameObject2 = ((Component)button.transform.GetChild(2)).gameObject;
			((TMP_Text)gameObject2.GetComponent<TextMeshProUGUI>()).SetText("(" + type.Format(Manager.GetMultiplier(type)) + " " + definition.Name + ")", true);
			((TMP_Text)button.GetComponentInChildren<TextMeshProUGUI>()).SetText(definition.ShortName + ":", true);
		}

		private void UpdateSkillPanel(SkillType type)
		{
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Expected O, but got Unknown
			//IL_01f9: Expected O, but got Unknown
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_0226: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Expected O, but got Unknown
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Expected O, but got Unknown
			//IL_0253: Expected O, but got Unknown
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Expected O, but got Unknown
			//IL_0280: Expected O, but got Unknown
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Expected O, but got Unknown
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			//IL_02ad: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Expected O, but got Unknown
			//IL_02da: Expected O, but got Unknown
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Expected O, but got Unknown
			if (!Manager.TryGetDefinition(type, out SkillDefinition definition))
			{
				Logger.Warning($"Skill {type} doesn't have a definiton and is unable to populate info panel with data. (CLIENT IS VERY OUT OF SYNC)");
				return;
			}
			if (!_infoPanel.activeSelf)
			{
				_infoPanel.SetActive(true);
			}
			TextMeshProUGUI component = ((Component)_infoPanel.transform.GetChild(0)).gameObject.GetComponent<TextMeshProUGUI>();
			TextMeshProUGUI component2 = ((Component)_infoPanel.transform.GetChild(1)).gameObject.GetComponent<TextMeshProUGUI>();
			TextMeshProUGUI component3 = ((Component)_infoPanel.transform.GetChild(2)).gameObject.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).SetText(definition.Name, true);
			if (definition.MaxLevel == 99999)
			{
				((TMP_Text)component2).SetText(Manager.GetAllocated(type).ToString(), true);
			}
			else
			{
				((TMP_Text)component2).SetText($"{Manager.GetAllocated(type)} / {definition.MaxLevel}", true);
			}
			((TMP_Text)component3).SetText(definition.Description, true);
			GameObject gameObject = ((Component)_infoPanel.transform.GetChild(3)).gameObject;
			GameObject gameObject2 = ((Component)_infoPanel.transform.GetChild(4)).gameObject;
			GameObject gameObject3 = ((Component)_infoPanel.transform.GetChild(5)).gameObject;
			GameObject gameObject4 = ((Component)_infoPanel.transform.GetChild(6)).gameObject;
			GameObject gameObject5 = ((Component)_infoPanel.transform.GetChild(7)).gameObject;
			GameObject gameObject6 = ((Component)_infoPanel.transform.GetChild(8)).gameObject;
			Button component4 = gameObject.GetComponent<Button>();
			ButtonClickedEvent val = new ButtonClickedEvent();
			ButtonClickedEvent val2 = val;
			component4.onClick = val;
			ButtonClickedEvent val3 = val2;
			((UnityEvent)val3).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, 5);
			});
			Button component5 = gameObject2.GetComponent<Button>();
			ButtonClickedEvent val4 = new ButtonClickedEvent();
			val2 = val4;
			component5.onClick = val4;
			ButtonClickedEvent val5 = val2;
			((UnityEvent)val5).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, 2);
			});
			Button component6 = gameObject3.GetComponent<Button>();
			ButtonClickedEvent val6 = new ButtonClickedEvent();
			val2 = val6;
			component6.onClick = val6;
			ButtonClickedEvent val7 = val2;
			((UnityEvent)val7).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, 1);
			});
			Button component7 = gameObject4.GetComponent<Button>();
			ButtonClickedEvent val8 = new ButtonClickedEvent();
			val2 = val8;
			component7.onClick = val8;
			ButtonClickedEvent val9 = val2;
			((UnityEvent)val9).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, -5);
			});
			Button component8 = gameObject5.GetComponent<Button>();
			ButtonClickedEvent val10 = new ButtonClickedEvent();
			val2 = val10;
			component8.onClick = val10;
			ButtonClickedEvent val11 = val2;
			((UnityEvent)val11).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, -2);
			});
			Button component9 = gameObject6.GetComponent<Button>();
			ButtonClickedEvent val12 = new ButtonClickedEvent();
			val2 = val12;
			component9.onClick = val12;
			ButtonClickedEvent val13 = val2;
			((UnityEvent)val13).AddListener((UnityAction)delegate
			{
				ChangeSkillPoints(type, -1);
			});
		}

		private void ChangeSkillPoints(SkillType type, int amount)
		{
			if (!Manager.TryGetDefinition(type, out SkillDefinition definition))
			{
				Logger.Warning($"Skill {type} doesn't have a definiton. (CLIENT IS VERY OUT OF SYNC)");
				return;
			}
			if (IngamePlayerSettings.Instance != null)
			{
				IngamePlayerSettings instance = IngamePlayerSettings.Instance;
				InputAction val = instance.playerInput.actions.FindAction("Sprint", false);
				if (val != null && val.IsPressed())
				{
					amount *= 10;
				}
				InputAction val2 = instance.playerInput.actions.FindAction("Crouch", false);
				if (val2 != null && val2.IsPressed())
				{
					amount = ((amount < 1) ? (-Manager.GetAllocated(type)) : Manager.UnusedSkillPoints);
				}
			}
			Manager.SetAlloacted(type, Math.Max(Manager.GetAllocated(type) + amount, 0));
			UpdateSkillPanel(type);
			foreach (GameObject skillButton in _skillButtons)
			{
				if (string.Equals(((Object)skillButton).name, definition.Type.ToString(), StringComparison.Ordinal))
				{
					LoadSkillData(definition, skillButton);
				}
			}
		}
	}
}
namespace CookieProgression.Skills
{
	public sealed class SkillDefinition
	{
		public static readonly int EncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>() + FastBufferWriter.GetWriteSize<int>();

		public SkillType Type { get; }

		public int MaxLevel { get; }

		public int Multiplier { get; }

		public bool IsNegative { get; }

		public bool IsTeamShared { get; }

		public string Name { get; }

		public string ShortName { get; }

		public string Description { get; }

		public SkillDefinition(SkillType type, int maxLevel, int multiplier)
		{
			Guard.MustBeGreaterThan<int>(maxLevel, 0, "maxLevel");
			Guard.MustBeGreaterThan<int>(multiplier, 0, "multiplier");
			Type = type;
			MaxLevel = maxLevel;
			Multiplier = multiplier;
			IsNegative = type.IsNegative();
			IsTeamShared = type.IsTeamShared();
			Name = type.GetName();
			ShortName = type.GetShortName();
			Description = type.GetDescription();
			if (IsNegative && IsTeamShared)
			{
				throw new InvalidOperationException($"SkillType {type} is both negative and team shared.");
			}
		}

		public double GetFinalMultiplier(int level)
		{
			return (double)Multiplier / 10000.0 * (double)level;
		}

		public ulong GetRawMultiplier(int level)
		{
			return (ulong)(Multiplier * (uint)level);
		}

		public static SkillDefinition Decode(FastBufferReader reader)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			SkillType type = default(SkillType);
			((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref type, default(ForEnums));
			int maxLevel = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref maxLevel, default(ForPrimitives));
			int multiplier = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref multiplier, default(ForPrimitives));
			return new SkillDefinition(type, maxLevel, multiplier);
		}

		public void Encode(FastBufferWriter writer)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			SkillType type = Type;
			((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref type, default(ForEnums));
			int maxLevel = MaxLevel;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref maxLevel, default(ForPrimitives));
			maxLevel = Multiplier;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref maxLevel, default(ForPrimitives));
		}
	}
	public sealed class SkillManager : IPlayerComponent
	{
		private readonly Dictionary<SkillType, SkillDefinition> _definitions = new Dictionary<SkillType, SkillDefinition>();

		private readonly Dictionary<SkillType, int> _previousAllocations = new Dictionary<SkillType, int>();

		private readonly Dictionary<SkillType, int> _allocations = new Dictionary<SkillType, int>();

		private readonly Dictionary<SkillType, int> _loaded = new Dictionary<SkillType, int>();

		private static readonly Dictionary<SkillType, ulong> TeamValues;

		public AbstractPlayer Player { get; }

		public IExperienceGroup ExpGroup { get; } = ExperienceGroups.Lethal;


		public int Exp { get; private set; }

		public int Level => ExpGroup.GetLevel(Exp);

		public int UsedExp => ExpGroup.GetExperience(Level);

		public int RequiredExp => ExpGroup.GetExperience(Level + 1);

		public bool HasMoreLevels => NeededExp != 0;

		public int NeededExp => RequiredExp - UsedExp;

		public int UnusedExp => Exp - UsedExp;

		public int SkillPoints
		{
			get
			{
				int level = Level;
				int num = level / 5;
				int num2 = level / 10;
				int num3 = level / 100 * 2;
				return 5 + (level - 1 + num + num2 + num3) * 2;
			}
		}

		public int Allocations { get; private set; }

		public int UnusedSkillPoints => Math.Max(SkillPoints - Allocations, 0);

		public IEnumerable<SkillDefinition> Definitions => _definitions.Values;

		public string ComponentId => "SkillManager";

		internal static void Bootstrap()
		{
		}

		static SkillManager()
		{
			TeamValues = new Dictionary<SkillType, ulong>();
			ClientNetworking.Register<TeamSkillS2C>(TeamSkillS2C.Type, (Action<ClientPlayer, TeamSkillS2C>)delegate(ClientPlayer player, TeamSkillS2C payload)
			{
				SkillManager skillManager5 = default(SkillManager);
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager5))
				{
					TeamValues[payload.SkillType] = Math.Max(payload.Multiplier, 0uL);
					Logger.Info($"[Server says team] {payload.SkillType} totals {payload.Multiplier}");
					if (skillManager5._definitions.TryGetValue(payload.SkillType, out SkillDefinition value))
					{
						SkillMenu.Instance?.LoadSkillData(value);
					}
				}
			});
			ClientNetworking.Register<SetSkillS2C>(SetSkillS2C.Type, (Action<ClientPlayer, SetSkillS2C>)delegate(ClientPlayer player, SetSkillS2C payload)
			{
				SkillManager skillManager4 = default(SkillManager);
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager4))
				{
					skillManager4._allocations[payload.SkillType] = payload.Points;
					Logger.Info($"[Server says] {payload.SkillType} is {payload.Points}");
					skillManager4.UpdateAllocations(updating: false);
				}
			});
			ClientNetworking.Register<DefineSkillsS2C>(DefineSkillsS2C.Type, (Action<ClientPlayer, DefineSkillsS2C>)delegate(ClientPlayer player, DefineSkillsS2C payload)
			{
				SkillManager skillManager3 = default(SkillManager);
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager3))
				{
					SkillMenu.OnDestroy();
					skillManager3._previousAllocations.Clear();
					skillManager3._definitions.Clear();
					if (!((AbstractClientPlayer)player).IsLocal)
					{
						TeamValues.Clear();
					}
					foreach (SkillDefinition definition in payload.Definitions)
					{
						Logger.Info($"[Server defines] {definition.Type}");
						skillManager3._definitions[definition.Type] = definition;
					}
					skillManager3.UpdateAllocations(updating: false);
					SkillMenu.OnInitialize(skillManager3);
				}
			});
			ClientNetworking.Register<SetExpS2C>(SetExpS2C.Type, (Action<ClientPlayer, SetExpS2C>)delegate(ClientPlayer player, SetExpS2C payload)
			{
				SkillManager skillManager2 = default(SkillManager);
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager2))
				{
					int level = skillManager2.Level;
					skillManager2.Exp = Math.Max(payload.Exp, 0);
					if (level < skillManager2.Level)
					{
						MenuPatches.ShowLevelPopup();
					}
				}
			});
			ServerNetworking.Register<AllocateSkillC2S>(AllocateSkillC2S.Type, (Action<ServerPlayer, AllocateSkillC2S>)delegate(ServerPlayer player, AllocateSkillC2S payload)
			{
				SkillManager skillManager = default(SkillManager);
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager))
				{
					Logger.Info($"[Client asks] {payload.SkillType} is {payload.Points}");
					skillManager.SetAlloacted(payload.SkillType, payload.Points);
				}
			});
		}

		internal SkillManager(AbstractPlayer player)
		{
			Guard.NotNull<AbstractPlayer>(player, "player");
			Player = player;
		}

		public bool TryGetDefinition(SkillType type, [NotNullWhen(true)] out SkillDefinition? definition)
		{
			return _definitions.TryGetValue(type, out definition);
		}

		public void UpdateTeamValue(SkillType type)
		{
			AbstractPlayer player = Player;
			ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
			if (val == null || !_definitions.TryGetValue(type, out SkillDefinition value))
			{
				return;
			}
			ulong num = 0uL;
			List<ServerPlayer> list = new List<ServerPlayer>();
			SkillManager skillManager = default(SkillManager);
			foreach (ServerPlayer player2 in val.Server.PlayerManager.Players)
			{
				if (!((AbstractPlayer)player2).TryGet<SkillManager>(ref skillManager))
				{
					if (player2 != val)
					{
						continue;
					}
					skillManager = this;
				}
				list.Add(player2);
				num += skillManager.GetRawMultiplier(type);
			}
			TeamValues[type] = Math.Min(num, (ulong)(value.MaxLevel * value.Multiplier));
			ServerNetworking.Send<TeamSkillS2C>((IEnumerable<ServerPlayer>)list, new TeamSkillS2C(type, num));
		}

		public void UpdateAllocations(bool updating)
		{
			int num = 0;
			foreach (KeyValuePair<SkillType, SkillDefinition> definition in _definitions)
			{
				definition.Deconstruct(out var key, out var value);
				SkillType skillType = key;
				SkillDefinition skillDefinition = value;
				int valueOrDefault = _previousAllocations.GetValueOrDefault(skillType, -1);
				int valueOrDefault2 = _allocations.GetValueOrDefault(skillType, 0);
				if (valueOrDefault != valueOrDefault2)
				{
					_previousAllocations[skillType] = valueOrDefault2;
					if (updating)
					{
						AbstractPlayer player = Player;
						ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
						if (val != null)
						{
							ServerNetworking.Send<SetSkillS2C>(val, new SetSkillS2C(skillType, valueOrDefault2));
							if (skillDefinition.IsTeamShared)
							{
								UpdateTeamValue(skillType);
							}
						}
						else
						{
							ClientNetworking.Send<AllocateSkillC2S>(new AllocateSkillC2S(skillType, valueOrDefault2));
						}
					}
				}
				num = ((!skillDefinition.IsNegative) ? (num + valueOrDefault2) : (num - valueOrDefault2));
			}
			if (Player.IsClient)
			{
				SkillMenu.Instance?.LoadAllSkillData();
			}
			Allocations = num;
		}

		public void SetAlloacted(SkillType type, int points)
		{
			Guard.MustBeGreaterThanOrEqualTo<int>(points, 0, "points");
			if (_definitions.TryGetValue(type, out SkillDefinition value))
			{
				points = Math.Min(points, value.MaxLevel);
				int valueOrDefault = _allocations.GetValueOrDefault(type, 0);
				if (value.IsNegative)
				{
					int val = valueOrDefault - UnusedSkillPoints;
					valueOrDefault = Math.Max(points, val);
				}
				else
				{
					int val2 = valueOrDefault + UnusedSkillPoints;
					valueOrDefault = Math.Min(points, val2);
				}
				_allocations[type] = valueOrDefault;
				UpdateAllocations(updating: true);
			}
		}

		public void AddExp(int experience)
		{
			AbstractPlayer player = Player;
			ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
			if (val != null)
			{
				Logger.Info($"{Player} +{experience} Exp");
				Exp += experience;
				ServerNetworking.Send<SetExpS2C>(val, new SetExpS2C(Exp));
			}
		}

		public void SetExp(int experience)
		{
			AbstractPlayer player = Player;
			ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
			if (val != null)
			{
				Logger.Info($"{Player} -> {experience} Exp");
				Exp = experience;
				ServerNetworking.Send<SetExpS2C>(val, new SetExpS2C(Exp));
			}
		}

		public int GetAllocated(SkillType type)
		{
			return _allocations.GetValueOrDefault(type, 0);
		}

		public static double GetTeamMultiplier(SkillType type)
		{
			return (double)TeamValues.GetValueOrDefault(type) / 10000.0;
		}

		public double GetMultiplier(SkillType type)
		{
			if (!_definitions.TryGetValue(type, out SkillDefinition value))
			{
				return 0.0;
			}
			if (value.IsTeamShared)
			{
				return (double)TeamValues.GetValueOrDefault(type) / 10000.0;
			}
			int valueOrDefault = _allocations.GetValueOrDefault(type, 0);
			return value.GetFinalMultiplier(valueOrDefault);
		}

		internal ulong GetRawMultiplier(SkillType type)
		{
			if (!_definitions.TryGetValue(type, out SkillDefinition value))
			{
				return 0uL;
			}
			int valueOrDefault = _allocations.GetValueOrDefault(type, 0);
			return value.GetRawMultiplier(valueOrDefault);
		}

		internal void SetDefinitions(IEnumerable<(SkillType type, int MaxLevel, int Multiplier)> definitions)
		{
			AbstractPlayer player = Player;
			ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
			if (val == null)
			{
				return;
			}
			_previousAllocations.Clear();
			_definitions.Clear();
			TeamValues.Clear();
			foreach (var (skillType, maxLevel, multiplier) in definitions)
			{
				_definitions.Add(skillType, new SkillDefinition(skillType, maxLevel, multiplier));
			}
			ServerNetworking.Send<DefineSkillsS2C>(val, new DefineSkillsS2C(Definitions));
			UpdateAllocations(updating: true);
		}

		public bool ShouldPersist(AbstractPlayer player)
		{
			return !player.IsClient;
		}

		public bool OnPlayerAttach(AbstractPlayer player)
		{
			if (Player != player || player is OtherClientPlayer)
			{
				return false;
			}
			if (player.IsClient)
			{
				SkillMenu.OnInitialize(this);
			}
			else
			{
				SetExp(Exp);
				foreach (var (key, value) in _loaded)
				{
					_allocations[key] = value;
				}
				Config.SetSkills(this);
			}
			return true;
		}

		public bool OnPlayerDetach(AbstractPlayer player, bool forced)
		{
			if (player.IsClient)
			{
				TeamValues.Clear();
				SkillMenu.OnDestroy();
			}
			else
			{
				ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null);
				if (val != null && !val.Server.IsStopping)
				{
					_allocations.Clear();
					foreach (SkillDefinition value in _definitions.Values)
					{
						UpdateTeamValue(value.Type);
					}
				}
			}
			return true;
		}

		public void OnPlayerSave(AbstractPlayer player, string path)
		{
			Guard.NotNullOrWhiteSpace(path, "path");
			Guard.IsFalse(player.IsClient, (string)null, "player.IsClient");
			string text = path + "/save.es3";
			ES3.Save<int>("exp", Exp, text);
			SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType));
			foreach (SkillType skillType in array)
			{
				if (_definitions.ContainsKey(skillType))
				{
					ES3.Save<int>($"skill.{skillType}", _allocations.GetValueOrDefault(skillType), text);
				}
				else
				{
					ES3.Save<int>($"skill.{skillType}", 0, text);
				}
			}
		}

		public void OnPlayerLoad(AbstractPlayer player, string path)
		{
			Guard.NotNullOrWhiteSpace(path, "path");
			Guard.IsFalse(player.IsClient, (string)null, "player.IsClient");
			string text = path + "/save.es3";
			if (ES3.FileExists(text))
			{
				Exp = ES3.Load<int>("exp", text, 0);
				SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType));
				foreach (SkillType skillType in array)
				{
					_loaded[skillType] = ES3.Load<int>($"skill.{skillType}", text, 0);
				}
			}
		}
	}
	public enum SkillType
	{
		MaxHealth,
		HealthRegen,
		Stamina,
		StaminaRegen,
		Strength,
		JumpHeight,
		SprintSpeed,
		SwimStamina,
		SwimSpeed,
		Oxygen,
		Battery,
		Slots,
		Exp,
		MonsterExp,
		SellExp,
		SellValue,
		ShipDoor,
		OvertimeBonus,
		Lockpick,
		Scrap,
		Neg
	}
	public static class SkillTypeExtensions
	{
		public static bool IsNegative(this SkillType type)
		{
			if (1 == 0)
			{
			}
			bool result = type == SkillType.Neg;
			if (1 == 0)
			{
			}
			return result;
		}

		public static bool IsTeamShared(this SkillType type)
		{
			if (1 == 0)
			{
			}
			bool result = (uint)(type - 14) <= 5u;
			if (1 == 0)
			{
			}
			return result;
		}

		public static string GetName(this SkillType type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				SkillType.MaxHealth => "Max Health", 
				SkillType.HealthRegen => "Health Regen", 
				SkillType.Stamina => "Stamina", 
				SkillType.StaminaRegen => "Stamina Regen", 
				SkillType.Strength => "Strength", 
				SkillType.JumpHeight => "Jump Strength", 
				SkillType.SprintSpeed => "Sprint Speed", 
				SkillType.SwimSpeed => "Swim Speed", 
				SkillType.SwimStamina => "Swim Stamina", 
				SkillType.Oxygen => "Oxygen", 
				SkillType.Battery => "Battery", 
				SkillType.Slots => "Utility Belt", 
				SkillType.Exp => "Exp Bonus", 
				SkillType.MonsterExp => "Monster Exp Bonus", 
				SkillType.SellExp => "Sell Base Exp", 
				SkillType.SellValue => "Sell Value", 
				SkillType.ShipDoor => "Ship Door Hydraulics", 
				SkillType.OvertimeBonus => "Overtime Bonus", 
				SkillType.Lockpick => "Lockpick Engineer", 
				SkillType.Scrap => "Scrap", 
				_ => (!type.IsNegative()) ? "Nothing there" : "Nothing There", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string GetShortName(this SkillType type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				SkillType.MaxHealth => "MHP", 
				SkillType.HealthRegen => "HPR", 
				SkillType.Stamina => "STA", 
				SkillType.StaminaRegen => "AGI", 
				SkillType.Strength => "STR", 
				SkillType.JumpHeight => "JMP", 
				SkillType.SprintSpeed => "SPD", 
				SkillType.SwimSpeed => "SWM", 
				SkillType.SwimStamina => "WSC", 
				SkillType.Oxygen => "OXY", 
				SkillType.Battery => "BAT", 
				SkillType.Slots => "BLT", 
				SkillType.Exp => "EXP", 
				SkillType.MonsterExp => "MXP", 
				SkillType.SellExp => "SXP", 
				SkillType.SellValue => "VAL", 
				SkillType.ShipDoor => "HYD", 
				SkillType.OvertimeBonus => "BON", 
				SkillType.Lockpick => "TKR", 
				SkillType.Scrap => "SCP", 
				_ => (!type.IsNegative()) ? "???" : "!?!", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string GetDescription(this SkillType type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				SkillType.MaxHealth => "The countless injuries you obtained from past expeditions steeled your body making you more durable.", 
				SkillType.HealthRegen => "Hours of exposure to the Apparatus mutated your blood cells to regenerate your health faster than before.", 
				SkillType.Stamina => "Hitting that Company Gym™ is finally paying out! Increasing your ability to jump and run more!", 
				SkillType.StaminaRegen => "The Company infused your blood with coffeine making you regen your Stamina faster than before!", 
				SkillType.Strength => "You infuse your blood with pure testosterone to make you carry heavy scrap with ease.", 
				SkillType.JumpHeight => "Releasing your inner bunny spirit animal makes you jump higher.", 
				SkillType.SprintSpeed => "The company empowers you with pure steroids, run, spaceman.", 
				SkillType.SwimSpeed => "Your training for the Mud Puddle swimming competition in the Backyard Olympics made you an excellent swimmer!", 
				SkillType.SwimStamina => "Installing flippers on the Suit makes it less exhausting moving through the water.", 
				SkillType.Oxygen => "The company installed basic, yet useful Oxygen tanks to your suit making you able to stay underwater for longer.", 
				SkillType.Battery => "Playing with the electrical outlet as a kid, has made you find a way to overcharge your batteries at the Charging Station.", 
				SkillType.Slots => "You figured out by combining useful materials on the ship to make a custom utility belt helping you to carry more scrap and items with you!", 
				SkillType.Exp => "Knowledge is Power! You try to learn as much and quickly as possible and thus accelerating your growth!", 
				SkillType.MonsterExp => "Violence is Power! Slay your enemies and get more experience by doing so. Also works on Co-workers!", 
				SkillType.SellExp => "Extensive studying on the Company's boss during sell time makes you all smarter! It could also just be the fear of getting eaten pumping a lot of Adrenaline into your brain...", 
				SkillType.SellValue => "You and your team learn how to trick the Company to give you more Credits than the scrap is worth.", 
				SkillType.ShipDoor => "You and your team's combined engineering on the ship's door increased the strength of the Hydraulics and now stays closed for longer.", 
				SkillType.OvertimeBonus => "By committing fraud you trick the company to give you more money after each completed Quota.", 
				SkillType.Lockpick => "By working on the company provided Lockpicker, you made it faster at locking doors and unlocking doors quicker!", 
				SkillType.Scrap => "The Company Issued scrap prospects to each employee to raise awareness of what is scrap and what is not! Increasing the amount of scrap per moon.", 
				_ => type.IsNegative() ? "This skill is missing a description but it sure does seem angry ònó" : ((!type.IsTeamShared()) ? "This skill is missing a description uwu" : "This skill is missing a description yet yuu still share it despite not knowing what it is uwu"), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string Format(this SkillType type, double multiplier)
		{
			return type.GetFormat().Format(multiplier);
		}

		public static string Format(this SkillFormat format, double multiplier)
		{
			if (1 == 0)
			{
			}
			string result = format switch
			{
				SkillFormat.Modifier => $"+{multiplier * 100.0:0.##}%", 
				SkillFormat.Mulitply => $"x{multiplier:0.##}", 
				SkillFormat.SubtractSeconds => $"-{multiplier * 100.0:0.##}s", 
				SkillFormat.Value => $"+{multiplier * 100.0:0.##}", 
				_ => multiplier.ToString(), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static SkillFormat GetFormat(this SkillType type)
		{
			if (1 == 0)
			{
			}
			SkillFormat result;
			switch (type)
			{
			case SkillType.Slots:
			case SkillType.Scrap:
				result = SkillFormat.Value;
				break;
			case SkillType.SellExp:
				result = SkillFormat.Mulitply;
				break;
			default:
				result = SkillFormat.Modifier;
				break;
			}
			if (1 == 0)
			{
			}
			return result;
		}

		public static int GetDefaultMaxLevel(this SkillType type)
		{
			if (1 == 0)
			{
			}
			int result = type switch
			{
				SkillType.HealthRegen => 100, 
				SkillType.StaminaRegen => 80, 
				SkillType.Strength => 80, 
				SkillType.JumpHeight => 100, 
				SkillType.SprintSpeed => 250, 
				SkillType.SwimSpeed => 200, 
				SkillType.SwimStamina => 50, 
				SkillType.Slots => 30, 
				SkillType.ShipDoor => 200, 
				SkillType.OvertimeBonus => 1000, 
				SkillType.Lockpick => 50, 
				SkillType.Neg => 99999, 
				_ => (!type.IsNegative()) ? 99999 : 100, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static int GetDefaultMultiplier(this SkillType type)
		{
			if (1 == 0)
			{
			}
			int result = type switch
			{
				SkillType.MaxHealth => 400, 
				SkillType.HealthRegen => 1, 
				SkillType.Stamina => 100, 
				SkillType.StaminaRegen => 100, 
				SkillType.Strength => 75, 
				SkillType.JumpHeight => 100, 
				SkillType.SprintSpeed => 80, 
				SkillType.SwimSpeed => 200, 
				SkillType.SwimStamina => 100, 
				SkillType.Oxygen => 50, 
				SkillType.Battery => 100, 
				SkillType.Slots => 10, 
				SkillType.Exp => 100, 
				SkillType.MonsterExp => 400, 
				SkillType.SellExp => 2000, 
				SkillType.SellValue => 20, 
				SkillType.ShipDoor => 100, 
				SkillType.OvertimeBonus => 20, 
				SkillType.Lockpick => 500, 
				SkillType.Scrap => 5, 
				_ => 100, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
}
namespace CookieProgression.Payloads
{
	public sealed class AllocateSkillC2S : NetworkPayload<AllocateSkillC2S>
	{
		private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>();

		public static NetworkPayloadType<AllocateSkillC2S> Type { get; } = new NetworkPayloadType<AllocateSkillC2S>("AllocateSkill", (NetworkSide)2);


		public override NetworkPayloadType<AllocateSkillC2S> PayloadType => Type;

		public SkillType SkillType { get; }

		public int Points { get; }

		private AllocateSkillC2S(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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = default(SkillType);
			((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums));
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			SkillType = skillType;
			Points = num;
		}

		public AllocateSkillC2S(SkillType type, int points)
		{
			SkillType = type;
			Points = points;
		}

		public override void Encode(FastBufferWriter writer)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = SkillType;
			((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums));
			int points = Points;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref points, default(ForPrimitives));
		}

		public override int GetEstimatedSize()
		{
			return StaticEncodingSize;
		}
	}
	public sealed class DefineSkillsS2C : NetworkPayload<DefineSkillsS2C>
	{
		public static NetworkPayloadType<DefineSkillsS2C> Type { get; } = new NetworkPayloadType<DefineSkillsS2C>("DefineSkills", (NetworkSide)1);


		public override NetworkPayloadType<DefineSkillsS2C> PayloadType => Type;

		public IReadOnlyList<SkillDefinition> Definitions { get; }

		private DefineSkillsS2C(FastBufferReader reader)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			List<SkillDefinition> list = new List<SkillDefinition>();
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			while (num-- > 0)
			{
				list.Add(SkillDefinition.Decode(reader));
			}
			Definitions = list.AsReadOnly();
		}

		public DefineSkillsS2C(IEnumerable<SkillDefinition> definitions)
		{
			Definitions = new List<SkillDefinition>(definitions).AsReadOnly();
		}

		public override void Encode(FastBufferWriter writer)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			int count = Definitions.Count;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives));
			foreach (SkillDefinition definition in Definitions)
			{
				definition.Encode(writer);
			}
		}

		public override int GetEstimatedSize()
		{
			return FastBufferWriter.GetWriteSize<int>() + SkillDefinition.EncodingSize * Definitions.Count;
		}
	}
	public sealed class SetExpS2C : NetworkPayload<SetExpS2C>
	{
		public static NetworkPayloadType<SetExpS2C> Type { get; } = new NetworkPayloadType<SetExpS2C>("SetExp", (NetworkSide)1);


		public override NetworkPayloadType<SetExpS2C> PayloadType => Type;

		public int Exp { get; }

		private SetExpS2C(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)
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			Exp = num;
		}

		public SetExpS2C(int exp)
		{
			Exp = exp;
		}

		public override void Encode(FastBufferWriter writer)
		{
			//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)
			int exp = Exp;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref exp, default(ForPrimitives));
		}

		public override int GetEstimatedSize()
		{
			return FastBufferWriter.GetWriteSize<int>();
		}
	}
	public sealed class SetSkillS2C : NetworkPayload<SetSkillS2C>
	{
		private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>();

		public static NetworkPayloadType<SetSkillS2C> Type { get; } = new NetworkPayloadType<SetSkillS2C>("SetSkill", (NetworkSide)1);


		public override NetworkPayloadType<SetSkillS2C> PayloadType => Type;

		public SkillType SkillType { get; }

		public int Points { get; }

		private SetSkillS2C(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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = default(SkillType);
			((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums));
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			SkillType = skillType;
			Points = num;
		}

		public SetSkillS2C(SkillType type, int points)
		{
			SkillType = type;
			Points = points;
		}

		public override void Encode(FastBufferWriter writer)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = SkillType;
			((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums));
			int points = Points;
			((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref points, default(ForPrimitives));
		}

		public override int GetEstimatedSize()
		{
			return StaticEncodingSize;
		}
	}
	public sealed class TeamSkillS2C : NetworkPayload<TeamSkillS2C>
	{
		private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<ulong>();

		public static NetworkPayloadType<TeamSkillS2C> Type { get; } = new NetworkPayloadType<TeamSkillS2C>("TeamSkill", (NetworkSide)1);


		public override NetworkPayloadType<TeamSkillS2C> PayloadType => Type;

		public SkillType SkillType { get; }

		public ulong Multiplier { get; }

		private TeamSkillS2C(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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = default(SkillType);
			((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums));
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			SkillType = skillType;
			Multiplier = num;
		}

		public TeamSkillS2C(SkillType type, ulong multiplier)
		{
			SkillType = type;
			Multiplier = multiplier;
		}

		public override void Encode(FastBufferWriter writer)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			SkillType skillType = SkillType;
			((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums));
			ulong multiplier = Multiplier;
			((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref multiplier, default(ForPrimitives));
		}

		public override int GetEstimatedSize()
		{
			return StaticEncodingSize;
		}
	}
	public sealed class UpdateConfigS2C : NetworkPayload<UpdateConfigS2C>
	{
		public static NetworkPayloadType<UpdateConfigS2C> Type { get; } = new NetworkPayloadType<UpdateConfigS2C>("UpdateConfig", (NetworkSide)1);


		public override NetworkPayloadType<UpdateConfigS2C> PayloadType => Type;

		public override void Encode(FastBufferWriter writer)
		{
			throw new NotImplementedException();
		}

		public override int GetEstimatedSize()
		{
			throw new NotImplementedException();
		}
	}
}
namespace CookieProgression.Patches
{
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class BatteryPatch
	{
		[HarmonyPatch(typeof(GrabbableObject), "SyncBatteryServerRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnBatteryCharge(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int>>>)(() => ((GrabbableObject)null).SyncBatteryClientRpc));
			MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<GrabbableObject, int>>>)(() => OnBatteryChargeRedirect));
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)replacement);
					found = true;
				}
				else
				{
					yield return instruction;
				}
			}
			if (!found)
			{
				Logger.Error("[Patch] Unable to patch item charge.");
			}
		}

		private static void OnBatteryChargeRedirect(GrabbableObject gObject, int charge)
		{
			int num = charge;
			try
			{
				if (!Networking.IsConnected || !Networking.Instance.IsServer)
				{
					return;
				}
				AbstractServer server = Networking.Instance.Server;
				PlayerControllerB playerHeldBy = gObject.playerHeldBy;
				ServerPlayer val = default(ServerPlayer);
				if (charge == 100 && playerHeldBy != null && server.PlayerManager.TryGetPlayer(playerHeldBy.actualClientId, ref val))
				{
					Logger.Info(string.Format("About to charge: {0} to {1} for {2}", gObject.itemProperties.itemName, charge, playerHeldBy.playerUsername ?? "<unknown>"));
					SkillManager skillManager = default(SkillManager);
					if (((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager))
					{
						double num2 = 1.0 + skillManager.GetMultiplier(SkillType.Battery);
						num = (int)((double)charge * num2);
						Logger.Info($"Charged {playerHeldBy.playerUsername}'s {gObject.itemProperties.itemName}'s battery to {num}% ({charge}x{num2})");
					}
				}
			}
			catch (Exception arg)
			{
				Logger.Error($"Exception while handling item charger.\n{arg}");
			}
			finally
			{
				gObject.SyncBatteryClientRpc(num);
			}
		}
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class ExpPatches
	{
		private static readonly List<GrabbableObject> CollectedScrap = new List<GrabbableObject>();

		private static readonly Dictionary<EnemyAI, (ulong, long)> Attackers = new Dictionary<EnemyAI, (ulong, long)>();

		private static readonly Dictionary<ulong, (ulong, long, int)> Violence = new Dictionary<ulong, (ulong, long, int)>();

		[HarmonyPatch(typeof(PlayerControllerB), "SetItemInElevator")]
		[HarmonyPrefix]
		private static void OnPlacedScrap(PlayerControllerB __instance, bool droppedInShipRoom, GrabbableObject gObject)
		{
			if (!Networking.IsConnected || !Networking.Instance.IsServer || !droppedInShipRoom || gObject.isInShipRoom == droppedInShipRoom || gObject.scrapPersistedThroughRounds)
			{
				return;
			}
			AbstractServer server = Networking.Instance.Server;
			if (gObject.itemProperties.isScrap && !CollectedScrap.Contains(gObject))
			{
				CollectedScrap.Add(gObject);
				ServerPlayer val = default(ServerPlayer);
				SkillManager skillManager = default(SkillManager);
				if (server.PlayerManager.TryGetPlayer(__instance.actualClientId, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager))
				{
					int scrapValue = gObject.scrapValue;
					double num = 1.0 + skillManager.GetMultiplier(SkillType.Exp);
					int num2 = (int)((double)scrapValue * num);
					skillManager.AddExp(num2);
					Logger.Info($"Awarded net:{((AbstractPlayer)val).NetworkId} {num2} exp ({scrapValue}x{num:f2}) from collecting scrap {gObject.itemProperties.itemName}.");
				}
				else
				{
					Logger.Error($"Lost {gObject.scrapValue} credits worth of exp for net:{__instance.actualClientId}");
				}
			}
		}

		[HarmonyPatch(typeof(EnemyAI), "HitEnemy")]
		[HarmonyPostfix]
		private static void OnHitEnemy(EnemyAI __instance, PlayerControllerB? playerWhoHit)
		{
			if (Networking.IsConnected && Networking.Instance.IsServer && playerWhoHit != null)
			{
				Attackers[__instance] = (playerWhoHit.actualClientId, Stopwatch.GetTimestamp());
			}
		}

		[HarmonyPatch(typeof(EnemyAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void OnEnemyDeath(EnemyAI __instance)
		{
			//IL_0195: 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)
			if (!Networking.IsConnected || !Networking.Instance.IsServer)
			{
				return;
			}
			(Config.EnemyExpType, int Range, int BaseExp) enemyExp = Config.GetEnemyExp(((object)__instance).GetType());
			Config.EnemyExpType item = enemyExp.Item1;
			int item2 = enemyExp.Range;
			int item3 = enemyExp.BaseExp;
			string enemyFriendlyName = Config.GetEnemyFriendlyName(((object)__instance).GetType());
			Logger.Info($"[{enemyFriendlyName}] Mode: {item}, Range: {item2}, Exp: {item3}");
			if (item == Config.EnemyExpType.Disabled || item3 < 1)
			{
				Logger.Info("[" + enemyFriendlyName + "] cannot award exp.");
			}
			ulong num = ulong.MaxValue;
			if (Attackers.TryGetValue(__instance, out var value))
			{
				(ulong, long) tuple = value;
				ulong item4 = tuple.Item1;
				long item5 = tuple.Item2;
				TimeSpan timeSpan = TimeSpan.FromSeconds((double)(Stopwatch.GetTimestamp() - item5) / (double)Stopwatch.Frequency);
				if (timeSpan <= TimeSpan.FromSeconds(10.0))
				{
					num = item4;
				}
			}
			else if (item == Config.EnemyExpType.Attacker)
			{
				Logger.Info($"[{enemyFriendlyName}] died without an attacker, lost {item3} exp.");
				return;
			}
			AbstractServer server = Networking.Instance.Server;
			PlayerControllerB val = default(PlayerControllerB);
			SkillManager skillManager = default(SkillManager);
			foreach (ServerPlayer player in server.PlayerManager.Players)
			{
				if (!PlayerUtils.TryGetPlayerScript(((AbstractPlayer)player).NetworkId, ref val) || val.isPlayerDead)
				{
					continue;
				}
				bool flag = item == Config.EnemyExpType.AoE && Vector3.Distance(((Component)__instance).transform.position, ((Component)val).transform.position) <= (float)item2;
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager) && (((AbstractPlayer)player).NetworkId == num || flag))
				{
					int num2 = item3;
					double num3 = (1.0 + skillManager.GetMultiplier(SkillType.Exp)) * (1.0 + skillManager.GetMultiplier(SkillType.MonsterExp));
					int num4 = (int)((double)num2 * num3);
					skillManager.AddExp(num4);
					if (((AbstractPlayer)player).NetworkId == num)
					{
						Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num4} exp ({num2}x{num3:f2}) from killing a {enemyFriendlyName}.");
					}
					else
					{
						Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num4} exp ({num2}x{num3:f2}) from a {enemyFriendlyName} dying within 10 units.");
					}
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientServerRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnPlayerHit(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, Vector3, int, int>>>)(() => ((PlayerControllerB)null).DamagePlayerFromOtherClientClientRpc));
			MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<PlayerControllerB, int, Vector3, int, int>>>)(() => OnPlayerHitRedirect));
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)replacement);
					Logger.Info(string.Format("[Patch] Redirected call {0} -> {1} in {2}", original, replacement, "DamagePlayerFromOtherClientServerRpc"));
					found = true;
				}
				else
				{
					yield return instruction;
				}
			}
			if (!found)
			{
				Logger.Error("[Patch] Unable to patch player on player violence.");
			}
		}

		private static void OnPlayerHitRedirect(PlayerControllerB script, int damageAmount, Vector3 hitDirection, int playerWhoHit, int newHealthAmount)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			script.DamagePlayerFromOtherClientClientRpc(damageAmount, hitDirection, playerWhoHit, newHealthAmount);
			try
			{
				PlayerControllerB val = default(PlayerControllerB);
				if (PlayerUtils.TryGetPlayerScript(playerWhoHit, ref val))
				{
					Violence[script.actualClientId] = (val.actualClientId, Stopwatch.GetTimestamp(), damageAmount);
					Logger.Info($"{val.playerUsername} hit {script.playerUsername} for {damageAmount} damage.");
				}
			}
			catch (Exception arg)
			{
				Logger.Error($"Exception while handling player on player violence.\n{arg}");
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "KillPlayerServerRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnPlayerDeath(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, bool, Vector3, int, int, Vector3>>>)(() => ((PlayerControllerB)null).KillPlayerClientRpc));
			MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<PlayerControllerB, int, bool, Vector3, int, int, Vector3>>>)(() => OnPlayerDeathRedirect));
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)replacement);
					Logger.Info(string.Format("[Patch] Redirected call {0} -> {1} in {2}", original, replacement, "KillPlayerServerRpc"));
					found = true;
				}
				else
				{
					yield return instruction;
				}
			}
			if (!found)
			{
				Logger.Error("[Patch] Unable to patch player death.");
			}
		}

		private static void OnPlayerDeathRedirect(PlayerControllerB script, int playerId, bool spawnBody, Vector3 bodyVelocity, int causeOfDeath, int deathAnimation, Vector3 positionOffset)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			script.KillPlayerClientRpc(playerId, spawnBody, bodyVelocity, causeOfDeath, deathAnimation, positionOffset);
			try
			{
				MetaPatches.OnPlayerDeath(script);
			}
			catch (Exception arg)
			{
				Logger.Error($"Exception while handling meta player death.\n{arg}");
			}
			try
			{
				if (!Networking.IsConnected || !Networking.Instance.IsServer || !Violence.TryGetValue(script.actualClientId, out var value))
				{
					return;
				}
				(ulong, long, int) tuple = value;
				ulong item = tuple.Item1;
				long item2 = tuple.Item2;
				int item3 = tuple.Item3;
				TimeSpan timeSpan = TimeSpan.FromSeconds((double)(Stopwatch.GetTimestamp() - item2) / (double)Stopwatch.Frequency);
				if (!(timeSpan > TimeSpan.FromTicks(1000000L * (long)Math.Max(item3, 5))))
				{
					AbstractServer server = Networking.Instance.Server;
					ServerPlayer val = default(ServerPlayer);
					SkillManager skillManager = default(SkillManager);
					if (server.PlayerManager.TryGetPlayer(item, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager))
					{
						int num = 5;
						double num2 = (1.0 + skillManager.GetMultiplier(SkillType.Exp)) * (1.0 + skillManager.GetMultiplier(SkillType.MonsterExp));
						int num3 = (int)((double)num * num2);
						skillManager.AddExp(num3);
						Logger.Info($"Awarded net:{((AbstractPlayer)val).NetworkId} {num3} ({num}x{num2:f2}) exp for killing their friend {script.playerUsername} (net:{script.actualClientId}) ohno");
					}
				}
			}
			catch (Exception arg2)
			{
				Logger.Error($"Exception while handling player death.\n{arg2}");
			}
		}

		[HarmonyPatch(typeof(DepositItemsDesk), "SellItemsOnServer")]
		[HarmonyPriority(300)]
		[HarmonyPrefix]
		private static void OnSellExp(DepositItemsDesk __instance)
		{
			if (!((NetworkBehaviour)__instance).IsServer)
			{
				return;
			}
			int num = 0;
			foreach (GrabbableObject item in __instance.itemsOnCounter)
			{
				if (item.itemProperties.isScrap)
				{
					num++;
				}
			}
			OnScrapSold(num);
		}

		private static void OnScrapSold(int scrapSold)
		{
			try
			{
				if (!Networking.IsConnected || !Networking.Instance.IsServer)
				{
					return;
				}
				AbstractServer server = Networking.Instance.Server;
				if (scrapSold == 0)
				{
					Logger.Warning("Patch incompatability: scrap sold was 0 - unless you really did only sell 0 scrap.");
					return;
				}
				SkillManager skillManager = default(SkillManager);
				foreach (ServerPlayer player in server.PlayerManager.Players)
				{
					if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager))
					{
						double num = (double)scrapSold * skillManager.GetMultiplier(SkillType.SellExp);
						double num2 = 1.0 + skillManager.GetMultiplier(SkillType.Exp);
						int num3 = (int)(num * num2);
						skillManager.AddExp(num3);
						Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num3} exp ({num:0.#}x{num2:f2}) from selling {scrapSold} scrap.");
					}
				}
			}
			catch (Exception arg)
			{
				Logger.Error($"Exception while handling player exp distribution.\n{arg}");
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
		[HarmonyPostfix]
		private static IEnumerator OnRoundReset(IEnumerator result)
		{
			CollectedScrap.Clear();
			Attackers.Clear();
			Violence.Clear();
			while (result.MoveNext())
			{
				yield return result.Current;
			}
		}
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class MenuPatches
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__21_0;

			internal void <MakeSkillMenuButton>b__21_0()
			{
				SkillMenu.Instance?.OpenSkillMenu();
			}
		}

		private static GameObject? _skillMenuButton;

		private static GameObject? _xpBar;

		private static GameObject? _xpInfoContainer;

		private static GameObject? _xpBarProgress;

		private static TextMeshProUGUI? _xpText;

		private static TextMeshProUGUI? _xpLevel;

		private static TextMeshProUGUI? _profit;

		private static GameObject? _popupBar;

		private static TextMeshProUGUI? _popupText;

		private static GameObject? _levelText;

		private static bool _popupTimer;

		private static bool _popupLevelTimer;

		internal static void Destroy()
		{
			_skillMenuButton = null;
			_xpBar = null;
			_xpInfoContainer = null;
			_xpBarProgress = null;
			_xpText = null;
			_xpLevel = null;
			_profit = null;
			_popupBar = null;
			_popupText = null;
			_levelText = null;
			_popupTimer = false;
			_popupLevelTimer = false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")]
		private static void OnOpenMenu(QuickMenuManager __instance)
		{
			if (__instance.isMenuOpen)
			{
				if (!Object.op_Implicit((Object)(object)_xpInfoContainer) || !Object.op_Implicit((Object)(object)_xpBar) || !Object.op_Implicit((Object)(object)_xpBarProgress))
				{
					MakeNewXPBar();
				}
				if (!Object.op_Implicit((Object)(object)_skillMenuButton))
				{
					MakeSkillMenuButton();
				}
				_xpBar.SetActive(true);
				_xpBarProgress.SetActive(true);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(QuickMenuManager), "Update")]
		private static void OnUpdate(QuickMenuManager __instance)
		{
			if (Object.op_Implicit((Object)(object)_xpInfoContainer) && Object.op_Implicit((Object)(object)_xpBar) && Object.op_Implicit((Object)(object)_xpBarProgress) && SkillMenu.Instance != null)
			{
				SkillManager manager = SkillMenu.Instance.Manager;
				bool activeSelf = __instance.mainButtonsPanel.activeSelf;
				_xpInfoContainer.SetActive(activeSelf);
				if (manager.HasMoreLevels)
				{
					((TMP_Text)_xpText).SetText($"{manager.UnusedExp} / {manager.NeededExp}", true);
					_xpBarProgress.GetComponent<Image>().fillAmount = (float)manager.UnusedExp / (float)manager.NeededExp;
				}
				else
				{
					((TMP_Text)_xpText).SetText("MAX", true);
					_xpBarProgress.GetComponent<Image>().fillAmount = 1f;
				}
				((TMP_Text)_xpLevel).SetText($"Level: {manager.Level}", true);
				((TMP_Text)_profit).SetText($"You've made.. {Random.Range(1000, 10000)}$", true);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HUDManager), "PingScan_performed")]
		private static void TestScan()
		{
			if (!Networking.IsConnected)
			{
				return;
			}
			Networking instance = Networking.Instance;
			if (!instance.IsServer)
			{
				return;
			}
			AbstractServer server = instance.Server;
			SkillManager skillManager = default(SkillManager);
			foreach (ServerPlayer player in server.Players)
			{
				if (!((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager))
				{
				}
			}
		}

		public static void ShowXpPopup()
		{
			if (SkillMenu.Instance != null)
			{
				if (!Object.op_Implicit((Object)(object)_popupBar))
				{
					MakePopupBar();
				}
				SkillManager manager = SkillMenu.Instance.Manager;
				GameObject val = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPBarProgress");
				if (manager.HasMoreLevels)
				{
					((TMP_Text)_popupText).SetText($"{manager.UnusedExp} / {manager.NeededExp}", true);
					val.GetComponent<Image>().fillAmount = (float)manager.UnusedExp / (float)manager.NeededExp;
				}
				else
				{
					((TMP_Text)_popupText).SetText("MAX", true);
					val.GetComponent<Image>().fillAmount = 1f;
				}
				_popupTimer = true;
				if (!_popupBar.activeSelf)
				{
					((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(OnXpPopup());
				}
			}
		}

		public static void ShowLevelPopup()
		{
			if (!Object.op_Implicit((Object)(object)_levelText))
			{
				MakeLevelUp();
			}
			_popupLevelTimer = true;
			if (!_levelText.gameObject.activeSelf)
			{
				((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(OnLevelPopup());
			}
		}

		private static IEnumerator OnXpPopup()
		{
			_popupBar.SetActive(true);
			while (_popupTimer)
			{
				_popupTimer = false;
				yield return (object)new WaitForSeconds(2f);
			}
			GameObject? popupBar = _popupBar;
			if (popupBar != null)
			{
				popupBar.SetActive(false);
			}
		}

		private static IEnumerator OnLevelPopup()
		{
			_levelText.gameObject.SetActive(true);
			while (_popupLevelTimer)
			{
				_popupLevelTimer = false;
				yield return (object)new WaitForSeconds(5f);
			}
			GameObject? levelText = _levelText;
			if (levelText != null)
			{
				levelText.gameObject.SetActive(false);
			}
		}

		public static void MakeNewXPBar()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("/Systems/UI/Canvas/QuickMenu");
			GameObject val2 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total");
			if (!Object.op_Implicit((Object)(object)_xpInfoContainer))
			{
				_xpInfoContainer = new GameObject("XpInfoContainer");
				_xpInfoContainer.transform.SetParent(val.transform, false);
				_xpInfoContainer.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
				_xpInfoContainer.transform.Translate(-1.7f, 0.9f, 0f);
			}
			if (!Object.op_Implicit((Object)(object)_xpBar))
			{
				GameObject val3 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpBox");
				_xpBar = Object.Instantiate<GameObject>(val3);
				_xpBar.transform.SetParent(_xpInfoContainer.transform, false);
				((Object)_xpBar).name = "XPBar";
				_xpText = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>();
				((TMP_Text)_xpText).transform.SetParent(_xpBar.transform, false);
				((TMP_Text)_xpText).transform.Translate(-0.75f, 0.21f, 0f);
				((Object)_xpText).name = "XPText";
				((TMP_Text)_xpText).alignment = (TextAlignmentOptions)514;
				((TMP_Text)_xpText).SetText("0/40", true);
				((Graphic)_xpText).color = new Color(1f, 0.6f, 0f, 1f);
				_xpLevel = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>();
				((TMP_Text)_xpLevel).transform.SetParent(_xpInfoContainer.transform, false);
				((TMP_Text)_xpLevel).transform.position = new Vector3(_xpBar.transform.position.x, _xpBar.transform.position.y, _xpBar.transform.position.z);
				((TMP_Text)_xpLevel).transform.Translate(-0.3f, 0.2f, 0f);
				((Object)_xpLevel).name = "XPLevel";
				((TMP_Text)_xpLevel).alignment = (TextAlignmentOptions)514;
				((TMP_Text)_xpLevel).SetText("Level: 0", true);
				((Graphic)_xpLevel).color = new Color(1f, 0.6f, 0f, 1f);
				_profit = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>();
				((TMP_Text)_profit).transform.SetParent(_xpInfoContainer.transform, false);
				((TMP_Text)_profit).transform.position = new Vector3(_xpBar.transform.position.x, _xpBar.transform.position.y, _xpBar.transform.position.z);
				((TMP_Text)_profit).transform.Translate(-0.1f, -0.2f, 0f);
				((Object)_profit).name = "XPProfit";
				((TMP_Text)_profit).alignment = (TextAlignmentOptions)514;
				((TMP_Text)_profit).SetText("You've made.. 0$.", true);
				((Graphic)_profit).color = new Color(1f, 0.6f, 0f, 1f);
			}
			if (!Object.op_Implicit((Object)(object)_xpBarProgress))
			{
				GameObject val4 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpMeter");
				_xpBarProgress = Object.Instantiate<GameObject>(val4);
				_xpBarProgress.transform.SetParent(_xpBar.transform, false);
				_xpBarProgress.transform.SetAsFirstSibling();
				_xpBarProgress.transform.localScale = new Vector3(0.597f, 5.21f, 1f);
				_xpBarProgress.transform.Translate(-0.8f, 0.2f, 0f);
				_xpBarProgress.transform.localPosition = new Vector3(0f, 0f, 0f);
				((Object)_xpBarProgress).name = "XPBarProgress";
				_xpBarProgress.GetComponent<Image>().fillAmount = 0f;
			}
		}

		private static void MakeSkillMenuButton()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_013e: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons/Resume");
			_skillMenuButton = Object.Instantiate<GameObject>(val);
			GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons");
			_skillMenuButton.transform.SetParent(val2.transform, false);
			_skillMenuButton.transform.position = new Vector3(0.55f + _xpBar.transform.position.x, 1.09f + _xpBar.transform.position.y, _xpBar.transform.position.z);
			((Object)_skillMenuButton).name = "Skills";
			((TMP_Text)_skillMenuButton.GetComponentInChildren<TextMeshProUGUI>()).SetText("> Skills", true);
			Transform transform = ((TMP_Text)_xpText).transform;
			_skillMenuButton.transform.localPosition = new Vector3(transform.position.x, transform.position.y, transform.position.z);
			Transform transform2 = _skillMenuButton.transform;
			transform2.position += new Vector3(-0.15f, 1.056f);
			Button component = _skillMenuButton.GetComponent<Button>();
			ButtonClickedEvent val3 = new ButtonClickedEvent();
			ButtonClickedEvent val4 = val3;
			component.onClick = val3;
			ButtonClickedEvent val5 = val4;
			object obj = <>c.<>9__21_0;
			if (obj == null)
			{
				UnityAction val6 = delegate
				{
					SkillMenu.Instance?.OpenSkillMenu();
				};
				<>c.<>9__21_0 = val6;
				obj = (object)val6;
			}
			((UnityEvent)val5).AddListener((UnityAction)obj);
			Button component2 = _xpBar.GetComponent<Button>();
			if (component2 == null)
			{
				_xpBar.AddComponent<Button>().onClick = val5;
			}
			component2 = _xpBarProgress.GetComponent<Button>();
			if (component2 == null)
			{
				_xpBarProgress.AddComponent<Button>().onClick = val5;
			}
		}

		private static void MakePopupBar()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			MakeNewXPBar();
			GameObject val = GameObject.Find("/Systems/UI/Canvas/QuickMenu/XpInfoContainer/XPBar");
			_popupBar = Object.Instantiate<GameObject>(val);
			((Object)_popupBar).name = "XPUpdate";
			_popupText = _popupBar.GetComponentInChildren<TextMeshProUGUI>();
			GameObject val2 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle");
			_popupBar.transform.SetParent(val2.transform, false);
			_popupBar.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
			GameObject val3 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPLevel");
			Object.Destroy((Object)(object)val3);
			GameObject val4 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPProfit");
			Object.Destroy((Object)(object)val4);
			_popupBar.transform.Translate(3.1f, -2.1f, 0f);
			Vector3 localPosition = _popupBar.transform.localPosition;
			_popupBar.transform.localPosition = new Vector3(localPosition.x, localPosition.y + 5f, localPosition.z);
			_popupBar.SetActive(false);
		}

		public static void MakeLevelUp()
		{
			_levelText = Object.Instantiate<GameObject>(Plugin.MenuBundle.LoadAsset<GameObject>("LevelUp"));
			((TMP_Text)((Component)_levelText.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "Level Up! Spend your skill points.";
			_levelText.gameObject.SetActive(false);
		}
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class MetaPatches
	{
		[HarmonyPatch(typeof(StartOfRound), "FirePlayersAfterDeadlineClientRpc")]
		[HarmonyPostfix]
		private static void OnPlayerFired()
		{
			if (!Networking.IsConnected || !Networking.Instance.IsServer)
			{
				return;
			}
			AbstractServer server = Networking.Instance.Server;
			SkillManager skillManager = default(SkillManager);
			foreach (ServerPlayer player in server.Players)
			{
				if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager))
				{
					skillManager.SetExp(skillManager.UsedExp);
				}
			}
		}

		internal static void OnPlayerDeath(PlayerControllerB script)
		{
			if (Networking.IsConnected && Networking.Instance.IsServer)
			{
				AbstractServer server = Networking.Instance.Server;
				ServerPlayer val = default(ServerPlayer);
				SkillManager skillManager = default(SkillManager);
				if (server.PlayerManager.TryGetPlayer(script.actualClientId, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager))
				{
					skillManager.SetExp(skillManager.UsedExp);
				}
			}
		}
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	internal static class ScrapPatch
	{
		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnSpawnScrapInLevel(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo currentLevel = AccessTools.DeclaredField(typeof(RoundManager), "currentLevel");
			FieldInfo minScrap = AccessTools.DeclaredField(typeof(SelectableLevel), "minScrap");
			FieldInfo maxScrap = AccessTools.DeclaredField(typeof(SelectableLevel), "maxScrap");
			MethodInfo getMul = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Func<SkillType, double>>>)(() => SkillManager.GetTeamMultiplier));
			int step = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				yield return instruction;
				if (CodeInstructionExte