Decompiled source of NotControlCompany v1.0.0

ControlCompany.dll

Decompiled 8 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ControlCompany.Core;
using ControlCompany.Core.Config;
using ControlCompany.Core.Enemy;
using ControlCompany.Core.Extentions;
using ControlCompany.Core.Input;
using ControlCompany.Core.UI;
using ControlCompany.Patches;
using Dissonance;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ControlCompany")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ControlCompany")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("dfed064e-ab44-4aa7-b361-7a59370d39a8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ControlCompany
{
	[BepInPlugin("ControlCompany.ControlCompany", "ControlCompany", "1.0.6")]
	public class ControlCompanyPlugin : BaseUnityPlugin
	{
		private const string modGUID = "ControlCompany.ControlCompany";

		private const string modName = "ControlCompany";

		private const string modVersion = "1.0.6";

		private readonly Harmony harmony = new Harmony("ControlCompany.ControlCompany");

		public static ControlCompanyPlugin Instance;

		internal ManualLogSource logger;

		private bool isInitialized;

		private bool ranInitializationScripts;

		private void Awake()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			logger = Logger.CreateLogSource("ControlCompany.ControlCompany");
			logger.LogInfo((object)"Loaded ControlCompany. Patching.");
			ApplyPatches();
			logger.LogInfo((object)"Completed patching. Initializing control center.");
			GameObject val = new GameObject("control_company_control_center");
			val.AddComponent<ControlCenter>();
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<UIManager>();
			val.AddComponent<ConfigManager>().Initialize(((BaseUnityPlugin)this).Config);
			Object.DontDestroyOnLoad((Object)val);
			logger.LogInfo((object)"Completed initialization.");
			isInitialized = true;
		}

		private void ApplyPatches()
		{
			harmony.PatchAll(typeof(ControlCompanyPlugin));
			harmony.PatchAll(typeof(HUDManagerPatch));
			harmony.PatchAll(typeof(StartOfRoundPatch));
			harmony.PatchAll(typeof(PlayerControllerBPatch));
			harmony.PatchAll(typeof(EnemyAIPatch));
			harmony.PatchAll(typeof(TimeOfDayPatch));
		}
	}
}
namespace ControlCompany.Patches
{
	[HarmonyPatch(typeof(EnemyAI))]
	internal class EnemyAIPatch
	{
		[HarmonyPatch("ChangeOwnershipOfEnemy")]
		[HarmonyPrefix]
		private static bool ChangeOwnershipOfEnemyPrefix(EnemyAI __instance, ref ulong newOwnerClientId)
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				if (ControlCenter.Instance.CurrentMode == ControlCenter.Mode.ENEMY)
				{
					if (ControlCenter.Instance.GetHostPlayer().actualClientId != newOwnerClientId && !ControlCenter.Instance.CurrentControlledEnemy.IsAIControlled)
					{
						return (Object)(object)ControlCenter.Instance.CurrentControlledEnemy.EnemyAI != (Object)(object)__instance;
					}
					return true;
				}
				return true;
			}
			return true;
		}

		[HarmonyPatch("ChangeEnemyOwnerServerRpc")]
		[HarmonyPrefix]
		private static bool ChangeEnemyOwnerServerRpcPrefix(EnemyAI __instance, ref ulong clientId)
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				if (ControlCenter.Instance.CurrentMode == ControlCenter.Mode.ENEMY)
				{
					if (ControlCenter.Instance.GetHostPlayer().actualClientId != clientId && !ControlCenter.Instance.CurrentControlledEnemy.IsAIControlled)
					{
						return (Object)(object)ControlCenter.Instance.CurrentControlledEnemy.EnemyAI != (Object)(object)__instance;
					}
					return true;
				}
				return true;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	internal class HUDManagerPatch
	{
		[HarmonyPatch("CanPlayerScan")]
		[HarmonyPostfix]
		private static void CanPlayerScanPostfix(ref bool __result)
		{
			if (__result && (Object)(object)ControlCenter.Instance != (Object)null)
			{
				__result = ControlCenter.Instance.CurrentMode == ControlCenter.Mode.HOST;
			}
		}

		[HarmonyPatch("UpdateHealthUI")]
		[HarmonyPrefix]
		private static bool UpdateHealthUIPrefix()
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				return ControlCenter.Instance.CurrentMode == ControlCenter.Mode.HOST;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch
	{
		[HarmonyPatch("PlayerLookInput")]
		[HarmonyPrefix]
		private static bool PlayerLookInputPrefix()
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				return ControlCenter.Instance.CurrentMode == ControlCenter.Mode.HOST;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal class StartOfRoundPatch
	{
		[HarmonyPatch("ShipHasLeft")]
		[HarmonyPrefix]
		private static void ShipHasLeftPrefix()
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				ControlCenter.Instance.EndOfRoundCleanUp();
			}
		}

		[HarmonyPatch("StartGame")]
		[HarmonyPostfix]
		private static void StartGamePostfix()
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				ControlCenter.Instance.StartOfRoundInitialization();
			}
		}
	}
	[HarmonyPatch(typeof(TimeOfDay))]
	internal class TimeOfDayPatch
	{
		[HarmonyPatch("VoteShipToLeaveEarly")]
		[HarmonyPrefix]
		private static bool VoteToLeaveEarly()
		{
			if ((Object)(object)ControlCenter.Instance != (Object)null)
			{
				return ControlCenter.Instance.CurrentMode == ControlCenter.Mode.HOST;
			}
			return true;
		}
	}
}
namespace ControlCompany.Core
{
	internal static class Constants
	{
		public static Dictionary<int, string> ALL_LAYERS_DICT = (from index in Enumerable.Range(0, 32)
			where !string.IsNullOrEmpty(LayerMask.LayerToName(index))
			select index).ToDictionary((int index) => index, (int index) => LayerMask.LayerToName(index));

		public static LayerMask PLAYER_LOS_LAYER = LayerMask.op_Implicit(262144);

		public static LayerMask PLAYER_LAYER = LayerMask.op_Implicit(8);

		public static LayerMask ITERACTABLE_OBJ_LAYER = LayerMask.op_Implicit(512);

		public static LayerMask PROPS_LAYER = LayerMask.op_Implicit(64);

		public static LayerMask ENEMIES_LAYER = LayerMask.op_Implicit(524288);

		public static LayerMask PLAYER_RAGDOLL_LAYER = LayerMask.op_Implicit(1048576);
	}
	internal class ControlCenter : MonoBehaviour
	{
		public enum Mode
		{
			HOST,
			GHOST,
			ENEMY
		}

		public static ControlCenter Instance;

		private GameObject ghost;

		private EnemyController currentControlledEnemy;

		private int currentTargetIndex;

		private PlayerControllerB currentTarget;

		private Mode currentMode;

		private bool allowAllEnemies;

		private bool initialMicPushToTalkSetting;

		private bool hostDeadOnThisFrame;

		private bool isExtendedModeEnabled;

		private bool scrapSpawnMode;

		private int scrapSpawnPage;

		private int scrapSpawnPageSize = 10;

		private bool loadedConfig;

		private bool showUI = true;

		private float gameStartedTime;

		public Mode CurrentMode => currentMode;

		public EnemyController CurrentControlledEnemy => currentControlledEnemy;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
		}

		private void Update()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			if (!IsGameStarted())
			{
				return;
			}
			if (!loadedConfig)
			{
				loadedConfig = true;
				ConfigManager.Instance.LoadPlayerKeybinds();
			}
			if (((ButtonControl)InputKeys.TOGGLE_UI_KEY).wasPressedThisFrame)
			{
				showUI = !showUI;
			}
			gameStartedTime += Time.deltaTime;
			if (IsHost())
			{
				if (((Object)(object)currentTarget == (Object)null || !currentTarget.isPlayerControlled || currentTarget.isPlayerDead) && GetAlivePlayers().Count > 0)
				{
					SetNextTargetPlayer(1);
				}
				if ((Object)(object)ghost == (Object)null)
				{
					GameObject val = new GameObject("ghost");
					val.AddComponent<CustomPlayerController>().Initialize(GetHostPlayer().playerActions, CustomPlayerController.CameraMode.FIRST_PERSON);
					ghost = val;
					ghost.SetActive(false);
				}
				if (!hostDeadOnThisFrame && IsHostDead())
				{
					hostDeadOnThisFrame = true;
				}
				if (currentMode != 0)
				{
					GetHostPlayer().isTypingChat = true;
				}
				InputUpdate();
			}
		}

		private void InputUpdate()
		{
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			if (!IsGameStarted() || !IsHost())
			{
				return;
			}
			if (((ButtonControl)InputKeys.EXTENDED_MODE_KEY).wasPressedThisFrame)
			{
				isExtendedModeEnabled = !isExtendedModeEnabled;
				allowAllEnemies = isExtendedModeEnabled;
			}
			switch (currentMode)
			{
			case Mode.ENEMY:
				if (!currentControlledEnemy.IsAIControlled && !currentControlledEnemy.EnemyAI.isEnemyDead)
				{
					if (InputKeys.ENEMY_PRIMARY_SKILL_BUTTON.wasPressedThisFrame)
					{
						currentControlledEnemy.UsePrimarySkill();
					}
					else if (InputKeys.ENEMY_PRIMARY_SKILL_BUTTON.wasReleasedThisFrame)
					{
						currentControlledEnemy.ReleasePrimarySkill();
					}
					else if (InputKeys.ENEMY_SECONDARY_SKILL_BUTTON.wasPressedThisFrame)
					{
						currentControlledEnemy.UseSecondarySkill();
					}
					else if (InputKeys.ENEMY_SECONDARY_SKILL_BUTTON.wasReleasedThisFrame)
					{
						currentControlledEnemy.ReleaseSecondarySkill();
					}
					currentControlledEnemy.SetLockEnemyRotation(((ButtonControl)InputKeys.LOCK_ENEMY_ROTATION_KEY).isPressed);
				}
				if (((ButtonControl)InputKeys.EXIT_KEY).wasPressedThisFrame)
				{
					EnableGhost(enable: true, ((Component)currentControlledEnemy).transform.position);
					bool enable = IsTargetInside();
					ghost.GetComponentInChildren<CustomPlayerController>().EnableLight(enable);
					currentControlledEnemy.DestroyAndCleanUp();
					currentMode = Mode.GHOST;
				}
				else if (((ButtonControl)InputKeys.ENEMY_TOGGLE_AI_KEY).wasPressedThisFrame)
				{
					currentControlledEnemy.ToggleAIControl();
				}
				break;
			case Mode.HOST:
				if (((ButtonControl)InputKeys.HOST_GHOST_MODE_KEY).wasPressedThisFrame)
				{
					EnableGhost(enable: true, ((Component)currentTarget).gameObject.transform.position);
					bool enable2 = IsTargetInside();
					ghost.GetComponentInChildren<CustomPlayerController>().EnableLight(enable2);
					EnableHostPlayer(enable: false);
					currentMode = Mode.GHOST;
				}
				else if (((ButtonControl)InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_LEFT).wasPressedThisFrame)
				{
					SetNextTargetPlayer(-1);
				}
				else if (((ButtonControl)InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_RIGHT).wasPressedThisFrame)
				{
					SetNextTargetPlayer(1);
				}
				if (isExtendedModeEnabled)
				{
					if (((ButtonControl)InputKeys.HOST_TELEPORT_TO_ENTRANCE_KEY).wasPressedThisFrame)
					{
						((Component)GetHostPlayer()).gameObject.transform.position = RoundManager.FindMainEntrancePosition(true, false);
						GetHostPlayer().isInsideFactory = true;
					}
					else if (((ButtonControl)InputKeys.HOST_GIVE_CREDITS_KEY).wasPressedThisFrame)
					{
						Object.FindObjectOfType<Terminal>().groupCredits = 5000;
					}
				}
				break;
			case Mode.GHOST:
				if (!scrapSpawnMode)
				{
					bool isIndoor = IsTargetInside();
					List<SpawnableEnemyWithRarity> spawnableEnemies = GetSpawnableEnemies(isIndoor);
					for (int i = 0; i < InputKeys.GHOST_SPAWN_ENEMY_KEYS.Count && i < spawnableEnemies.Count; i++)
					{
						if (((ButtonControl)InputKeys.GHOST_SPAWN_ENEMY_KEYS[i]).wasPressedThisFrame)
						{
							currentControlledEnemy = SpawnControllableEnemy(spawnableEnemies[i], ghost.transform.position, ghost.transform.rotation);
							EnableGhost(enable: false);
							currentMode = Mode.ENEMY;
							break;
						}
					}
				}
				else
				{
					List<SpawnableItemWithRarity> list = ExtensionMethods.Chunk(GetSpawnableScraps(), scrapSpawnPageSize).ToList()[scrapSpawnPage].ToList();
					for (int j = 0; j < InputKeys.GHOST_SPAWN_ENEMY_KEYS.Count && j < list.Count; j++)
					{
						if (((ButtonControl)InputKeys.GHOST_SPAWN_ENEMY_KEYS[j]).wasPressedThisFrame)
						{
							SpawnScrap(list[j], ghost.transform.position);
							break;
						}
					}
				}
				if (((ButtonControl)InputKeys.EXIT_KEY).wasPressedThisFrame)
				{
					EnableGhost(enable: false);
					EnableHostPlayer(enable: true);
					currentMode = Mode.HOST;
					GetHostPlayer().isTypingChat = false;
				}
				_ = ((ButtonControl)Keyboard.current.upArrowKey).wasPressedThisFrame;
				if (scrapSpawnMode && ((ButtonControl)Keyboard.current.downArrowKey).wasPressedThisFrame)
				{
					int num = GetSpawnableScraps().Count / scrapSpawnPageSize;
					ControlCompanyPlugin.Instance.logger.LogMessage((object)$"Total scraps: {GetSpawnableScraps().Count()}, final page of scrap: {num}");
					scrapSpawnPage++;
					if (scrapSpawnPage > num)
					{
						scrapSpawnPage = 0;
					}
				}
				break;
			}
		}

		private bool IsTargetInside()
		{
			if ((Object)(object)currentTarget != (Object)null)
			{
				return currentTarget.isInsideFactory;
			}
			return false;
		}

		private void OnGUI()
		{
			if (!IsGameStarted() || !showUI)
			{
				return;
			}
			if (!IsHost())
			{
				if (gameStartedTime < 30f)
				{
					UIManager.Instance.RenderNotHostLabel(((InputControl)InputKeys.TOGGLE_UI_KEY).displayName);
				}
				return;
			}
			switch (currentMode)
			{
			case Mode.ENEMY:
				UIManager.Instance.RenderEnemyControls(((InputControl)InputKeys.ENEMY_PRIMARY_SKILL_BUTTON).shortDisplayName, ((InputControl)InputKeys.ENEMY_SECONDARY_SKILL_BUTTON).shortDisplayName, ((InputControl)InputKeys.ENEMY_TOGGLE_AI_KEY).displayName, ((InputControl)InputKeys.EXIT_KEY).displayName, currentControlledEnemy, GetHostPlayer());
				break;
			case Mode.HOST:
				UIManager.Instance.RenderHostControls(((InputControl)InputKeys.HOST_GHOST_MODE_KEY).displayName, ((InputControl)InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_LEFT).displayName, ((InputControl)InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_RIGHT).displayName, currentTarget, isExtendedModeEnabled, ((InputControl)InputKeys.HOST_GIVE_CREDITS_KEY).displayName, ((InputControl)InputKeys.HOST_TELEPORT_TO_ENTRANCE_KEY).displayName, ((InputControl)InputKeys.TOGGLE_UI_KEY).displayName);
				break;
			case Mode.GHOST:
			{
				bool isIndoor = IsTargetInside();
				UIManager.Instance.RenderGhostControls(InputKeys.GHOST_SPAWN_ENEMY_KEYS.Select((KeyControl key) => ((InputControl)key).displayName).ToList(), ((InputControl)InputKeys.EXIT_KEY).displayName, GetSpawnableEnemies(isIndoor), ExtensionMethods.Chunk(GetSpawnableScraps(), scrapSpawnPageSize).ToList()[scrapSpawnPage].ToList(), GetHostPlayer(), scrapSpawnMode);
				break;
			}
			}
		}

		private bool IsHostDead()
		{
			return GetHostPlayer().isPlayerDead;
		}

		private void EnableGhost(bool enable)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			EnableGhost(enable, Vector3.zero);
		}

		private void EnableGhost(bool enable, Vector3 position)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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)
			if (enable)
			{
				ghost.transform.position = position + new Vector3(0f, 0.5f, 0f);
				ghost.transform.rotation = Quaternion.identity;
				ghost.SetActive(true);
			}
			else
			{
				ghost.SetActive(false);
			}
		}

		private void EnableHostPlayer(bool enable)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB hostPlayer = GetHostPlayer();
			MovementActions movement;
			if (!enable)
			{
				ResetMicPushToTalk();
				HUDManager.Instance.HideHUD(false);
				((Behaviour)StartOfRound.Instance.audioListener).enabled = true;
				movement = hostPlayer.playerActions.Movement;
				((MovementActions)(ref movement)).PingScan.Disable();
			}
			else
			{
				initialMicPushToTalkSetting = IngamePlayerSettings.Instance.settings.pushToTalk;
				ForceMicPushToTalk();
				HUDManager.Instance.HideHUD(true);
				((Behaviour)StartOfRound.Instance.audioListener).enabled = false;
				movement = hostPlayer.playerActions.Movement;
				((MovementActions)(ref movement)).PingScan.Enable();
			}
		}

		private void EnablePlayer2DMics(bool enable, List<PlayerControllerB> players)
		{
			foreach (PlayerControllerB player in players)
			{
				if (player.isHostPlayerObject)
				{
					continue;
				}
				AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource;
				if (enable)
				{
					if ((Object)(object)currentVoiceChatAudioSource != (Object)null)
					{
						currentVoiceChatAudioSource.spatialBlend = 0f;
					}
					player.currentVoiceChatIngameSettings.set2D = true;
					player.voicePlayerState.Volume = 1f;
				}
				else
				{
					if ((Object)(object)currentVoiceChatAudioSource != (Object)null)
					{
						currentVoiceChatAudioSource.spatialBlend = 1f;
					}
					player.currentVoiceChatIngameSettings.set2D = false;
					player.voicePlayerState.Volume = 0f;
				}
			}
		}

		private void SetNextTargetPlayer(int direction)
		{
			List<PlayerControllerB> alivePlayers = GetAlivePlayers();
			if (alivePlayers.Count == 0)
			{
				SetCurrentTargetToHost();
				ControlCompanyPlugin.Instance.logger.LogMessage((object)"Alive player count is zero");
			}
			else
			{
				currentTargetIndex += direction;
				if (currentTargetIndex >= alivePlayers.Count)
				{
					currentTargetIndex = 0;
				}
				else if (currentTargetIndex < 0)
				{
					currentTargetIndex = alivePlayers.Count - 1;
				}
				currentTargetIndex = Math.Min(Math.Max(0, currentTargetIndex), alivePlayers.Count - 1);
				currentTarget = alivePlayers[currentTargetIndex];
			}
			ControlCompanyPlugin.Instance.logger.LogMessage((object)$"Current target index: {currentTargetIndex}");
			ControlCompanyPlugin.Instance.logger.LogMessage((object)("Setting next target to: " + currentTarget?.playerUsername));
		}

		public void SetCurrentTargetToHost()
		{
			currentTargetIndex = 0;
			currentTarget = GetHostPlayer();
			ControlCompanyPlugin.Instance.logger.LogMessage((object)"Setting next target to host");
		}

		public void StartOfRoundInitialization()
		{
			gameStartedTime = 0f;
			SetCurrentTargetToHost();
			ResetToDefault();
			ControlCompanyPlugin.Instance.logger.LogMessage((object)"Start of round initialization completed.");
		}

		public void EndOfRoundCleanUp()
		{
			ResetToDefault();
			ControlCompanyPlugin.Instance.logger.LogMessage((object)"End of round clean up completed.");
		}

		private void ResetToDefault()
		{
			GetHostPlayer().isTypingChat = false;
			currentMode = Mode.HOST;
			if ((Object)(object)ghost != (Object)null)
			{
				Object.Destroy((Object)(object)ghost);
				ghost = null;
			}
			if ((Object)(object)currentControlledEnemy != (Object)null)
			{
				currentControlledEnemy.DestroyAndCleanUp();
			}
			EnableHostPlayer(enable: true);
			ControlCompanyPlugin.Instance.logger.LogMessage((object)"Reset to default.");
		}

		public PlayerControllerB GetHostPlayer()
		{
			return RoundManager.Instance.playersManager.allPlayerObjects[0].GetComponentInChildren<PlayerControllerB>();
		}

		public List<PlayerControllerB> GetDeadPlayers()
		{
			return (from player in GetAllPlayers()
				where player.isPlayerDead
				select player).ToList();
		}

		public List<PlayerControllerB> GetAlivePlayers()
		{
			return (from player in GetAllPlayers()
				where !player.isPlayerDead
				select player).ToList();
		}

		public List<PlayerControllerB> GetAllPlayers()
		{
			List<PlayerControllerB> list = new List<PlayerControllerB>();
			GameObject[] allPlayerObjects = RoundManager.Instance.playersManager.allPlayerObjects;
			for (int i = 0; i < allPlayerObjects.Length; i++)
			{
				PlayerControllerB componentInChildren = allPlayerObjects[i].GetComponentInChildren<PlayerControllerB>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.isPlayerControlled)
				{
					list.Add(componentInChildren);
				}
			}
			return list;
		}

		public bool DoesCurrentLevelExist()
		{
			return (Object)(object)GetCurrentLevel() != (Object)null;
		}

		public bool IsGameStarted()
		{
			if ((Object)(object)RoundManager.Instance != (Object)null && (Object)(object)RoundManager.Instance.currentLevel != (Object)null && (Object)(object)GameNetworkManager.Instance != (Object)null && GameNetworkManager.Instance.gameHasStarted && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				return !StartOfRound.Instance.inShipPhase;
			}
			return false;
		}

		public SelectableLevel GetCurrentLevel()
		{
			return RoundManager.Instance.currentLevel;
		}

		public StartOfRound GetPlayersManager()
		{
			return RoundManager.Instance.playersManager;
		}

		private bool IsHost()
		{
			return ((NetworkBehaviour)RoundManager.Instance).IsHost;
		}

		public List<SpawnableItemWithRarity> GetSpawnableScraps()
		{
			return GetCurrentLevel().spawnableScrap;
		}

		public List<SpawnableEnemyWithRarity> GetSpawnableEnemies(bool isIndoor)
		{
			if (isIndoor)
			{
				return GetSpawnableIndoorEnemies();
			}
			return GetSpawnableOutdoorEnemies();
		}

		public List<SpawnableEnemyWithRarity> GetSpawnableIndoorEnemies()
		{
			if (!allowAllEnemies)
			{
				return GetAllowListedIndoorEnemies();
			}
			return GetIndoorEnemyList();
		}

		public List<SpawnableEnemyWithRarity> GetAllowListedIndoorEnemies()
		{
			return GetIndoorEnemyList().Where(delegate(SpawnableEnemyWithRarity enemy)
			{
				EnemyAI componentInChildren = enemy.enemyType.enemyPrefab.GetComponentInChildren<EnemyAI>();
				return !((Object)(object)componentInChildren == (Object)null) && componentInChildren.IsEnemyAllowlisted();
			}).ToList();
		}

		public List<SpawnableEnemyWithRarity> GetIndoorEnemyList()
		{
			return GetCurrentLevel().Enemies;
		}

		public List<SpawnableEnemyWithRarity> GetSpawnableOutdoorEnemies()
		{
			if (!allowAllEnemies)
			{
				return GetAllowListedOutdoorEnemies();
			}
			return GetOutdoorEnemyList();
		}

		public List<SpawnableEnemyWithRarity> GetAllowListedOutdoorEnemies()
		{
			return GetOutdoorEnemyList().Where(delegate(SpawnableEnemyWithRarity enemy)
			{
				EnemyAI componentInChildren = enemy.enemyType.enemyPrefab.GetComponentInChildren<EnemyAI>();
				return !((Object)(object)componentInChildren == (Object)null) && componentInChildren.IsEnemyAllowlisted();
			}).ToList();
		}

		public List<SpawnableEnemyWithRarity> GetOutdoorEnemyList()
		{
			return GetCurrentLevel().OutsideEnemies;
		}

		private GameObject SpawnScrap(SpawnableItemWithRarity scrap, Vector3 position)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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)
			GameObject obj = Object.Instantiate<GameObject>(scrap.spawnableItem.spawnPrefab, position, Quaternion.identity);
			GrabbableObject componentInChildren = obj.GetComponentInChildren<GrabbableObject>();
			((Component)componentInChildren).transform.rotation = Quaternion.Euler(componentInChildren.itemProperties.restingRotation);
			obj.GetComponentInChildren<NetworkObject>().Spawn(true);
			return obj;
		}

		private GameObject SpawnEnemy(SpawnableEnemyWithRarity enemyWithRarity, Vector3 position)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(enemyWithRarity.enemyType.enemyPrefab, position + new Vector3(0f, 0.5f, 0f), Quaternion.identity);
			obj.GetComponentInChildren<NetworkObject>().Spawn(true);
			return obj;
		}

		private EnemyController SpawnControllableEnemy(SpawnableEnemyWithRarity enemyWithRarity, Vector3 position, Quaternion rotation)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(enemyWithRarity.enemyType.enemyPrefab, position + new Vector3(0f, 0.5f, 0f), Quaternion.identity);
			val.GetComponentInChildren<NetworkObject>().Spawn(true);
			GameObject val2 = new GameObject("enemy_controller");
			val2.transform.position = position + new Vector3(0f, 0.5f, 0f);
			val2.transform.rotation = rotation;
			EnemyAI componentInChildren = val.GetComponentInChildren<EnemyAI>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				throw new Exception("Enemy AI is null, cannot spawn enemy");
			}
			EnemyController andAttachEnemyController = componentInChildren.GetAndAttachEnemyController(val2);
			andAttachEnemyController.InitializeEnemyController(GetHostPlayer().playerActions, val);
			andAttachEnemyController.EnableLight(IsTargetInside());
			return andAttachEnemyController;
		}

		private DissonanceComms GetMic()
		{
			return StartOfRound.Instance.voiceChatModule;
		}

		private void ForceMicPushToTalk()
		{
			IngamePlayerSettings.Instance.settings.pushToTalk = true;
		}

		private void ResetMicPushToTalk()
		{
			IngamePlayerSettings.Instance.settings.pushToTalk = initialMicPushToTalkSetting;
		}
	}
	internal class DoorOpener : MonoBehaviour
	{
		public void OpenDoor(float range)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, range);
			for (int i = 0; i < array.Length; i++)
			{
				DoorLock componentInChildren = ((Component)array[i]).GetComponentInChildren<DoorLock>();
				if ((Object)(object)componentInChildren != (Object)null && !componentInChildren.GetFieldValue<bool>("isDoorOpened"))
				{
					if (componentInChildren.isLocked)
					{
						componentInChildren.UnlockDoorServerRpc();
					}
					componentInChildren.OpenDoorAsEnemyServerRpc();
					((Component)componentInChildren).gameObject.GetComponent<AnimatedObjectTrigger>().TriggerAnimationNonPlayer(false, true, false);
					ControlCompanyPlugin.Instance.logger.LogMessage((object)"Opened door");
				}
			}
		}
	}
	internal class EnemyController : CustomPlayerController
	{
		protected GameObject enemyGameObject;

		private EnemyAI enemyAI;

		private NavMeshAgent enemyAIAgent;

		private float originalAgentAngularSpeed;

		private float originalAgentSpeed;

		private float rotationSpeed = 5f;

		protected bool isAIControlled;

		protected bool controlEnemyRotation;

		protected bool controlEnemyMovement = true;

		protected bool lockEnemyRotationInput;

		public bool IsAIControlled => isAIControlled;

		public EnemyAI EnemyAI => enemyAI;

		public virtual void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!isInitialized)
			{
				Initialize(playerActions, CameraMode.THIRD_PERSON);
				enemyAI = GetEnemyAIFromEnemyGameObject(enemyGameObject);
				if ((Object)(object)enemyAI == (Object)null)
				{
					throw new Exception("Enemy gameobject does not have EnemyAI script attacked.");
				}
				canJump = false;
				((Component)enemyAI).gameObject.LogLayer();
				enemyGameObject.transform.position = ((Component)this).transform.position;
				enemyGameObject.transform.rotation = ((Component)this).transform.rotation;
				this.enemyGameObject = enemyGameObject;
				enemyAIAgent = enemyGameObject.GetComponentInChildren<NavMeshAgent>();
				originalAgentAngularSpeed = enemyAIAgent.angularSpeed;
				originalAgentSpeed = enemyAIAgent.speed;
				ConfigureEnemyAttributes(enemyAI);
				EnableAIControl(enabled: false);
			}
		}

		protected EnemyAI GetEnemyAIFromEnemyGameObject(GameObject enemyObj)
		{
			return enemyObj.GetComponentInChildren<EnemyAI>();
		}

		private void ConfigureEnemyAttributes(EnemyAI enemyAI)
		{
			EnemyAttributes enemyAttributes = enemyAI.GetEnemyAttributes();
			base.WalkSpeed = enemyAttributes.WalkSpeed;
			base.RunSpeed = enemyAttributes.RunSpeed;
			SetCamDistance(enemyAttributes.CamDistance);
			SetCamHeight(enemyAttributes.CamHeight);
			controlEnemyRotation = enemyAttributes.PlayerControlsRotation;
			controlEnemyMovement = true;
		}

		protected override void Update()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!isInitialized)
			{
				return;
			}
			base.Update();
			if (!isAIControlled)
			{
				if (!enemyAI.isEnemyDead)
				{
					if (controlEnemyMovement)
					{
						enemyGameObject.transform.position = ((Component)this).transform.position;
					}
					if (controlEnemyRotation && !lockEnemyRotationInput)
					{
						enemyGameObject.transform.rotation = ((Component)this).transform.rotation;
					}
				}
			}
			else
			{
				((Component)this).transform.position = enemyGameObject.transform.position;
			}
		}

		public void SetLockEnemyRotation(bool lockEnemyRotationInput)
		{
			this.lockEnemyRotationInput = lockEnemyRotationInput;
		}

		public virtual void UsePrimarySkill()
		{
			CheckInitialized();
			_ = isAIControlled;
		}

		public virtual void ReleasePrimarySkill()
		{
			CheckInitialized();
			_ = isAIControlled;
		}

		public virtual void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				enemyAI.SwitchToBehaviourState(1);
			}
		}

		public virtual void ReleaseSecondarySkill()
		{
			CheckInitialized();
			_ = isAIControlled;
		}

		public void SwitchAIState(int stateIndex)
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				enemyAI.SwitchToBehaviourState(stateIndex);
			}
		}

		protected virtual void EnableAIControl(bool enabled)
		{
			CheckInitialized();
			isAIControlled = enabled;
			ControlCompanyPlugin.Instance.logger.LogMessage((object)$"Enable AI control: {enabled}");
			if (IsAIControlled)
			{
				enemyAIAgent.angularSpeed = originalAgentAngularSpeed;
				enemyAIAgent.speed = originalAgentSpeed;
				enemyAIAgent.isStopped = false;
			}
			else
			{
				enemyAI.ChangeOwnershipOfEnemy(ControlCenter.Instance.GetHostPlayer().actualClientId);
				enemyAIAgent.angularSpeed = 0f;
				enemyAIAgent.speed = 0f;
				enemyAIAgent.isStopped = true;
				((Component)this).transform.SetParent((Transform)null);
			}
			canMove = !isAIControlled;
		}

		public void ToggleAIControl()
		{
			CheckInitialized();
			isAIControlled = !isAIControlled;
			EnableAIControl(isAIControlled);
		}

		public virtual void DestroyAndCleanUp()
		{
			if (!enemyAI.isEnemyDead)
			{
				Object.Destroy((Object)(object)enemyGameObject);
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		public virtual string GetPrimarySkillName()
		{
			return "";
		}

		public virtual string GetSecondarySkillName()
		{
			return "Secondary Skill";
		}

		protected void CheckInitialized()
		{
			if (!isInitialized)
			{
				throw new Exception("Not initialized yet.");
			}
		}
	}
	internal class CustomPlayerController : MonoBehaviour
	{
		public enum CameraMode
		{
			THIRD_PERSON,
			FIRST_PERSON
		}

		protected bool isInitialized;

		protected bool hasControl;

		protected bool canMove;

		protected bool canRotate;

		protected bool canJump;

		protected CameraMode camMode;

		protected CharacterController characterController;

		protected GameObject cameraGameObjectParent;

		protected GameObject cameraGameObject;

		protected Camera camera;

		protected Light light;

		protected PlayerActions playerActions;

		protected DoorOpener doorOpener;

		private float runSpeed = 9f;

		private float walkSpeed = 7f;

		private float camDistance = -3.5f;

		private float camHeight = 2f;

		private float gravity = -20f;

		private float jumpHeight = 4.5f;

		private float currentYVelocity;

		private HashSet<int> seenLayers = new HashSet<int>();

		public float RunSpeed
		{
			get
			{
				return runSpeed;
			}
			set
			{
				runSpeed = value;
			}
		}

		public float WalkSpeed
		{
			get
			{
				return walkSpeed;
			}
			set
			{
				walkSpeed = value;
			}
		}

		public float Gravity
		{
			get
			{
				return gravity;
			}
			set
			{
				gravity = value;
			}
		}

		public void Initialize(PlayerActions playerActions, CameraMode camMode)
		{
			if (!isInitialized)
			{
				this.playerActions = playerActions;
				this.camMode = camMode;
				characterController = InitializeCharacterController();
				camera = InitializeCamera();
				light = InitializeLight(((Component)camera).gameObject);
				doorOpener = ((Component)this).gameObject.AddComponent<DoorOpener>();
				EnableControl(enable: true);
				isInitialized = true;
			}
		}

		public void EnableLight(bool enable)
		{
			((Behaviour)light).enabled = enable;
		}

		public void EnableControl(bool enable)
		{
			hasControl = enable;
			canMove = enable;
			canRotate = enable;
			canJump = enable;
		}

		public bool IsMoving()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 velocity = characterController.velocity;
			return ((Vector3)(ref velocity)).sqrMagnitude > 0f;
		}

		public void SetCamHeight(float camHeight)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			this.camHeight = camHeight;
			cameraGameObjectParent.transform.localPosition = new Vector3(0f, camHeight, 0f);
		}

		public void SetCamDistance(float camDistance)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			this.camDistance = camDistance;
			cameraGameObject.transform.localPosition = new Vector3(0f, 0f, (camMode == CameraMode.THIRD_PERSON) ? camDistance : 0f);
		}

		protected virtual void Update()
		{
			if (isInitialized && hasControl)
			{
				if (canMove)
				{
					Move();
				}
				if (canRotate)
				{
					Rotate();
				}
				if (((ButtonControl)InputKeys.CONTROLLER_USE_KEY).wasPressedThisFrame)
				{
					doorOpener.OpenDoor(3f);
				}
			}
		}

		protected virtual void Move()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			MovementActions movement = playerActions.Movement;
			bool flag = ((MovementActions)(ref movement)).Sprint.IsInProgress();
			movement = playerActions.Movement;
			Vector3 val = Vector2.op_Implicit(((MovementActions)(ref movement)).Move.ReadValue<Vector2>());
			Vector3 val2 = ((Component)this).transform.right * val.x;
			Vector3 val3 = ((Component)this).transform.forward * val.y;
			bool isGrounded = characterController.isGrounded;
			if (isGrounded && currentYVelocity < 0f)
			{
				currentYVelocity = 0f;
			}
			if (canJump && isGrounded && ((ButtonControl)InputKeys.CONTROLLER_JUMP_KEY).wasPressedThisFrame)
			{
				currentYVelocity += Mathf.Sqrt(jumpHeight * (0f - gravity));
			}
			currentYVelocity += gravity * Time.deltaTime;
			characterController.Move(((val2 + val3) * (flag ? runSpeed : walkSpeed) + new Vector3(0f, currentYVelocity, 0f)) * Time.deltaTime);
		}

		protected virtual void Rotate()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			MovementActions movement = playerActions.Movement;
			Vector2 val = ((MovementActions)(ref movement)).Look.ReadValue<Vector2>() * 0.008f * (float)IngamePlayerSettings.Instance.settings.lookSensitivity;
			if (IngamePlayerSettings.Instance.settings.invertYAxis)
			{
				val.y *= -1f;
			}
			((Component)this).transform.Rotate(new Vector3(0f, val.x, 0f));
			cameraGameObjectParent.transform.Rotate(new Vector3(0f - val.y, 0f, 0f));
		}

		private Light InitializeLight(GameObject lightParent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("controller_light");
			val.transform.SetParent(lightParent.transform);
			val.transform.localPosition = new Vector3(0f, 0.5f, 0f);
			val.transform.localRotation = Quaternion.identity;
			Light obj = val.AddComponent<Light>();
			obj.range = 15f;
			obj.intensity = 250f;
			obj.cullingMask = -1;
			return obj;
		}

		private CharacterController InitializeCharacterController()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			CharacterController obj = ((Component)this).gameObject.AddComponent<CharacterController>();
			((Collider)obj).excludeLayers = LayerMask.op_Implicit(LayerMask.op_Implicit(Constants.PLAYER_LOS_LAYER) | LayerMask.op_Implicit(Constants.ITERACTABLE_OBJ_LAYER) | LayerMask.op_Implicit(Constants.ENEMIES_LAYER) | LayerMask.op_Implicit(Constants.PROPS_LAYER) | LayerMask.op_Implicit(Constants.PLAYER_RAGDOLL_LAYER));
			obj.center = new Vector3(0f, 0.55f, 0f);
			obj.height = 0.4f;
			obj.slopeLimit = 60f;
			obj.stepOffset = 0.4f;
			return obj;
		}

		private Camera InitializeCamera()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0022: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("controller_cam_parent");
			val.transform.SetParent(((Component)this).transform);
			val.transform.localRotation = Quaternion.identity;
			val.transform.localPosition = new Vector3(0f, camHeight, 0f);
			GameObject val2 = new GameObject("controller_cam");
			val2.transform.SetParent(val.transform);
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localPosition = new Vector3(0f, 0f, (camMode == CameraMode.THIRD_PERSON) ? camDistance : 0f);
			Camera obj = val2.AddComponent<Camera>();
			val2.AddComponent<AudioListener>();
			cameraGameObject = val2;
			cameraGameObjectParent = val;
			obj.cullingMask = ControlCenter.Instance.GetHostPlayer().gameplayCamera.cullingMask;
			return obj;
		}

		private void OnControllerColliderHit(ControllerColliderHit hit)
		{
			if (!seenLayers.Contains(hit.gameObject.layer))
			{
				hit.gameObject.LogLayer();
				seenLayers.Add(hit.gameObject.layer);
			}
		}
	}
}
namespace ControlCompany.Core.UI
{
	public class UIInstruction
	{
		public string InputKey { get; set; }

		public string ActionText { get; set; }
	}
	internal class UIManager : MonoBehaviour
	{
		private const float GUI_LABEL_HEIGHT = 36f;

		private const float GUI_LABEL_WIDTH = 750f;

		private const float GUI_PADDING = 32f;

		private const int GUI_FONT_SIZE = 28;

		private const FontStyle GUI_FONT_WEIGHT = 0;

		public static UIManager Instance;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
		}

		public void RenderNotHostLabel(string toggleUIKey)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)3,
				fontSize = 24,
				fontStyle = (FontStyle)0
			};
			val.normal.textColor = Color.red;
			RenderTextTopLeftCorner("Not hosting. ControlCompany mod is disabled. Press " + toggleUIKey + " to hide.", 0f, val);
		}

		public void RenderEnemyControls(string primaryKey, string secondaryKey, string aiControlKey, string exitKey, EnemyController enemyController, PlayerControllerB hostPlayer)
		{
			string primarySkillName = enemyController.GetPrimarySkillName();
			string secondarySkillName = enemyController.GetSecondarySkillName();
			List<UIInstruction> list = new List<UIInstruction>();
			if (enemyController.IsAIControlled)
			{
				list.Add(new UIInstruction
				{
					InputKey = aiControlKey,
					ActionText = "Take control"
				});
			}
			else
			{
				if (!Utility.IsNullOrWhiteSpace(primarySkillName))
				{
					list.Add(new UIInstruction
					{
						InputKey = primaryKey,
						ActionText = primarySkillName
					});
				}
				if (!Utility.IsNullOrWhiteSpace(secondarySkillName))
				{
					list.Add(new UIInstruction
					{
						InputKey = secondaryKey,
						ActionText = secondarySkillName
					});
				}
				list.Add(new UIInstruction
				{
					InputKey = aiControlKey,
					ActionText = "AI control"
				});
			}
			list.Add(new UIInstruction
			{
				InputKey = exitKey,
				ActionText = "Exit"
			});
			RenderPlayerStatus(hostPlayer);
			float height = 0f;
			height = RenderEnemyStatus(enemyController, height);
			RenderEnemySkills(list, height);
		}

		public void RenderHostControls(string ghostModeKey, string cycleLeftKey, string cycleRightKey, PlayerControllerB currentTarget, bool isExtendedModeEnabled, string creditsKey, string entranceTeleportKey, string toggleUIKey)
		{
			List<UIInstruction> list = new List<UIInstruction>();
			list.Add(new UIInstruction
			{
				InputKey = ghostModeKey,
				ActionText = "Ghost mode"
			});
			list.Add(new UIInstruction
			{
				InputKey = $"{cycleLeftKey}/{cycleRightKey}",
				ActionText = "Change target"
			});
			list.Add(new UIInstruction
			{
				InputKey = toggleUIKey,
				ActionText = "Hide UI"
			});
			if (isExtendedModeEnabled)
			{
				list.Add(new UIInstruction
				{
					InputKey = creditsKey,
					ActionText = "Give credits"
				});
				list.Add(new UIInstruction
				{
					InputKey = entranceTeleportKey,
					ActionText = "Teleport to entrance"
				});
			}
			RenderHostControlList(list, currentTarget);
		}

		public void RenderGhostControls(List<string> enemySpawnKeys, string exitKey, List<SpawnableEnemyWithRarity> enemies, List<SpawnableItemWithRarity> scraps, PlayerControllerB hostPlayer, bool scrapSpawnMode)
		{
			List<UIInstruction> list = new List<UIInstruction>();
			if (!scrapSpawnMode)
			{
				for (int i = 0; i < enemies.Count && i < enemySpawnKeys.Count; i++)
				{
					EnemyAI componentInChildren = enemies[i].enemyType.enemyPrefab.GetComponentInChildren<EnemyAI>();
					list.Add(new UIInstruction
					{
						InputKey = enemySpawnKeys[i],
						ActionText = $"Control {(((Object)(object)componentInChildren == (Object)null) ? enemies[i].enemyType.enemyName : componentInChildren.GetEnemyName())}"
					});
				}
			}
			else
			{
				for (int j = 0; j < scraps.Count && j < enemySpawnKeys.Count; j++)
				{
					list.Add(new UIInstruction
					{
						InputKey = enemySpawnKeys[j],
						ActionText = $"Spawn {scraps[j].spawnableItem.itemName}"
					});
				}
			}
			list.Add(new UIInstruction
			{
				InputKey = exitKey,
				ActionText = "Exit"
			});
			RenderPlayerStatus(hostPlayer);
			RenderGhostControlList(list);
		}

		private void RenderGhostControlList(List<UIInstruction> ghostControls)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			//IL_002f: Expected O, but got Unknown
			if (ghostControls.Count <= 0)
			{
				return;
			}
			GUIStyle style = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)5,
				fontSize = 28,
				fontStyle = (FontStyle)0
			};
			float num = 0f;
			foreach (UIInstruction ghostControl in ghostControls)
			{
				RenderTextTopRightCorner($"{ghostControl.InputKey}: {ghostControl.ActionText}", num, style);
				num += 36f;
			}
		}

		private float RenderMicStatus(float height, PlayerControllerB hostPlayer)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)3,
				fontSize = 28,
				fontStyle = (FontStyle)0
			};
			float num = height;
			if (IngamePlayerSettings.Instance.settings.micEnabled)
			{
				if (!StartOfRound.Instance.voiceChatModule.IsMuted)
				{
					val.normal.textColor = Color.green;
					RenderTextTopLeftCorner(string.Format("{0} mic enabled", hostPlayer.isPlayerDead ? "Dead" : "Player"), num, val);
				}
				else
				{
					val.normal.textColor = Color.red;
					RenderTextTopLeftCorner(string.Format("{0} mic disabled (push to talk)", hostPlayer.isPlayerDead ? "Dead" : "Player"), num, val);
				}
				num += 36f;
			}
			return num;
		}

		private float RenderPlayerStatus(PlayerControllerB hostPlayer)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0046: 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)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)3,
				fontSize = 28,
				fontStyle = (FontStyle)0
			};
			if (hostPlayer.isPlayerDead)
			{
				val.normal.textColor = Color.red;
			}
			else
			{
				val.normal.textColor = Color.green;
			}
			float num = 0f;
			RenderTextTopLeftCorner(string.Format("Player status: {0}", hostPlayer.isPlayerDead ? "Dead" : "Alive"), num, val);
			num += 36f;
			if (!hostPlayer.isPlayerDead)
			{
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3,
					fontSize = 28,
					fontStyle = (FontStyle)0
				};
				bool flag = !HostIsNearOtherPlayers(hostPlayer);
				if (flag)
				{
					val2.normal.textColor = Color.green;
				}
				else
				{
					val2.normal.textColor = Color.red;
				}
				RenderTextTopLeftCorner(string.Format("Player proximity: {0}", flag ? "Alone" : "Near others"), num, val2);
				num += 36f;
			}
			return num + RenderMicStatus(num, hostPlayer);
		}

		private void RenderHostControlList(List<UIInstruction> hostControls, PlayerControllerB currentTarget)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if (hostControls.Count <= 0)
			{
				return;
			}
			GUIStyle style = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)5,
				fontSize = 28,
				fontStyle = (FontStyle)0
			};
			float num = 0f;
			if ((Object)(object)currentTarget != (Object)null)
			{
				RenderTextTopRightCorner($"Spawn target: {currentTarget.playerUsername}", num, style);
				num += 36f;
			}
			foreach (UIInstruction hostControl in hostControls)
			{
				RenderTextTopRightCorner($"{hostControl.InputKey}: {hostControl.ActionText}", num, style);
				num += 36f;
			}
		}

		private float RenderEnemyStatus(EnemyController enemyController, float height)
		{
			//IL_0014: 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_0020: 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_0030: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			float num = height;
			if (enemyController.IsAIControlled)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)5,
					fontSize = 28,
					fontStyle = (FontStyle)0
				};
				val.normal.textColor = Color.red;
				RenderTextTopRightCorner("AI controlled", num, val);
				num += 36f;
			}
			return num;
		}

		private float RenderEnemySkills(List<UIInstruction> playerEnemyControls, float height)
		{
			//IL_0015: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			float num = height;
			if (playerEnemyControls.Count > 0)
			{
				GUIStyle style = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)5,
					fontSize = 28,
					fontStyle = (FontStyle)0
				};
				foreach (UIInstruction playerEnemyControl in playerEnemyControls)
				{
					RenderTextTopRightCorner($"{playerEnemyControl.InputKey}: {playerEnemyControl.ActionText}", num, style);
					num += 36f;
				}
			}
			return num;
		}

		private void RenderTextMiddle(string text, float yPos, GUIStyle style)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect((float)Screen.width / 2f - 375f, yPos + 32f, 750f, 36f), text, style);
		}

		private void RenderTextTopRightCorner(string text, float yPos, GUIStyle style)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect((float)Screen.width - 750f - 32f, yPos + 32f, 750f, 36f), text, style);
		}

		private void RenderTextTopLeftCorner(string text, float yPos, GUIStyle style)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect(32f, yPos + 32f, 750f, 36f), text, style);
		}

		private bool HostIsNearOtherPlayers(PlayerControllerB hostPlayer)
		{
			return (bool)hostPlayer.Call("NearOtherPlayers", hostPlayer, 17f);
		}
	}
}
namespace ControlCompany.Core.Input
{
	public static class InputKeys
	{
		public static KeyControl EXIT_KEY = Keyboard.current.escapeKey;

		public static KeyControl EXTENDED_MODE_KEY = Keyboard.current.digit0Key;

		public static KeyControl TOGGLE_UI_KEY = Keyboard.current.uKey;

		public static KeyControl HOST_GHOST_MODE_KEY = Keyboard.current.f1Key;

		public static KeyControl HOST_CYCLE_PLAYER_TARGET_LIST_KEY_LEFT = Keyboard.current.oKey;

		public static KeyControl HOST_CYCLE_PLAYER_TARGET_LIST_KEY_RIGHT = Keyboard.current.pKey;

		public static KeyControl HOST_GIVE_CREDITS_KEY = Keyboard.current.digit8Key;

		public static KeyControl HOST_TELEPORT_TO_ENTRANCE_KEY = Keyboard.current.digit9Key;

		public static KeyControl GHOST_SPAWN_ENEMY_1 = Keyboard.current.f1Key;

		public static KeyControl GHOST_SPAWN_ENEMY_2 = Keyboard.current.f2Key;

		public static KeyControl GHOST_SPAWN_ENEMY_3 = Keyboard.current.f3Key;

		public static KeyControl GHOST_SPAWN_ENEMY_4 = Keyboard.current.f4Key;

		public static KeyControl GHOST_SPAWN_ENEMY_5 = Keyboard.current.f5Key;

		public static KeyControl GHOST_SPAWN_ENEMY_6 = Keyboard.current.f6Key;

		public static KeyControl GHOST_SPAWN_ENEMY_7 = Keyboard.current.f7Key;

		public static KeyControl GHOST_SPAWN_ENEMY_8 = Keyboard.current.f8Key;

		public static KeyControl GHOST_SPAWN_ENEMY_9 = Keyboard.current.f9Key;

		public static KeyControl GHOST_SPAWN_ENEMY_10 = Keyboard.current.f10Key;

		public static KeyControl GHOST_SPAWN_ENEMY_11 = Keyboard.current.f11Key;

		public static KeyControl GHOST_SPAWN_ENEMY_12 = Keyboard.current.f12Key;

		public static List<KeyControl> GHOST_SPAWN_ENEMY_KEYS = new List<KeyControl>();

		public static KeyControl ENEMY_TOGGLE_AI_KEY = Keyboard.current.f1Key;

		public static ButtonControl ENEMY_PRIMARY_SKILL_BUTTON = Mouse.current.leftButton;

		public static ButtonControl ENEMY_SECONDARY_SKILL_BUTTON = Mouse.current.rightButton;

		public static KeyControl LOCK_ENEMY_ROTATION_KEY = Keyboard.current.leftAltKey;

		public static KeyControl CONTROLLER_USE_KEY = Keyboard.current.eKey;

		public static KeyControl CONTROLLER_JUMP_KEY = Keyboard.current.spaceKey;
	}
}
namespace ControlCompany.Core.Extentions
{
	public static class ExtensionMethods
	{
		public static T GetFieldValue<T>(this object obj, string name)
		{
			return (T)(obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj));
		}

		public static void SetFieldValue<T>(this object obj, string method, T value)
		{
			obj.GetType().GetField(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField | BindingFlags.SetProperty)?.SetValue(obj, value);
		}

		public static object Call(this object o, string methodName, params object[] args)
		{
			MethodInfo method = o.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
			if (method != null)
			{
				return method.Invoke(o, args);
			}
			return null;
		}

		public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
		{
			if (dictionary.TryGetValue(key, out var value))
			{
				return value;
			}
			return defaultValue;
		}

		public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
		{
			while (source.Any())
			{
				yield return source.Take(chunksize);
				source = source.Skip(chunksize);
			}
		}

		public static void LogLayer(this GameObject gameObject)
		{
			ControlCompanyPlugin.Instance.logger.LogMessage((object)$"Enemy layer ({LayerMask.LayerToName(gameObject.layer)}): {gameObject.layer}");
		}

		public static void LogGameObjectName(this GameObject gameObject)
		{
			ControlCompanyPlugin.Instance.logger.LogMessage((object)string.Format("GameObject name: {0}, parent: {1}", ((Object)gameObject).name, ((Object)(object)gameObject.transform.parent != (Object)null) ? ((Object)gameObject.transform.parent).name : "null"));
		}

		public static void LogAllComponents(this GameObject gameObject)
		{
			Component[] components = gameObject.GetComponents<Component>();
			foreach (Component val in components)
			{
				_ = $"GameObject ({((Object)gameObject).name}) component: {((Object)val).name}";
			}
		}

		public static void LogPosition(this GameObject gameObject)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			ControlCompanyPlugin.Instance.logger.LogMessage((object)$"GameObject ({((Object)gameObject).name}) position: {gameObject.transform.position}, local position: {gameObject.transform.localPosition}");
		}
	}
}
namespace ControlCompany.Core.Enemy
{
	internal class CentipedeEnemyController : EnemyController
	{
		private CentipedeAI centipedeAI;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			centipedeAI = (CentipedeAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		protected override void Update()
		{
			base.Update();
			bool flag = IsClingingToSomething();
			controlEnemyRotation = !flag;
			controlEnemyMovement = !flag;
		}

		protected override void Move()
		{
			if (!IsClingingToSomething())
			{
				base.Move();
			}
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && ((EnemyAI)centipedeAI).currentBehaviourStateIndex == 1)
			{
				SwitchAIState(2);
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && !IsClingingToSomething())
			{
				centipedeAI.Call("RaycastToCeiling");
				SwitchAIState(1);
			}
		}

		public bool IsClingingToSomething()
		{
			if (!((Object)(object)centipedeAI.clingingToPlayer != (Object)null) && !((EnemyAI)centipedeAI).inSpecialAnimation && !centipedeAI.GetFieldValue<bool>("clingingToDeadBody") && !centipedeAI.GetFieldValue<bool>("clingingToCeiling") && !centipedeAI.GetFieldValue<bool>("startedCeilingAnimationCoroutine"))
			{
				return centipedeAI.GetFieldValue<bool>("inDroppingOffPlayerAnim");
			}
			return true;
		}

		public override string GetPrimarySkillName()
		{
			return "Drop";
		}

		public override string GetSecondarySkillName()
		{
			return "Attach to ceiling";
		}
	}
	internal class FlowermanEnemyController : EnemyController
	{
		private FlowermanAI flowermanAI;

		private const int FLOWERMAN_DEFAULT_MODE = 0;

		private const int FLOWERMAN_STAND_MODE = 1;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			flowermanAI = (FlowermanAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				((EnemyAI)flowermanAI).SwitchToBehaviourState(1);
			}
		}

		public override void ReleaseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				((EnemyAI)flowermanAI).SwitchToBehaviourState(0);
			}
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && flowermanAI.carryingPlayerBody)
			{
				flowermanAI.Call("DropPlayerBody");
				flowermanAI.DropPlayerBodyServerRpc();
			}
		}

		public override string GetPrimarySkillName()
		{
			if (!flowermanAI.carryingPlayerBody)
			{
				return "";
			}
			return "Drop body";
		}

		public override string GetSecondarySkillName()
		{
			return "";
		}
	}
	internal class ForestGiantEnemyController : EnemyController
	{
		private ForestGiantAI forestGiantAI;

		private const int FOREST_GIANT_DEFAULT_MODE = 0;

		private const int FOREST_GIANT_CHASE_MODE = 1;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			forestGiantAI = (ForestGiantAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		protected override void Update()
		{
			base.Update();
			bool flag = IsEatingPlayer();
			controlEnemyRotation = !flag;
			controlEnemyMovement = !flag;
		}

		protected override void Move()
		{
			if (!IsEatingPlayer())
			{
				base.Move();
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			_ = isAIControlled;
		}

		public override void ReleaseSecondarySkill()
		{
			CheckInitialized();
			_ = isAIControlled;
		}

		public override string GetSecondarySkillName()
		{
			return "";
		}

		public bool IsEatingPlayer()
		{
			return forestGiantAI.GetFieldValue<bool>("inEatingPlayerAnimation");
		}
	}
	internal class HoardingBugEnemyController : EnemyController
	{
		private HoarderBugAI hoarderBugAI;

		private List<Type> allowedGrabbableItemUse = new List<Type>
		{
			typeof(ShotgunItem),
			typeof(NoisemakerProp),
			typeof(FlashlightItem)
		};

		private float grabRange = 1.5f;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			hoarderBugAI = (HoarderBugAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		protected override void EnableAIControl(bool enabled)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (enabled)
			{
				hoarderBugAI.Call("ChooseNestPosition");
				((EnemyAI)hoarderBugAI).SwitchToBehaviourState(0);
			}
			else
			{
				hoarderBugAI.nestPosition = new Vector3(2000f, 2000f, 2000f);
			}
			base.EnableAIControl(enabled);
		}

		protected override void Update()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (isInitialized)
			{
				base.Update();
				if (!isAIControlled)
				{
					hoarderBugAI.nestPosition = new Vector3(2000f, 2000f, 2000f);
				}
			}
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && hoarderBugAI.heldItem != null)
			{
				UseHeldItem();
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				ControlCompanyPlugin.Instance.logger.LogMessage((object)"Using hoarder bug secondary");
				if (hoarderBugAI.heldItem == null)
				{
					GrabNearbyItem();
				}
				else
				{
					DropCurrentItem();
				}
			}
		}

		public void UseHeldItem()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject itemGrabbableObject = hoarderBugAI.heldItem.itemGrabbableObject;
			Type type = ((object)itemGrabbableObject).GetType();
			if (allowedGrabbableItemUse.Contains(type))
			{
				if (type == typeof(ShotgunItem))
				{
					ShotgunItem val = (ShotgunItem)itemGrabbableObject;
					val.gunShootAudio.volume = 0.15f;
					val.shotgunRayPoint = enemyGameObject.transform;
					val.ShootGunAndSync(false);
				}
				else
				{
					itemGrabbableObject.UseItemOnClient(true);
				}
			}
		}

		public void GrabNearbyItem()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (hoarderBugAI.heldItem != null)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(enemyGameObject.transform.position, grabRange);
			for (int i = 0; i < array.Length; i++)
			{
				GrabbableObject componentInChildren = ((Component)array[i]).GetComponentInChildren<GrabbableObject>();
				if ((Object)(object)componentInChildren != (Object)null && hoarderBugAI.heldItem == null && (Object)(object)((Component)componentInChildren).GetComponent<NetworkObject>() != (Object)null)
				{
					hoarderBugAI.targetItem = componentInChildren;
					hoarderBugAI.Call("GrabTargetItemIfClose");
					break;
				}
			}
		}

		public void DropCurrentItem()
		{
			if (hoarderBugAI.heldItem != null)
			{
				hoarderBugAI.Call("DropItemAndCallDropRPC", ((Component)hoarderBugAI.heldItem.itemGrabbableObject).GetComponent<NetworkObject>(), false);
			}
		}

		public override string GetPrimarySkillName()
		{
			if (hoarderBugAI.heldItem == null || !allowedGrabbableItemUse.Contains(((object)hoarderBugAI.heldItem).GetType()))
			{
				return "";
			}
			return "Use item";
		}

		public override string GetSecondarySkillName()
		{
			if (hoarderBugAI.heldItem != null)
			{
				return "Drop item";
			}
			return "Grab item";
		}
	}
	internal class JesterEnemyController : EnemyController
	{
		private JesterAI jesterEnemyAI;

		private const int JESTER_DEFAULT_MODE = 0;

		private const int JESTER_CRANK_MODE_INDEX = 1;

		private const int JESTER_POP_OUT_INDEX = 2;

		private float initialWalkSpeed;

		private float initialRunSpeed;

		private bool initialControlRotation;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			jesterEnemyAI = (JesterAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
			initialWalkSpeed = base.WalkSpeed;
			initialRunSpeed = base.RunSpeed;
			initialControlRotation = controlEnemyRotation;
		}

		protected override void Update()
		{
			base.Update();
			if (IsCranking())
			{
				controlEnemyMovement = false;
				controlEnemyRotation = false;
			}
			else if (IsPoppedOut() || IsInBox())
			{
				controlEnemyMovement = initialControlRotation;
				controlEnemyRotation = initialControlRotation;
			}
			if (IsPoppedOut())
			{
				base.WalkSpeed = 10f;
				base.RunSpeed = 15f;
			}
			else if (IsInBox())
			{
				base.WalkSpeed = initialWalkSpeed;
				base.RunSpeed = initialRunSpeed;
			}
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && !IsInBox())
			{
				ResetState();
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && IsInBox())
			{
				Cranking();
			}
		}

		public override void ReleaseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && IsCranking())
			{
				PopOut();
			}
		}

		protected override void Move()
		{
			if (!IsCranking())
			{
				base.Move();
			}
		}

		public override string GetPrimarySkillName()
		{
			return "Close box";
		}

		public override string GetSecondarySkillName()
		{
			return "(HOLD) Play music";
		}

		private void Cranking()
		{
			SwitchAIState(1);
		}

		private void PopOut()
		{
			SwitchAIState(2);
		}

		private void ResetState()
		{
			SwitchAIState(0);
		}

		private bool IsInBox()
		{
			return ((EnemyAI)jesterEnemyAI).currentBehaviourStateIndex == 0;
		}

		private bool IsCranking()
		{
			return ((EnemyAI)jesterEnemyAI).currentBehaviourStateIndex == 1;
		}

		private bool IsPoppedOut()
		{
			return ((EnemyAI)jesterEnemyAI).currentBehaviourStateIndex == 2;
		}
	}
	internal class MouthDogEnemyController : EnemyController
	{
		private MouthDogAI mouthDogAI;

		private const int MOUTH_DOG_LUNGE = 2;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			mouthDogAI = (MouthDogAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && !IsLunging())
			{
				Lunge();
			}
		}

		public override string GetSecondarySkillName()
		{
			return "Lunge";
		}

		private void Lunge()
		{
			((EnemyAI)mouthDogAI).SwitchToBehaviourState(2);
		}

		private bool IsLunging()
		{
			return ((EnemyAI)mouthDogAI).currentBehaviourStateIndex == 2;
		}
	}
	internal class NutcrackerEnemyController : EnemyController
	{
		private NutcrackerEnemyAI nutcrackerEnemyAI;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			nutcrackerEnemyAI = (NutcrackerEnemyAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		protected override void Update()
		{
			if (isInitialized)
			{
				base.Update();
				if (!isAIControlled && IsMoving() && ((EnemyAI)nutcrackerEnemyAI).currentBehaviourStateIndex != 0)
				{
					((EnemyAI)nutcrackerEnemyAI).SwitchToBehaviourState(0);
				}
			}
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled && (Object)(object)nutcrackerEnemyAI.gun != (Object)null)
			{
				nutcrackerEnemyAI.gun.gunShootAudio.volume = 0.15f;
				nutcrackerEnemyAI.FireGunServerRpc();
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				SwitchAIState(1);
			}
		}

		public override void ReleaseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				SwitchAIState(0);
			}
		}

		public override void DestroyAndCleanUp()
		{
			if (!((EnemyAI)nutcrackerEnemyAI).isEnemyDead)
			{
				Object.Destroy((Object)(object)((Component)nutcrackerEnemyAI.gun).gameObject);
			}
			base.DestroyAndCleanUp();
		}

		public override string GetPrimarySkillName()
		{
			return "Fire";
		}

		public override string GetSecondarySkillName()
		{
			return "(HOLD) Sentry mode";
		}
	}
	internal class PufferEnemyController : EnemyController
	{
		private PufferAI pufferAI;

		public override void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			pufferAI = (PufferAI)GetEnemyAIFromEnemyGameObject(enemyGameObject);
			base.InitializeEnemyController(playerActions, enemyGameObject);
		}

		public override void UsePrimarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				if (((EnemyAI)pufferAI).currentBehaviourStateIndex != 1)
				{
					SwitchAIState(1);
				}
				pufferAI.StompServerRpc();
			}
		}

		public override void UseSecondarySkill()
		{
			CheckInitialized();
			if (!isAIControlled)
			{
				if (((EnemyAI)pufferAI).currentBehaviourStateIndex != 1)
				{
					SwitchAIState(1);
				}
				pufferAI.ShakeTailServerRpc();
			}
		}

		public override string GetPrimarySkillName()
		{
			return "Stomp";
		}

		public override string GetSecondarySkillName()
		{
			return "Smoke";
		}
	}
}
namespace ControlCompany.Core.Config
{
	internal class ConfigManager : MonoBehaviour
	{
		public static ConfigManager Instance;

		private ConfigFile config;

		private bool isInitialized;

		private const string KEYBIND_CONFIG = "Keybinds";

		private const string KEYBIND_CONFIG_HOST_MODE = "Keybinds.PlayerMode";

		private const string KEYBIND_CONFIG_GHOST_MODE = "Keybinds.GhostMode";

		private const string KEYBIND_CONFIG_ENEMY_MODE = "Keybinds.MonsterMode";

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
		}

		public void Initialize(ConfigFile config)
		{
			if (!isInitialized)
			{
				this.config = config;
				isInitialized = true;
			}
		}

		public void LoadPlayerKeybinds()
		{
			if (config != null)
			{
				LoadKeysFromConfig(config);
			}
		}

		private void LoadKeysFromConfig(ConfigFile config)
		{
			ConfigEntry<string> keyEntry = config.Bind<string>("Keybinds", "extended_mode_key", "0", (ConfigDescription)null);
			ConfigEntry<string> keyEntry2 = config.Bind<string>("Keybinds", "exit_mode_key", "esc", (ConfigDescription)null);
			ConfigEntry<string> keyEntry3 = config.Bind<string>("Keybinds", "open_door", "e", (ConfigDescription)null);
			ConfigEntry<string> keyEntry4 = config.Bind<string>("Keybinds", "toggle_ui", "u", (ConfigDescription)null);
			InputKeys.CONTROLLER_USE_KEY = GetKeyControlFromConfig(keyEntry3, InputKeys.CONTROLLER_USE_KEY);
			InputKeys.EXTENDED_MODE_KEY = GetKeyControlFromConfig(keyEntry, InputKeys.EXTENDED_MODE_KEY);
			InputKeys.EXIT_KEY = GetKeyControlFromConfig(keyEntry2, InputKeys.EXIT_KEY);
			InputKeys.TOGGLE_UI_KEY = GetKeyControlFromConfig(keyEntry4, InputKeys.TOGGLE_UI_KEY);
			ConfigEntry<string> keyEntry5 = config.Bind<string>("Keybinds.PlayerMode", "ghost_mode_key", "f1", (ConfigDescription)null);
			ConfigEntry<string> keyEntry6 = config.Bind<string>("Keybinds.PlayerMode", "cycle_target_left_key", "o", (ConfigDescription)null);
			ConfigEntry<string> keyEntry7 = config.Bind<string>("Keybinds.PlayerMode", "cycle_target_right_key", "p", (ConfigDescription)null);
			InputKeys.HOST_GHOST_MODE_KEY = GetKeyControlFromConfig(keyEntry5, InputKeys.HOST_GHOST_MODE_KEY);
			InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_LEFT = GetKeyControlFromConfig(keyEntry6, InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_LEFT);
			InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_RIGHT = GetKeyControlFromConfig(keyEntry7, InputKeys.HOST_CYCLE_PLAYER_TARGET_LIST_KEY_RIGHT);
			ConfigEntry<string> keyEntry8 = config.Bind<string>("Keybinds.PlayerMode", "extended_teleport_to_entrance_key", "9", (ConfigDescription)null);
			InputKeys.HOST_TELEPORT_TO_ENTRANCE_KEY = GetKeyControlFromConfig(keyEntry8, InputKeys.HOST_TELEPORT_TO_ENTRANCE_KEY);
			ConfigEntry<string> keyEntry9 = config.Bind<string>("Keybinds.GhostMode", "jump", "space", (ConfigDescription)null);
			InputKeys.CONTROLLER_JUMP_KEY = GetKeyControlFromConfig(keyEntry9, InputKeys.CONTROLLER_JUMP_KEY);
			ConfigEntry<string> keyEntry10 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_1", "f1", (ConfigDescription)null);
			ConfigEntry<string> keyEntry11 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_2", "f2", (ConfigDescription)null);
			ConfigEntry<string> keyEntry12 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_3", "f3", (ConfigDescription)null);
			ConfigEntry<string> keyEntry13 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_4", "f4", (ConfigDescription)null);
			ConfigEntry<string> keyEntry14 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_5", "f5", (ConfigDescription)null);
			ConfigEntry<string> keyEntry15 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_6", "f6", (ConfigDescription)null);
			ConfigEntry<string> keyEntry16 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_7", "f7", (ConfigDescription)null);
			ConfigEntry<string> keyEntry17 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_8", "f8", (ConfigDescription)null);
			ConfigEntry<string> keyEntry18 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_9", "f9", (ConfigDescription)null);
			ConfigEntry<string> keyEntry19 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_10", "f10", (ConfigDescription)null);
			ConfigEntry<string> keyEntry20 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_11", "f11", (ConfigDescription)null);
			ConfigEntry<string> keyEntry21 = config.Bind<string>("Keybinds.GhostMode", "control_enemy_12", "f12", (ConfigDescription)null);
			InputKeys.GHOST_SPAWN_ENEMY_1 = GetKeyControlFromConfig(keyEntry10, InputKeys.GHOST_SPAWN_ENEMY_1);
			InputKeys.GHOST_SPAWN_ENEMY_2 = GetKeyControlFromConfig(keyEntry11, InputKeys.GHOST_SPAWN_ENEMY_2);
			InputKeys.GHOST_SPAWN_ENEMY_3 = GetKeyControlFromConfig(keyEntry12, InputKeys.GHOST_SPAWN_ENEMY_3);
			InputKeys.GHOST_SPAWN_ENEMY_4 = GetKeyControlFromConfig(keyEntry13, InputKeys.GHOST_SPAWN_ENEMY_4);
			InputKeys.GHOST_SPAWN_ENEMY_5 = GetKeyControlFromConfig(keyEntry14, InputKeys.GHOST_SPAWN_ENEMY_5);
			InputKeys.GHOST_SPAWN_ENEMY_6 = GetKeyControlFromConfig(keyEntry15, InputKeys.GHOST_SPAWN_ENEMY_6);
			InputKeys.GHOST_SPAWN_ENEMY_7 = GetKeyControlFromConfig(keyEntry16, InputKeys.GHOST_SPAWN_ENEMY_7);
			InputKeys.GHOST_SPAWN_ENEMY_8 = GetKeyControlFromConfig(keyEntry17, InputKeys.GHOST_SPAWN_ENEMY_8);
			InputKeys.GHOST_SPAWN_ENEMY_9 = GetKeyControlFromConfig(keyEntry18, InputKeys.GHOST_SPAWN_ENEMY_9);
			InputKeys.GHOST_SPAWN_ENEMY_10 = GetKeyControlFromConfig(keyEntry19, InputKeys.GHOST_SPAWN_ENEMY_10);
			InputKeys.GHOST_SPAWN_ENEMY_11 = GetKeyControlFromConfig(keyEntry20, InputKeys.GHOST_SPAWN_ENEMY_11);
			InputKeys.GHOST_SPAWN_ENEMY_12 = GetKeyControlFromConfig(keyEntry21, InputKeys.GHOST_SPAWN_ENEMY_12);
			InputKeys.GHOST_SPAWN_ENEMY_KEYS = new List<KeyControl>
			{
				InputKeys.GHOST_SPAWN_ENEMY_1,
				InputKeys.GHOST_SPAWN_ENEMY_2,
				InputKeys.GHOST_SPAWN_ENEMY_3,
				InputKeys.GHOST_SPAWN_ENEMY_4,
				InputKeys.GHOST_SPAWN_ENEMY_5,
				InputKeys.GHOST_SPAWN_ENEMY_6,
				InputKeys.GHOST_SPAWN_ENEMY_7,
				InputKeys.GHOST_SPAWN_ENEMY_8,
				InputKeys.GHOST_SPAWN_ENEMY_9,
				InputKeys.GHOST_SPAWN_ENEMY_10,
				InputKeys.GHOST_SPAWN_ENEMY_11,
				InputKeys.GHOST_SPAWN_ENEMY_12
			};
			ConfigEntry<string> keyEntry22 = config.Bind<string>("Keybinds.MonsterMode", "toggle_ai_key", "f1", (ConfigDescription)null);
			InputKeys.ENEMY_TOGGLE_AI_KEY = GetKeyControlFromConfig(keyEntry22, InputKeys.ENEMY_TOGGLE_AI_KEY);
		}

		private KeyControl GetKeyControlFromConfig(ConfigEntry<string> keyEntry, KeyControl defaultKey)
		{
			try
			{
				KeyControl val = Keyboard.current.FindKeyOnCurrentKeyboardLayout(keyEntry.Value);
				if (val != null)
				{
					return val;
				}
				return defaultKey;
			}
			catch (Exception ex)
			{
				ControlCompanyPlugin.Instance.logger.LogError((object)("Cannot rebind key for " + ((ConfigEntryBase)keyEntry).Definition.Key + " to " + keyEntry.Value + ": " + ex.Message));
				return defaultKey;
			}
		}
	}
	public class EnemyAttributes
	{
		public float WalkSpeed { get; set; } = 5f;


		public float RunSpeed { get; set; } = 7f;


		public bool PlayerControlsRotation { get; set; } = true;


		public float CamHeight { get; set; } = 2f;


		public float CamDistance { get; set; } = -3.5f;


		public string EnemyName { get; set; } = "";

	}
	internal static class EnemyConfiguration
	{
		public static HashSet<Type> ALLOWLISTED_ENEMIES = new HashSet<Type>
		{
			typeof(BlobAI),
			typeof(NutcrackerEnemyAI),
			typeof(HoarderBugAI),
			typeof(CrawlerAI),
			typeof(PufferAI),
			typeof(CentipedeAI),
			typeof(JesterAI),
			typeof(ForestGiantAI),
			typeof(BaboonBirdAI),
			typeof(FlowermanAI)
		};

		public static HashSet<Type> EXPERIMENTAL_ENEMIES = new HashSet<Type> { typeof(MouthDogAI) };

		public const float DEFAULT_WALK_SPEED = 5f;

		public const float DEFAULT_RUN_SPEED = 7f;

		public const float DEFAULT_CAM_DISTANCE = -3.5f;

		public const float DEFAULT_CAM_HEIGHT = 2f;

		public const bool DEFAULT_PLAYER_CONTROLS_ROTATION = true;

		public static Dictionary<Type, EnemyAttributes> ENEMY_ATTRIBUTES = new Dictionary<Type, EnemyAttributes>
		{
			{
				typeof(BlobAI),
				new EnemyAttributes
				{
					WalkSpeed = 2f,
					RunSpeed = 2f,
					PlayerControlsRotation = false,
					EnemyName = "Blob"
				}
			},
			{
				typeof(CrawlerAI),
				new EnemyAttributes
				{
					WalkSpeed = 6f,
					RunSpeed = 12f,
					EnemyName = "Thumper"
				}
			},
			{
				typeof(JesterAI),
				new EnemyAttributes
				{
					WalkSpeed = 4f,
					RunSpeed = 6f,
					EnemyName = "Jester"
				}
			},
			{
				typeof(ForestGiantAI),
				new EnemyAttributes
				{
					WalkSpeed = 5f,
					RunSpeed = 7f,
					CamDistance = -7f,
					CamHeight = 10f,
					EnemyName = "Forest Keeper"
				}
			},
			{
				typeof(MouthDogAI),
				new EnemyAttributes
				{
					WalkSpeed = 4f,
					RunSpeed = 8f,
					CamDistance = -5f,
					CamHeight = 5f,
					EnemyName = "Eyeless Dog"
				}
			},
			{
				typeof(FlowermanAI),
				new EnemyAttributes
				{
					EnemyName = "Bracken",
					RunSpeed = 8f
				}
			},
			{
				typeof(PufferAI),
				new EnemyAttributes
				{
					EnemyName = "Spore Lizard"
				}
			},
			{
				typeof(HoarderBugAI),
				new EnemyAttributes
				{
					EnemyName = "Hoarding Bug"
				}
			},
			{
				typeof(CentipedeAI),
				new EnemyAttributes
				{
					EnemyName = "Snare Flea",
					CamHeight = 1.5f,
					CamDistance = -3f
				}
			},
			{
				typeof(SpringManAI),
				new EnemyAttributes
				{
					EnemyName = "Coil-Head"
				}
			},
			{
				typeof(SandSpiderAI),
				new EnemyAttributes
				{
					EnemyName = "Bunker Spider"
				}
			},
			{
				typeof(DressGirlAI),
				new EnemyAttributes
				{
					EnemyName = "Ghost Girl"
				}
			},
			{
				typeof(MaskedPlayerEnemy),
				new EnemyAttributes
				{
					EnemyName = "Masked"
				}
			}
		};

		private static readonly EnemyAttributes DEFAULT_ATTRIBUTES = new EnemyAttributes();

		public static Dictionary<Type, Func<GameObject, EnemyController>> ENEMY_CONTROLLERS = new Dictionary<Type, Func<GameObject, EnemyController>>
		{
			{
				typeof(NutcrackerEnemyAI),
				(GameObject controller) => controller.AddComponent<NutcrackerEnemyController>()
			},
			{
				typeof(CentipedeAI),
				(GameObject controller) => controller.AddComponent<CentipedeEnemyController>()
			},
			{
				typeof(PufferAI),
				(GameObject controller) => controller.AddComponent<PufferEnemyController>()
			},
			{
				typeof(JesterAI),
				(GameObject controller) => controller.AddComponent<JesterEnemyController>()
			},
			{
				typeof(ForestGiantAI),
				(GameObject controller) => controller.AddComponent<ForestGiantEnemyController>()
			},
			{
				typeof(MouthDogAI),
				(GameObject controller) => controller.AddComponent<MouthDogEnemyController>()
			},
			{
				typeof(HoarderBugAI),
				(GameObject controller) => controller.AddComponent<HoardingBugEnemyController>()
			},
			{
				typeof(FlowermanAI),
				(GameObject controller) => controller.AddComponent<FlowermanEnemyController>()
			}
		};

		public static EnemyAttributes GetEnemyAttributes(this EnemyAI enemyAI)
		{
			return ExtensionMethods.GetValueOrDefault(ENEMY_ATTRIBUTES, ((object)enemyAI).GetType(), DEFAULT_ATTRIBUTES);
		}

		public static bool IsEnemyAllowlisted(this EnemyAI enemyAI)
		{
			return ALLOWLISTED_ENEMIES.Contains(((object)enemyAI).GetType());
		}

		public static bool IsEnemyExperimental(this EnemyAI enemyAI)
		{
			return EXPERIMENTAL_ENEMIES.Contains(((object)enemyAI).GetType());
		}

		public static string GetEnemyName(this EnemyAI enemyAI)
		{
			EnemyAttributes valueOrDefault = ExtensionMethods.GetValueOrDefault(ENEMY_ATTRIBUTES, ((object)enemyAI).GetType(), null);
			if (valueOrDefault == null)
			{
				return enemyAI.enemyType.enemyName;
			}
			return valueOrDefault.EnemyName;
		}

		public static EnemyController GetAndAttachEnemyController(this EnemyAI enemyAI, GameObject controller)
		{
			return ExtensionMethods.GetValueOrDefault(ENEMY_CONTROLLERS, ((object)enemyAI).GetType(), (GameObject c) => c.AddComponent<EnemyController>())(controller);
		}
	}
}