Decompiled source of Unified Chaos Pack v0.0.15

BepInEx/plugins/TeamChaos.UnifiedChaosPack.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Lib;
using CSync.Util;
using FacilityMeltdown;
using GameNetcodeStuff;
using HarmonyLib;
using JetBrains.Annotations;
using LCSoundTool;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using Microsoft.CodeAnalysis;
using MoreShipUpgrades.Managers;
using Newtonsoft.Json;
using TMPro;
using TeamChaos.UnifiedChaosPack.Config;
using TeamChaos.UnifiedChaosPack.NetcodePatcher;
using TeamChaos.UnifiedChaosPack.NetworkBehaviors;
using TeamChaos.UnifiedChaosPack.PluginManagers;
using TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus;
using TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus.Coroutines;
using TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus.EventBrokers;
using TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus.Notifiers;
using TeamChaos.UnifiedChaosPack.Schema;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("Pirahtays")]
[assembly: AssemblyConfiguration("release")]
[assembly: AssemblyDescription("Unified Mod Pack / Tweaks created by Pirahtays")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("TeamChaos.UnifiedChaosPack")]
[assembly: AssemblyTitle("TeamChaos.UnifiedChaosPack")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 TeamChaos.UnifiedChaosPack
{
	public static class GeneralLethalPatches
	{
		private static Harmony HarmonyInstance { get; } = new Harmony(Guid.NewGuid().ToString());


		private static List<T> FindByName<T>(Func<IEnumerable<T>> selector, params string[] names) where T : MemberInfo
		{
			return (from o in selector()
				where names.Contains(o.Name)
				select o).ToList();
		}

		public static List<ConstructorInfo> FindConstructorsByName(Type type, params string[] methodNames)
		{
			return FindByName(() => AccessTools.GetDeclaredConstructors(type, (bool?)null), methodNames);
		}

		public static List<MethodInfo> FindMethodsByName(Type type, params string[] methodNames)
		{
			return FindByName(() => AccessTools.GetDeclaredMethods(type), methodNames);
		}

		public static List<PropertyInfo> FindPropertiesByName(Type type, params string[] methodNames)
		{
			return FindByName(() => AccessTools.GetDeclaredProperties(type), methodNames);
		}

		public static void PatchMethods(GeneralConfig config)
		{
		}

		public static bool __AnnoyingLogStopper()
		{
			return false;
		}
	}
	public static class PluginPackageInfo
	{
		public const string PLUGIN_GUID = "TeamChaos.UnifiedChaosPack";

		public const string PLUGIN_NAME = "UnifiedChaosPack";

		public const string PLUGIN_VERSION = "0.0.1";
	}
	[BepInPlugin("TeamChaos.UnifiedChaosPack", "UnifiedChaosPack", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class UnifiedChaosPlugin : BaseUnityPlugin
	{
		private const string DEPENDENCY_CSYNC = "com.sigurd.csync";

		private const string DEPENDENCY_LCSOUNDTOOL = "LCSoundTool";

		private const string DEPENDENCY_LETHALCONFIG = "ainavt.lc.lethalconfig";

		public const string DEPENDENCY_LGU = "com.malco.lethalcompany.moreshipupgrades";

		private const string DEPENDENCY_FACILITY_MELTDOWN = "me.loaforc.facilitymeltdown";

		private readonly GeneralConfig _config = new GeneralConfig();

		private readonly Dictionary<Type, UnifiedChaosPluginManager> _pluginMap = new Dictionary<Type, UnifiedChaosPluginManager>();

		private GameObject _gameObject;

		public AssetBundle UnityAssetBundle { get; }

		public static GeneralConfig GeneralConfig => Instance._config;

		public static UnifiedChaosPlugin Instance { get; private set; }

		public UnifiedChaosPlugin()
		{
			Instance = this;
			UnityAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "unifiedchaospack"));
		}

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin TeamChaos.UnifiedChaosPack is initializing!");
			NetcodePatcher();
			_gameObject = new GameObject("TeamChaos.UnifiedChaosPack");
			_config.Init();
			GeneralLethalPatches.PatchMethods(_config);
			UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Create(this);
			UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Create(this);
			UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>.Create(this);
			((Object)_gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_gameObject);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin TeamChaos.UnifiedChaosPack is loaded!");
		}

		public T GetPlugin<T>() where T : UnifiedChaosPluginManager
		{
			Type typeFromHandle = typeof(T);
			if (!_pluginMap.ContainsKey(typeFromHandle))
			{
				T val = (((Object)(object)_gameObject != (Object)null) ? _gameObject.GetComponent<T>() : null);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				_pluginMap.Add(typeFromHandle, val);
			}
			return (T)_pluginMap[typeFromHandle];
		}

		public T RegisterPlugin<T>() where T : UnifiedChaosPluginManager
		{
			Type typeFromHandle = typeof(T);
			if (!_pluginMap.ContainsKey(typeFromHandle))
			{
				_pluginMap.Remove(typeFromHandle);
			}
			return _gameObject.AddComponent<T>();
		}

		public void Log(LogLevel logLevel, string callingPlugin, string message, bool verboseOnly = false)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!verboseOnly || GeneralConfig.IsVerboseLogging)
			{
				((BaseUnityPlugin)this).Logger.Log(logLevel, (object)("[UnifiedChaos::" + callingPlugin + "]:" + message));
			}
		}

		public void LogDebug(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)32, callingPlugin, message, verboseOnly);
		}

		public void LogMessage(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)8, callingPlugin, message, verboseOnly);
		}

		public void LogAll(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)63, callingPlugin, message, verboseOnly);
		}

		public void LogError(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)2, callingPlugin, message, verboseOnly);
		}

		public void LogFatal(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)1, callingPlugin, message, verboseOnly);
		}

		public void LogInfo(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)16, callingPlugin, message, verboseOnly);
		}

		public void LogNone(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)0, callingPlugin, message, verboseOnly);
		}

		public void LogWarning(string callingPlugin, string message, bool verboseOnly = false)
		{
			Log((LogLevel)4, callingPlugin, message, verboseOnly);
		}

		private void NetcodePatcher()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						Instance.LogDebug(((object)this).GetType().Name, "NetcodePatcher - Invoking " + methodInfo.DeclaringType.Name + "::" + methodInfo.Name + " ");
						methodInfo.Invoke(null, null);
						MethodInfo methodInfo2 = AccessTools.FindIncludingBaseTypes<MethodInfo>(methodInfo.DeclaringType, (Func<Type, MethodInfo>)((Type t) => t.GetMethod("Patch")));
						if (!(methodInfo2 == null))
						{
							Instance.LogDebug(((object)this).GetType().Name, "NetcodePatcher - Patching " + methodInfo.DeclaringType.Name + "(" + methodInfo2.DeclaringType.Name + ")::" + methodInfo2.Name + " ");
							methodInfo2.Invoke(null, null);
						}
					}
				}
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "TeamChaos.UnifiedChaosPack";

		public const string PLUGIN_NAME = "TeamChaos.UnifiedChaosPack";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}
namespace TeamChaos.UnifiedChaosPack.Schema
{
	public class AudioFileInfo
	{
		[JsonProperty(PropertyName = "file")]
		[CanBeNull]
		public string Filename { get; set; }

		[JsonProperty(PropertyName = "chance")]
		public int Chance { get; set; } = 100;


		[JsonProperty(PropertyName = "is-silence")]
		public bool IsSilence { get; set; }

		[JsonProperty(PropertyName = "is-default")]
		public bool IsDefault { get; set; }
	}
	public class AudioMetadata
	{
		[JsonRequired]
		[JsonProperty(PropertyName = "type")]
		public string Type { get; set; }

		[JsonRequired]
		[JsonProperty(PropertyName = "field")]
		public string Field { get; set; }

		[JsonProperty(PropertyName = "exclusive")]
		public bool IsPlayerExclusive { get; set; }

		[JsonRequired]
		[JsonProperty(PropertyName = "replacement-file-data")]
		public List<AudioFileInfo> AudioFileInfo { get; set; } = new List<AudioFileInfo>();

	}
	public class AudioMetadataCollection
	{
		private const string BASE_FILENAME = "sound-data";

		private readonly Dictionary<ulong, List<PlayerSpecificAudioMetadata>> _playerSpecificData;

		private List<AudioMetadata> _defaultAudioMetadata;

		private AudioMetadataCollection()
		{
			_defaultAudioMetadata = Enumerable.Empty<AudioMetadata>().ToList();
			_playerSpecificData = new Dictionary<ulong, List<PlayerSpecificAudioMetadata>>();
		}

		public void Dump()
		{
			UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", $"Dumping all AudioMetadata - _default:{_defaultAudioMetadata.Count}, _playerSpecific:{_playerSpecificData.SelectMany((KeyValuePair<ulong, List<PlayerSpecificAudioMetadata>> p) => p.Value).Count()}");
			IEnumerable<IGrouping<(string, string), (ulong?, AudioMetadata)>> enumerable = from a in _playerSpecificData.SelectMany((KeyValuePair<ulong, List<PlayerSpecificAudioMetadata>> d) => ((IEnumerable<PlayerSpecificAudioMetadata>)d.Value).Select((Func<PlayerSpecificAudioMetadata, (ulong?, AudioMetadata)>)((PlayerSpecificAudioMetadata i) => (d.Key, i)))).Union(((IEnumerable<AudioMetadata>)_defaultAudioMetadata).Select((Func<AudioMetadata, (ulong?, AudioMetadata)>)((AudioMetadata d) => (null, d))))
				group a by (a.Value.Field, a.Value.Type);
			foreach (IGrouping<(string, string), (ulong?, AudioMetadata)> item in enumerable)
			{
				UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", "Audio Metadata " + item.Key.Item2 + "::" + item.Key.Item1);
				foreach (var item2 in item)
				{
					foreach (AudioFileInfo item3 in item2.Item2.AudioFileInfo)
					{
						string message = ((!(item2.Item2 is PlayerSpecificAudioMetadata)) ? $"\t Available files: {item3.Filename}[{item3.Chance}] - Default:{item3.IsDefault}, Silent:{item3.IsSilence}" : $"\t Available files[{item2.Item1}]: {item3.Filename}[{item3.Chance}] - Default:{item3.IsDefault}, Silent:{item3.IsSilence}, IsExclusive:{item2.Item2.IsPlayerExclusive}");
						UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", message);
					}
				}
			}
		}

		public void Dump<T>(string field, ulong? playerId = null)
		{
			List<AudioFileInfo> filteredData = GetFilteredData<T>(field, playerId);
			UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", $"Dumping filtered AudioMetadata - _data:{filteredData.Count}");
			foreach (AudioFileInfo item in filteredData)
			{
				UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", "Audio Metadata " + typeof(T).Name + "::" + field);
				string message = $"\t Available files: {item.Filename}[{item.Chance}] - Default:{item.IsDefault}, Silent:{item.IsSilence}";
				UnifiedChaosPlugin.Instance.LogDebug("AudioMetadataCollection", message);
			}
		}

		public IEnumerable<string> GetAudioIdsToLoad()
		{
			return (from a in _defaultAudioMetadata.SelectMany((AudioMetadata r) => r.AudioFileInfo).Union(_playerSpecificData.Values.SelectMany((List<PlayerSpecificAudioMetadata> r) => r.SelectMany((PlayerSpecificAudioMetadata p) => p.AudioFileInfo)))
				where !string.IsNullOrWhiteSpace(a.Filename)
				select a.Filename).Distinct();
		}

		private static List<T> GetAudioMetadataFromFile<T>(string file) where T : AudioMetadata
		{
			if (!File.Exists(file))
			{
				throw new FileNotFoundException("Json file not found!", file);
			}
			string text = File.ReadAllText(file);
			return JsonConvert.DeserializeObject<List<T>>(text);
		}

		public List<AudioFileInfo> GetFilteredData<T>(string field, ulong? playerId = null)
		{
			string type = typeof(T).Name;
			IEnumerable<AudioFileInfo> enumerable = _defaultAudioMetadata.FirstOrDefault((AudioMetadata a) => a.Field == field && a.Type == type)?.AudioFileInfo;
			IEnumerable<AudioFileInfo> enumerable2 = enumerable ?? Enumerable.Empty<AudioFileInfo>();
			if (playerId.HasValue && _playerSpecificData.ContainsKey(playerId.Value))
			{
				PlayerSpecificAudioMetadata playerSpecificAudioMetadata = _playerSpecificData[playerId.Value].FirstOrDefault((PlayerSpecificAudioMetadata a) => a.Field == field && a.Type == type);
				enumerable = playerSpecificAudioMetadata?.AudioFileInfo;
				IEnumerable<AudioFileInfo> enumerable3 = enumerable ?? Enumerable.Empty<AudioFileInfo>();
				enumerable2 = ((playerSpecificAudioMetadata != null && playerSpecificAudioMetadata.IsPlayerExclusive) ? enumerable3 : enumerable2.Union(enumerable3));
			}
			return enumerable2.ToList();
		}

		public static AudioMetadataCollection LoadAudioMetadataCollection(string path)
		{
			Regex regex = new Regex("sound-data\\.?(\\d+)*\\.json");
			DirectoryInfo directoryInfo = new DirectoryInfo(path);
			IEnumerable<FileInfo> enumerable = directoryInfo.EnumerateFiles("sound-data*.json");
			AudioMetadataCollection audioMetadataCollection = new AudioMetadataCollection();
			UnifiedChaosPlugin.Instance.LogInfo("AudioMetadataCollection", "[LoadAudioMetadataCollection]: Begin Load from '" + path + "'");
			foreach (FileInfo item in enumerable)
			{
				UnifiedChaosPlugin.Instance.LogInfo("AudioMetadataCollection", string.Format("[{0}]: Loading file: '{1}'", "LoadAudioMetadataCollection", item));
				if (string.Equals(item.Name, "sound-data.json", StringComparison.InvariantCultureIgnoreCase))
				{
					audioMetadataCollection._defaultAudioMetadata = GetAudioMetadataFromFile<AudioMetadata>(item.FullName);
					continue;
				}
				Group group = regex.Match(item.Name.ToLower())?.Groups[1];
				if (group != null && group.Success && ulong.TryParse(group.Value, out var result))
				{
					List<PlayerSpecificAudioMetadata> audioMetadataFromFile = GetAudioMetadataFromFile<PlayerSpecificAudioMetadata>(item.FullName);
					audioMetadataCollection._playerSpecificData.Add(result, audioMetadataFromFile);
				}
			}
			if (audioMetadataCollection._defaultAudioMetadata.SelectMany((AudioMetadata r) => r.AudioFileInfo).Union(audioMetadataCollection._playerSpecificData.Values.SelectMany((List<PlayerSpecificAudioMetadata> r) => r.SelectMany((PlayerSpecificAudioMetadata p) => p.AudioFileInfo))).Any((AudioFileInfo a) => string.IsNullOrWhiteSpace(a.Filename) && !a.IsSilence && !a.IsDefault))
			{
				UnifiedChaosPlugin.Instance.LogError("AudioMetadataCollection", "Audio Manifest has empty filenames for records not flagged as default or silence!");
			}
			return audioMetadataCollection;
		}
	}
	public class AudioPatchMetadata : AudioMetadata
	{
		[JsonRequired]
		[JsonProperty(PropertyName = "method")]
		public string Method { get; set; }

		[JsonRequired]
		[JsonProperty(PropertyName = "patch-method")]
		public string PatchMethod { get; set; }
	}
	public class PlayerSpecificAudioMetadata : AudioMetadata
	{
		[JsonProperty(PropertyName = "exclusive")]
		public new bool IsPlayerExclusive { get; set; }
	}
}
namespace TeamChaos.UnifiedChaosPack.PluginManagers
{
	public class MoreMobSoundsPluginManager : UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>
	{
		private const string PATCH_DATA_FILE = "sound-data.json";

		private readonly Dictionary<Type, MobPlusPatcher> _patchers = new Dictionary<Type, MobPlusPatcher>();

		private readonly Dictionary<Type, EventBroker> _patchersNew = new Dictionary<Type, EventBroker>();

		private AudioMetadataCollection _audioMetadata;

		protected override string PluginFriendlyName => "MobPlus";

		private EnemyAI GetNetworkEnemyInstance(Type type, ulong id)
		{
			if (!_patchersNew.TryGetValue(type, out var value))
			{
				return null;
			}
			return value?.GetEnemyInstanceByNetworkId(id);
		}

		private void HandlePlayAudioEvent(RandomAudioSyncNetworkHandler.AudioEventArgs e)
		{
			LogWarning(string.Format("[{0}]: {1}:'{2}',  {3}:'{4}',  {5}:'{6}'", "HandlePlayAudioEvent", "SourceType", e.SourceType, "SourceID", e.SourceID, "AudioKey", e.AudioKey));
			EnemyAI networkEnemyInstance = GetNetworkEnemyInstance(e.SourceType, e.SourceID);
			if (!Object.op_Implicit((Object)(object)networkEnemyInstance))
			{
				LogError(string.Format("[{0}]: Enemy instance not found! ({1}:{2})", "HandlePlayAudioEvent", e.SourceType, e.SourceID));
			}
			else if (!e.Fallback)
			{
				HandlePlayAudioEvent(networkEnemyInstance, e.AudioKey);
			}
		}

		private void HandlePlayAudioEvent(EnemyAI ai, string audioKey)
		{
			bool flag = !string.IsNullOrWhiteSpace(audioKey);
			AudioClip preloadedAudioClip;
			if (!flag || !Object.op_Implicit((Object)(object)(preloadedAudioClip = GetPreloadedAudioClip(audioKey))))
			{
				string message = (flag ? ("[HandlePlayAudioEvent]: Audioclip not found/loaded! (" + ((object)ai).GetType().Name + ":" + audioKey + ")") : "[HandlePlayAudioEvent]: Audiokey is null or blank!");
				LogInfo(message);
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(PlayAndWait(ai.creatureVoice, preloadedAudioClip));
			}
		}

		private IEnumerator PlayAndWait(AudioSource audioSource, AudioClip clip)
		{
			AudioSource.PlayOneShotHelper(audioSource, clip, 1f);
			yield return (object)new WaitForSeconds(clip.length);
		}

		private void PlayOneShot<T>(T ai, string field, Action<T> fallback = null, ulong? playerId = null) where T : EnemyAI
		{
			UnifiedChaosPluginNetworkHandler<RandomAudioSyncNetworkHandler>.Instance.PlayRandomOneShot<T>(ai, field, _audioMetadata, (Action<string>)delegate(string audioKey)
			{
				HandlePlayAudioEvent((EnemyAI)(object)ai, audioKey);
			}, fallback, playerId);
		}

		public override void Start()
		{
			_config.Init();
			LogInfo(((object)this).GetType().Name + " Start");
			_audioMetadata = AudioMetadataCollection.LoadAudioMetadataCollection(base.FullSoundPathForPlugin);
			_audioMetadata.Dump();
			LoadAudio(_audioMetadata.GetAudioIdsToLoad());
			_patchersNew.InitEventBroker(EventBroker<HoarderBugAINotifier, HoarderBugAI, HoarderBugEventBroker>.GetInstance(), InitHoarderBugPatches).InitEventBroker(EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>.GetInstance(), InitFlowermanPatches).InitEventBroker(EventBroker<SpringManAINotifier, SpringManAI, SpringManEventBroker>.GetInstance(), InitSpringManPatches);
			UnifiedChaosPluginNetworkHandler<RandomAudioSyncNetworkHandler>.NetworkSpawn += delegate
			{
				UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>.Instance.LogError("Called: NetworkSpawn");
				RandomAudioSyncNetworkHandler.PlayAudioEvent += UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>.Instance.HandlePlayAudioEvent;
			};
			UnifiedChaosPluginNetworkHandler<RandomAudioSyncNetworkHandler>.NetworkDespawn += delegate
			{
				UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>.Instance.LogError("Called: NetworkDespawn");
				RandomAudioSyncNetworkHandler.PlayAudioEvent -= UnifiedChaosPluginManager<MoreMobSoundsPluginManager, MobPlusPluginManagerConfig>.Instance.HandlePlayAudioEvent;
			};
		}

		private void InitBaboonBirdPatches(BaboonBirdExtender obj)
		{
		}

		private void InitBlobPatches(BlobExtender obj)
		{
		}

		private void InitCentipedePatches(CentipedeExtender obj)
		{
		}

		private void InitCrawlerPatches(CrawlerExtender obj)
		{
		}

		private void InitDocileLocustBeesPatches(DocileLocustBeesExtender obj)
		{
		}

		private void InitDoublewingPatches(DoublewingExtender obj)
		{
		}

		private void InitDressGirlPatches(DressGirlExtender obj)
		{
		}

		public void InitFlowermanPatches(FlowermanEventBroker broker)
		{
			broker.AngryAtPlayer += delegate(FlowermanAI ai, PlayerControllerB player)
			{
				PlayOneShot<FlowermanAI>(ai, "AngryAtPlayer", (Action<FlowermanAI>)null, player?.playerSteamId);
			};
			broker.DroppingBody += delegate(FlowermanAI ai, bool isHome)
			{
				PlayOneShot<FlowermanAI>(ai, isHome ? "DroppingBodyAtHome" : "DroppingBody", (Action<FlowermanAI>)null, (ulong?)null);
			};
			broker.EvadingPlayer += delegate(FlowermanAI ai, PlayerControllerB player)
			{
				PlayOneShot<FlowermanAI>(ai, "EvadingPlayer", (Action<FlowermanAI>)null, player?.playerSteamId);
			};
			broker.KilledPlayer += delegate(FlowermanAI ai, bool carryingBody, PlayerControllerB player)
			{
				PlayOneShot<FlowermanAI>(ai, carryingBody ? "KilledPlayerCarryingBody" : "KilledPlayer", (Action<FlowermanAI>)null, player?.playerSteamId);
			};
			broker.StaringDownPlayer += delegate(FlowermanAI ai, PlayerControllerB player)
			{
				PlayOneShot<FlowermanAI>(ai, "StaringDownPlayer", (Action<FlowermanAI>)null, player?.playerSteamId);
			};
		}

		private void InitForestGiantPatches(ForestGiantExtender obj)
		{
		}

		private void InitHoarderBugPatches(HoarderBugEventBroker broker)
		{
			broker.AngryAtPlayer += delegate(HoarderBugAI ai, PlayerControllerB player)
			{
				PlayOneShot<HoarderBugAI>(ai, "AngryAtPlayer", (Action<HoarderBugAI>)null, player?.playerSteamId);
			};
			broker.ChangedWatchingPlayer += delegate(HoarderBugAI ai, PlayerControllerB player)
			{
				PlayOneShot<HoarderBugAI>(ai, "ChangedWatchingPlayer", (Action<HoarderBugAI>)delegate(HoarderBugAI bugAI)
				{
					RoundManager.PlayRandomClip(((EnemyAI)bugAI).creatureVoice, bugAI.chitterSFX, true, 1f, 0, 1000);
				}, player?.playerSteamId);
			};
			broker.ItemDroppedInNest += delegate(HoarderBugAI ai, HoarderBugItem item)
			{
				PlayOneShot<HoarderBugAI>(ai, "ItemDroppedInNest", (Action<HoarderBugAI>)null, (ulong?)null);
			};
			broker.HuntingItem += delegate(HoarderBugAI ai, GrabbableObject item)
			{
				PlayOneShot<HoarderBugAI>(ai, "HuntingItem", (Action<HoarderBugAI>)null, (ulong?)null);
			};
			broker.ItemGrabbed += delegate(HoarderBugAI ai, HoarderBugItem item)
			{
				PlayOneShot<HoarderBugAI>(ai, "ItemGrabbed", (Action<HoarderBugAI>)null, (ulong?)null);
			};
		}

		private void InitJesterPatches(JesterExtender obj)
		{
		}

		private void InitLassoManPatches(LassoManExtender obj)
		{
		}

		private void InitMaskedPlayerEnemyPatches(MaskedPlayerEnemyExtender obj)
		{
		}

		private void InitMouthDogPatches(MouthDogExtender obj)
		{
		}

		private void InitNutcrackerEnemyPatches(NutcrackerEnemyExtender obj)
		{
		}

		private void InitPufferAIPatches(PufferExtender obj)
		{
		}

		private void InitRedLocustBeesPatches(RedLocustBeesExtender obj)
		{
		}

		private void InitSandSpiderPatches(SandSpiderExtender obj)
		{
		}

		private void InitSandWormPatches(SandWormExtender obj)
		{
		}

		private void InitSpringManPatches(SpringManEventBroker broker)
		{
			broker.StaringAtPlayer += delegate(SpringManAI ai, PlayerControllerB player)
			{
				PlayOneShot<SpringManAI>(ai, "StaringAtPlayer", (Action<SpringManAI>)null, player?.playerSteamId);
			};
			broker.StaringAtPlayerForAWhile += delegate(SpringManAI ai, PlayerControllerB player)
			{
				PlayOneShot<SpringManAI>(ai, "StaringAtPlayerForAWhile", (Action<SpringManAI>)null, player?.playerSteamId);
			};
			broker.StaringAtPlayerForALongTime += delegate(SpringManAI ai, PlayerControllerB player)
			{
				PlayOneShot<SpringManAI>(ai, "StaringAtPlayerForALongTime", (Action<SpringManAI>)null, player?.playerSteamId);
			};
		}
	}
	public class MultiSoundReplacePluginManager : UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>
	{
		private const string PATCH_DATA_FILE = "soundpatch.json";

		protected List<AudioPatchMetadata> _replacementData = new List<AudioPatchMetadata>();

		protected override string PluginFriendlyName => "MultiSoundReplacer";

		public override void Start()
		{
			_config.Init();
			LogInfo(((object)this).GetType().Name + " Start");
			LoadDynamicPatchData();
			LoadAudio(GetAudioIdsToLoad());
			DynamicPatch();
		}

		private void LoadDynamicPatchData()
		{
			string path = Path.Combine(base.FullSoundPathForPlugin, "soundpatch.json");
			if (File.Exists(path))
			{
				string text = File.ReadAllText(path);
				_replacementData = JsonConvert.DeserializeObject<List<AudioPatchMetadata>>(text);
			}
		}

		private void DynamicPatch()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			string contents = JsonConvert.SerializeObject((object)_replacementData, (Formatting)1);
			File.WriteAllText(Path.Combine(base.FullSoundPathForPlugin, "debug-test.json"), contents);
			Harmony val = new Harmony(Guid.NewGuid().ToString());
			foreach (var item2 in GetMethodsToPatch())
			{
				string item = item2.PatchMethod;
				if (!(item == "FacilityMeltdownAssetReplace"))
				{
					if (item == "StaticAudioClipArrayReplace")
					{
						StaticAudioClipArrayReplace(item2);
						continue;
					}
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogInfo("MultiSoundReplacePluginManager::DynamicPatch - Patching " + item2.Type + "::" + item2.Method + " with " + item2.PatchMethod);
					Type type = AccessTools.TypeByName(item2.Type);
					MethodInfo methodInfo = AccessTools.Method(type, item2.Method, (Type[])null, (Type[])null);
					MethodInfo method = ((object)this).GetType().GetMethod(item2.PatchMethod);
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogInfo("MultiSoundReplacePluginManager::DynamicPatch - Patching " + item2.Type + "::" + item2.Method + " with " + item2.PatchMethod);
					FacilityMeltdownAssetReplace(item2);
				}
			}
		}

		public static void TestPatch(ref object __instance, MethodBase __originalMethod)
		{
		}

		private IEnumerable<(string Type, string Method, string PatchMethod)> GetMethodsToPatch()
		{
			return _replacementData.Select((AudioPatchMetadata r) => (r.Type, r.Method, r.PatchMethod)).Distinct();
		}

		private IEnumerable<AudioPatchMetadata> GetAudioPatchesForMethod(string type, string method, [CallerMemberName] string patchMethod = null)
		{
			return _replacementData.Where((AudioPatchMetadata r) => r.PatchMethod == patchMethod && r.Type == type && r.Method == method);
		}

		private IEnumerable<string> GetAudioIdsToLoad()
		{
			return _replacementData.SelectMany((AudioPatchMetadata r) => r.AudioFileInfo.Select((AudioFileInfo a) => a.Filename)).Distinct();
		}

		public static void FacilityMeltdownAssetReplace((string Type, string Method, string PatchMethod) methodInfo)
		{
			Type type = AccessTools.TypeByName(methodInfo.Type);
			if (type == null)
			{
				UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + methodInfo.Type + "' was not found - mod may not be installed!");
				return;
			}
			MeltdownPlugin val = AccessTools.StaticFieldRefAccess<MeltdownPlugin>(type, "instance");
			if ((Object)(object)val == (Object)null)
			{
				UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + methodInfo.Type + "' instance was not found - mod may not be installed!");
				return;
			}
			PropertyInfo propertyInfo = AccessTools.Property(type, "assets");
			object value = propertyInfo.GetValue(val);
			foreach (AudioPatchMetadata item in UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetAudioPatchesForMethod(methodInfo.Type, methodInfo.Method, "FacilityMeltdownAssetReplace"))
			{
				UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogWarning("Implementing Patches on " + type.Name + "::" + item.Method);
				Traverse val2 = Traverse.Create(value).Property(methodInfo.Method, (object[])null);
				if (item.AudioFileInfo.Count == 1)
				{
					AudioFileInfo audioFileInfo = item.AudioFileInfo.Single();
					val2.SetValue((object)UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClips(audioFileInfo.Filename, val2.GetValue<AudioClip[]>()));
					continue;
				}
				AudioClip preloadedAudioClip = UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item.AudioFileInfo.OrderByDescending((AudioFileInfo a) => a.Chance).First().Filename);
				val2.SetValue((object)new AudioClip[1] { preloadedAudioClip });
				foreach (AudioFileInfo item2 in item.AudioFileInfo)
				{
					SoundTool.ReplaceAudioClip(preloadedAudioClip, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item2.Filename), (float)item2.Chance / 100f);
				}
			}
		}

		public static void StaticAudioClipArrayReplace((string Type, string Method, string PatchMethod) methodInfo)
		{
			UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogInfo("MultiSoundReplacePluginManager::StaticAudioClipArrayReplace - Patching " + methodInfo.Type + "::" + methodInfo.Method);
			Type type = AccessTools.TypeByName(methodInfo.Type);
			if (type == null)
			{
				UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + methodInfo.Type + "' was not found - mod may not be installed!");
				return;
			}
			foreach (AudioPatchMetadata item in UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetAudioPatchesForMethod(methodInfo.Type, string.Empty, "StaticAudioClipArrayReplace"))
			{
				UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogWarning("Implementing Patches on " + type.Name + "::" + item.Field);
				FieldInfo fieldInfo = AccessTools.Field(type, item.Field);
				if (fieldInfo == null)
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' was not found - mod may be incompatible or not found!");
					break;
				}
				if (fieldInfo.FieldType != typeof(AudioClip[]))
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' is not of type AudioClip[]!");
					break;
				}
				AudioClip[] original = AccessTools.StaticFieldRefAccess<AudioClip[]>(type, item.Field);
				Traverse val = Traverse.Create(type).Field(item.Field);
				if (item.AudioFileInfo.Count == 1)
				{
					AudioFileInfo audioFileInfo = item.AudioFileInfo.Single();
					val.SetValue((object)UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClips(audioFileInfo.Filename, original));
					continue;
				}
				AudioClip preloadedAudioClip = UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item.AudioFileInfo.OrderByDescending((AudioFileInfo a) => a.Chance).First().Filename);
				val.SetValue((object)new AudioClip[1] { preloadedAudioClip });
				foreach (AudioFileInfo item2 in item.AudioFileInfo)
				{
					SoundTool.ReplaceAudioClip(preloadedAudioClip, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item2.Filename), (float)item2.Chance / 100f);
				}
			}
		}

		public static void InstanceAudioClipArrayPatch(ref object __instance, MethodBase __originalMethod)
		{
			Type type = __instance.GetType();
			UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogInfo("MultiSoundReplacePluginManager::InstanceAudioClipArrayPatch - Patching " + type.Name + "::" + __originalMethod.Name);
			foreach (AudioPatchMetadata item in UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetAudioPatchesForMethod(type.Name, __originalMethod.Name, "InstanceAudioClipArrayPatch"))
			{
				FieldInfo fieldInfo = AccessTools.Field(type, item.Field);
				if (fieldInfo == null)
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' was not found!");
					break;
				}
				if (fieldInfo.FieldType != typeof(AudioClip[]))
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' is not of type AudioClip[]!");
					break;
				}
				AudioClip[] original = fieldInfo.GetValue(__instance) as AudioClip[];
				if (item.AudioFileInfo.Count == 1)
				{
					AudioFileInfo audioFileInfo = item.AudioFileInfo.Single();
					fieldInfo.SetValue(__instance, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClips(audioFileInfo.Filename, original));
					continue;
				}
				AudioClip preloadedAudioClip = UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item.AudioFileInfo.OrderByDescending((AudioFileInfo a) => a.Chance).First().Filename);
				fieldInfo.SetValue(__instance, new AudioClip[1] { preloadedAudioClip });
				foreach (AudioFileInfo item2 in item.AudioFileInfo)
				{
					SoundTool.ReplaceAudioClip(preloadedAudioClip, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item2.Filename), (float)item2.Chance / 100f);
				}
			}
		}

		public static void InstanceAudioClipPatch(ref object __instance, MethodBase __originalMethod)
		{
			Type type = __instance.GetType();
			UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogInfo("MultiSoundReplacePluginManager::InstanceAudioClipPatch - Patching " + type.Name + "::" + __originalMethod.Name);
			foreach (AudioPatchMetadata item in UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetAudioPatchesForMethod(type.Name, __originalMethod.Name, "InstanceAudioClipPatch"))
			{
				FieldInfo fieldInfo = AccessTools.Field(type, item.Field);
				if (fieldInfo == null)
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' was not found!");
					break;
				}
				if (fieldInfo.FieldType != typeof(AudioClip))
				{
					UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.LogError("'" + type.Name + "." + item.Field + "' is not of type AudioClip!");
					break;
				}
				object? value = fieldInfo.GetValue(__instance);
				AudioClip val = (AudioClip)((value is AudioClip) ? value : null);
				if (item.AudioFileInfo.Count == 1)
				{
					AudioFileInfo audioFileInfo = item.AudioFileInfo.Single();
					fieldInfo.SetValue(__instance, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(audioFileInfo.Filename) ?? val);
					continue;
				}
				AudioClip preloadedAudioClip = UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item.AudioFileInfo.OrderByDescending((AudioFileInfo a) => a.Chance).First().Filename);
				fieldInfo.SetValue(__instance, preloadedAudioClip);
				foreach (AudioFileInfo item2 in item.AudioFileInfo)
				{
					SoundTool.ReplaceAudioClip(preloadedAudioClip, UnifiedChaosPluginManager<MultiSoundReplacePluginManager, MultiSoundReplaceConfig>.Instance.GetPreloadedAudioClip(item2.Filename), (float)item2.Chance / 100f);
				}
			}
		}
	}
	public class OpenDoorsInSpacePluginManager : UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>
	{
		private class FiredMessagePatcher
		{
			private const string ELEMENT_TEXT = "MaskImage/HeaderText";

			private const string ELEMENT_SUBTEXT = "MaskImage/HeaderText (1)";

			private TextMeshProUGUI _youAreFiredDueToNegligenceSubtext;

			private TextMeshProUGUI _youAreFiredDueToNegligenceText;

			private GameObject _youAreFiredSubtext;

			private GameObject _youAreFiredText;

			private GameObject FindOriginalGameOverElement(string element)
			{
				return GameObject.Find("/Systems/UI/Canvas/GameOverScreen/" + element);
			}

			public void Init(bool force = false)
			{
				if ((Object)(object)_youAreFiredText == (Object)null)
				{
					_youAreFiredText = FindOriginalGameOverElement("MaskImage/HeaderText");
				}
				if ((Object)(object)_youAreFiredSubtext == (Object)null)
				{
					_youAreFiredSubtext = FindOriginalGameOverElement("MaskImage/HeaderText (1)");
				}
				if (force && (Object)(object)_youAreFiredDueToNegligenceText != (Object)null)
				{
					_youAreFiredDueToNegligenceText = null;
				}
				if ((Object)(object)_youAreFiredDueToNegligenceText == (Object)null)
				{
					_youAreFiredDueToNegligenceText = ReplaceTextElement("MaskImage/HeaderText", "(OpenDoorsInSpace fired text)", UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance._config.EjectedMessageText);
				}
				if (force && (Object)(object)_youAreFiredDueToNegligenceSubtext != (Object)null)
				{
					_youAreFiredDueToNegligenceSubtext = null;
				}
				if ((Object)(object)_youAreFiredDueToNegligenceSubtext == (Object)null)
				{
					_youAreFiredDueToNegligenceSubtext = ReplaceTextElement("MaskImage/HeaderText (1)", "(OpenDoorsInSpace fired subtext)", UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance._config.EjectedMessageSubtext);
				}
			}

			public void Activate()
			{
				_youAreFiredText.gameObject.SetActive(false);
				((Component)_youAreFiredDueToNegligenceText).gameObject.SetActive(true);
				_youAreFiredSubtext.gameObject.SetActive(false);
				((Component)_youAreFiredDueToNegligenceSubtext).gameObject.SetActive(true);
			}

			public IEnumerator Deactivate()
			{
				yield return (object)new WaitForSeconds(1f);
				GameObject youAreFiredText = _youAreFiredText;
				if (youAreFiredText != null)
				{
					GameObject gameObject = youAreFiredText.gameObject;
					if (gameObject != null)
					{
						gameObject.SetActive(true);
					}
				}
				TextMeshProUGUI youAreFiredDueToNegligenceText = _youAreFiredDueToNegligenceText;
				if (youAreFiredDueToNegligenceText != null)
				{
					GameObject gameObject2 = ((Component)youAreFiredDueToNegligenceText).gameObject;
					if (gameObject2 != null)
					{
						gameObject2.SetActive(false);
					}
				}
				GameObject youAreFiredSubtext = _youAreFiredSubtext;
				if (youAreFiredSubtext != null)
				{
					GameObject gameObject3 = youAreFiredSubtext.gameObject;
					if (gameObject3 != null)
					{
						gameObject3.SetActive(true);
					}
				}
				TextMeshProUGUI youAreFiredDueToNegligenceSubtext = _youAreFiredDueToNegligenceSubtext;
				if (youAreFiredDueToNegligenceSubtext != null)
				{
					GameObject gameObject4 = ((Component)youAreFiredDueToNegligenceSubtext).gameObject;
					if (gameObject4 != null)
					{
						gameObject4.SetActive(false);
					}
				}
			}

			private TextMeshProUGUI ReplaceTextElement(string element, string suffix, string text)
			{
				GameObject val = FindOriginalGameOverElement(element);
				GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
				((Object)val2).name = ((Object)val2).name + " " + suffix;
				val2.SetActive(false);
				TextMeshProUGUI component = val2.GetComponent<TextMeshProUGUI>();
				((TMP_Text)component).text = text;
				return component;
			}
		}

		public class LguPatches
		{
			[HarmonyPatch(typeof(LguStore), "PlayersFiredServerRpc")]
			[HarmonyPrefix]
			public static bool LguStore_PlayersFiredServerRpc_Prefix()
			{
				return !UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.IsEjectingDueToNegligence;
			}
		}

		private const string SOUND_DOORWARN = "door-open-warning";

		private const string SOUND_DOORERROR = "door-error";

		private const string SOUND_AIRBLAST = "fartwithreverb";

		private AudioSource _airBlastAudioSource;

		private FiredMessagePatcher _firedMessagePatcher;

		public bool IsEjectingDueToNegligence { get; internal set; }

		protected override string PluginFriendlyName => "OpenDoorsInSpace";

		public override void Start()
		{
			_config.Init();
			_config.ConfigValueUpdated += ConfigValueUpdated;
			LogInfo(((object)this).GetType().Name + " Start");
			SceneManager.activeSceneChanged += HandleActiveSceneChanged;
			_airBlastAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			_airBlastAudioSource.loop = false;
			_airBlastAudioSource.spatialBlend = 0f;
			_firedMessagePatcher = new FiredMessagePatcher();
			LoadAudio(new string[3] { "door-open-warning", "fartwithreverb", "door-error" });
			UnifiedChaosPluginNetworkHandler<OpenDoorsInSpaceNetworkHandler>.NetworkSpawn += delegate
			{
				UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance._firedMessagePatcher.Init();
				OpenDoorsInSpaceNetworkHandler.OpenDoorEvent += UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.HandleOpenDoorEvent;
			};
			UnifiedChaosPluginNetworkHandler<OpenDoorsInSpaceNetworkHandler>.NetworkDespawn += delegate
			{
				OpenDoorsInSpaceNetworkHandler.OpenDoorEvent -= UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.HandleOpenDoorEvent;
			};
		}

		private void ConfigValueUpdated(object sender, string configKey)
		{
		}

		private void HandleActiveSceneChanged(Scene prevScene, Scene activeScene)
		{
			ResetEjectingDueToNegligance();
		}

		public void PressDoorOpenServerRPC()
		{
			if ((NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) && !StartOfRound.Instance.firingPlayersCutsceneRunning && !IsEjectingDueToNegligence)
			{
				if (!_config.IsEnabled || Random.Range(0f, 100f) > _config.DoorOpenPercent)
				{
					UnifiedChaosPluginNetworkHandler<OpenDoorsInSpaceNetworkHandler>.Instance.DoorOpenErrorServerRPC();
				}
				else if (StartOfRound.Instance.firingPlayersCutsceneRunning || IsEjectingDueToNegligence)
				{
					LogInfo("Could not eject due to negligence: cutscene is already running");
				}
				else
				{
					UnifiedChaosPluginNetworkHandler<OpenDoorsInSpaceNetworkHandler>.Instance.EjectDueToNegligenceServerRPC();
				}
			}
		}

		private IEnumerator PlayDoorError()
		{
			if (_config.PlayDoorError)
			{
				AudioClip preloadedAudioClip = GetPreloadedAudioClip("door-error");
				if (!((Object)(object)preloadedAudioClip == (Object)null))
				{
					StartOfRound.Instance.shipDoorAudioSource.PlayOneShot(preloadedAudioClip, _config.DoorErrorVolume);
					yield return (object)new WaitForSeconds(preloadedAudioClip.length);
				}
			}
		}

		private IEnumerator PlayDoorOpenWarning()
		{
			IsEjectingDueToNegligence = true;
			StartOfRound shipManager = StartOfRound.Instance;
			AudioClip preloadedAudioClip = GetPreloadedAudioClip("door-open-warning");
			if ((Object)(object)preloadedAudioClip != (Object)null)
			{
				StartOfRound.Instance.shipDoorAudioSource.PlayOneShot(preloadedAudioClip, 1f);
				yield return (object)new WaitForSeconds(preloadedAudioClip.length);
			}
			yield return (object)new WaitForSeconds(0.1f);
			_firedMessagePatcher.Activate();
			if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)
			{
				shipManager.ManuallyEjectPlayersServerRpc();
			}
		}

		public void ResetEjectingDueToNegligance()
		{
			LogInfo("Reseting ...");
			if ((Object)(object)StartOfRound.Instance != (Object)null)
			{
				((MonoBehaviour)this).StartCoroutine(_firedMessagePatcher.Deactivate());
			}
			IsEjectingDueToNegligence = false;
		}

		public IEnumerator PlayersEjected(bool abridgedVersion)
		{
			AudioClip airBlast = GetPreloadedAudioClip("fartwithreverb");
			StartOfRound startOfRound = StartOfRound.Instance;
			startOfRound.shipDoorsAnimator.SetBool("OpenInOrbit", true);
			startOfRound.shipDoorAudioSource.PlayOneShot(startOfRound.airPressureSFX);
			startOfRound.starSphereObject.SetActive(true);
			startOfRound.starSphereObject.transform.position = ((Component)GameNetworkManager.Instance.localPlayerController).transform.position;
			yield return (object)new WaitForSeconds(0.25f);
			startOfRound.suckingPlayersOutOfShip = true;
			startOfRound.suckingFurnitureOutOfShip = true;
			PlaceableShipObject[] array = Object.FindObjectsOfType<PlaceableShipObject>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i].parentObject == (Object)null)
				{
					Debug.Log((object)("Error! No parentObject for placeable object: " + startOfRound.unlockablesList.unlockables[array[i].unlockableID].unlockableName));
				}
				array[i].parentObject.StartSuckingOutOfShip();
				if (startOfRound.unlockablesList.unlockables[array[i].unlockableID].spawnPrefab)
				{
					Collider[] componentsInChildren = ((Component)array[i].parentObject).GetComponentsInChildren<Collider>();
					foreach (Collider val in componentsInChildren)
					{
						val.enabled = false;
					}
				}
			}
			GameNetworkManager.Instance.localPlayerController.inSpecialInteractAnimation = true;
			GameNetworkManager.Instance.localPlayerController.DropAllHeldItems(true, false);
			HUDManager.Instance.UIAudio.PlayOneShot(startOfRound.suckedIntoSpaceSFX);
			yield return (object)new WaitForSeconds(6f);
			SoundManager.Instance.SetDiageticMixerSnapshot(3, 2f);
			HUDManager.Instance.ShowPlayersFiredScreen(true);
			_airBlastAudioSource.PlayOneShot(airBlast, 1f);
			yield return (object)new WaitForSeconds(2f);
			startOfRound.starSphereObject.SetActive(false);
			startOfRound.shipDoorAudioSource.Stop();
			startOfRound.speakerAudioSource.Stop();
			_airBlastAudioSource.Stop();
			startOfRound.suckingFurnitureOutOfShip = false;
			yield return (object)new WaitForSeconds(4f);
			GameNetworkManager.Instance.localPlayerController.TeleportPlayer(startOfRound.playerSpawnPositions[GameNetworkManager.Instance.localPlayerController.playerClientId].position, false, 0f, false, true);
			startOfRound.shipDoorsAnimator.SetBool("OpenInOrbit", false);
			startOfRound.currentPlanetPrefab.transform.position = ((Component)startOfRound.planetContainer).transform.position;
			startOfRound.suckingPlayersOutOfShip = false;
			startOfRound.choseRandomFlyDirForPlayer = false;
			startOfRound.suckingPower = 0f;
			startOfRound.shipRoomLights.SetShipLightsOnLocalClientOnly(true);
			yield return (object)new WaitForSeconds(2f);
			if (((NetworkBehaviour)startOfRound).IsServer)
			{
				startOfRound.playersRevived++;
				startOfRound.playersRevived = 0;
				startOfRound.EndPlayersFiredSequenceClientRpc();
			}
			else
			{
				startOfRound.PlayerHasRevivedServerRpc();
			}
		}

		public override void Patch()
		{
			AddPatchForSoftDependency("com.malco.lethalcompany.moreshipupgrades", typeof(LguPatches));
		}

		private void HandleOpenDoorEvent(OpenDoorsInSpaceNetworkHandler.NetworkEvent networkEvent)
		{
			switch (networkEvent)
			{
			case OpenDoorsInSpaceNetworkHandler.NetworkEvent.DoorOpenPressed:
				PressDoorOpenServerRPC();
				break;
			case OpenDoorsInSpaceNetworkHandler.NetworkEvent.DoorActivatedPlayError:
				((MonoBehaviour)this).StartCoroutine(PlayDoorError());
				break;
			case OpenDoorsInSpaceNetworkHandler.NetworkEvent.DoorActivatedEjectPlayers:
				((MonoBehaviour)this).StartCoroutine(PlayDoorOpenWarning());
				break;
			}
		}

		[HarmonyPatch(typeof(HangarShipDoor), "Update")]
		[HarmonyPostfix]
		public static void HangarShipDoor_Update_Postfix(HangarShipDoor __instance)
		{
			if (!__instance.triggerScript.interactable && StartOfRound.Instance.inShipPhase)
			{
				UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.LogInfo("Forcing door buttons to be interactable");
				__instance.triggerScript.interactable = true;
			}
		}

		[HarmonyPatch(typeof(HangarShipDoor), "PlayDoorAnimation")]
		[HarmonyPrefix]
		public static bool HangarShipDoor_PlayDoorAnimation_Prefix(bool closed)
		{
			if (closed || !StartOfRound.Instance.inShipPhase)
			{
				return true;
			}
			UnifiedChaosPluginNetworkHandler<OpenDoorsInSpaceNetworkHandler>.Instance.PressDoorOpenServerRPC();
			return true;
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
		[HarmonyPrefix]
		public static bool StartOfRound_ResetShip_Prefix()
		{
			return !UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.IsEjectingDueToNegligence;
		}

		[HarmonyPatch(typeof(StartOfRound), "PlayFirstDayShipAnimation")]
		[HarmonyPrefix]
		public static bool StartOfRound_PlayFirstDayShipAnimation_Prefix()
		{
			if (!UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.IsEjectingDueToNegligence)
			{
				return true;
			}
			UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.ResetEjectingDueToNegligance();
			return false;
		}

		[HarmonyPatch(typeof(StartOfRound), "playersFiredGameOver")]
		[HarmonyPrefix]
		public static bool StartOfRound_playersFiredGameOver_Enumerator_Prefix(bool abridgedVersion, ref IEnumerator __result)
		{
			if (!UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.IsEjectingDueToNegligence)
			{
				return true;
			}
			__result = UnifiedChaosPluginManager<OpenDoorsInSpacePluginManager, OpenDoorsInSpaceConfig>.Instance.PlayersEjected(abridgedVersion);
			return false;
		}
	}
	public abstract class UnifiedChaosPluginManager<TPlugin, TConfig> : UnifiedChaosPluginManager where TPlugin : UnifiedChaosPluginManager<TPlugin, TConfig> where TConfig : new()
	{
		protected TConfig _config = new TConfig();

		public static TPlugin Instance => UnifiedChaosPlugin.Instance.GetPlugin<TPlugin>();

		public static void Create(UnifiedChaosPlugin basePlugin)
		{
			UnifiedChaosPluginManager.Log(basePlugin, (LogLevel)16, "UnifiedChaosPlugin", $"Registering instance of \"{typeof(TPlugin)}\"");
			TPlugin val = basePlugin.RegisterPlugin<TPlugin>();
			val._basePlugin = basePlugin;
			Harmony.CreateAndPatchAll(((object)val).GetType(), (string)null);
			val.Patch();
		}

		public virtual void Patch()
		{
		}

		protected void AddPatchForSoftDependency(string key, Type patches)
		{
			if (Chainloader.PluginInfos.ContainsKey(key))
			{
				LogInfo("Found '" + Chainloader.PluginInfos[key].Metadata.Name + "' - Adding Patches");
				Harmony.CreateAndPatchAll(patches, (string)null);
			}
		}
	}
	public abstract class UnifiedChaosPluginManager : MonoBehaviour
	{
		private readonly Dictionary<string, List<AudioClip>> _audioClips = new Dictionary<string, List<AudioClip>>();

		protected UnifiedChaosPlugin _basePlugin;

		protected abstract string PluginFriendlyName { get; }

		protected string PluginDir => Path.GetRelativePath(Paths.PluginPath, Path.GetDirectoryName(((BaseUnityPlugin)_basePlugin).Info.Location));

		protected string SoundPathForPlugin => Path.Combine("Sounds", PluginFriendlyName);

		protected string FullSoundPathForPlugin => Path.Combine(Paths.PluginPath, PluginDir, Path.Combine("Sounds", PluginFriendlyName));

		public abstract void Start();

		protected static void Log(UnifiedChaosPlugin basePlugin, LogLevel logLevel, string pluginName, string message)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			basePlugin.Log(logLevel, pluginName, message);
		}

		protected void Log(LogLevel logLevel, string message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Log(_basePlugin, logLevel, PluginFriendlyName, message);
		}

		protected void LogDebug(string message)
		{
			Log((LogLevel)32, message);
		}

		protected void LogMessage(string message)
		{
			Log((LogLevel)8, message);
		}

		protected void LogAll(string message)
		{
			Log((LogLevel)63, message);
		}

		protected void LogError(string message)
		{
			Log((LogLevel)2, message);
		}

		protected void LogFatal(string message)
		{
			Log((LogLevel)1, message);
		}

		protected void LogInfo(string message)
		{
			Log((LogLevel)16, message);
		}

		protected void LogNone(string message)
		{
			Log((LogLevel)0, message);
		}

		protected void LogWarning(string message)
		{
			Log((LogLevel)4, message);
		}

		protected void LoadAudio(IEnumerable<string> audioIds)
		{
			string[] validExtensions = new string[3] { ".ogg", ".wav", ".mp3" };
			Func<FileInfo, string, bool> selector = (FileInfo f, string s) => f.Name.StartsWith(s, ignoreCase: true, CultureInfo.InvariantCulture);
			Func<FileInfo, bool> filter = (FileInfo f) => validExtensions.Contains(f.Extension.ToLower());
			if (!audioIds.Any())
			{
				return;
			}
			string fullSoundPathForPlugin = FullSoundPathForPlugin;
			if (!Directory.Exists(Path.Combine(fullSoundPathForPlugin)))
			{
				throw new DirectoryNotFoundException(fullSoundPathForPlugin);
			}
			DirectoryInfo directoryInfo = new DirectoryInfo(fullSoundPathForPlugin);
			FileInfo[] source = (from f in directoryInfo.EnumerateFiles()
				where audioIds.Any((string i) => filter(f) && selector(f, i))
				select f).ToArray();
			foreach (string audioId in audioIds)
			{
				if (!_audioClips.ContainsKey(audioId))
				{
					_audioClips.Add(audioId, new List<AudioClip>());
				}
				foreach (FileInfo item in source.Where((FileInfo f) => selector(f, audioId)))
				{
					LogDebug("Audio Found:('" + audioId + "')" + item.Name);
					AudioClip audioClip = SoundTool.GetAudioClip(PluginDir, SoundPathForPlugin, item.Name);
					_audioClips[audioId].Add(audioClip);
				}
			}
		}

		[CanBeNull]
		protected AudioClip GetPreloadedAudioClip(string key)
		{
			if (!_audioClips.ContainsKey(key) || !_audioClips[key].Any())
			{
				return null;
			}
			return _audioClips[key].First();
		}

		protected AudioClip[] GetPreloadedAudioClips(string key, [CanBeNull] AudioClip[] original = null)
		{
			object source;
			if (!_audioClips.ContainsKey(key) || !_audioClips[key].Any())
			{
				IEnumerable<AudioClip> enumerable = original;
				source = enumerable ?? Enumerable.Empty<AudioClip>();
			}
			else
			{
				IEnumerable<AudioClip> enumerable = _audioClips[key];
				source = enumerable;
			}
			return ((IEnumerable<AudioClip>)source).ToArray();
		}

		protected AudioClip[] GetPreloadedAudioClips(IEnumerable<string> keys, [CanBeNull] AudioClip[] original = null)
		{
			IEnumerable<AudioClip> enumerable = _audioClips.Where((KeyValuePair<string, List<AudioClip>> c) => keys.Contains(c.Key)).SelectMany((KeyValuePair<string, List<AudioClip>> c) => c.Value);
			object source;
			if (!enumerable.Any())
			{
				source = original ?? Enumerable.Empty<AudioClip>();
			}
			else
			{
				source = enumerable;
			}
			return ((IEnumerable<AudioClip>)source).ToArray();
		}
	}
}
namespace TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus
{
	public class BaboonBirdExtender : MobPlusPatcher<BaboonBirdExtender, BaboonBirdAI>
	{
		protected BaboonBirdExtender()
		{
		}
	}
	public class BlobExtender : MobPlusPatcher<BlobExtender, BlobAI>
	{
		protected BlobExtender()
		{
		}
	}
	public class CentipedeExtender : MobPlusPatcher<CentipedeExtender, CentipedeAI>
	{
		protected CentipedeExtender()
		{
		}
	}
	public class CrawlerExtender : MobPlusPatcher<CrawlerExtender, CrawlerAI>
	{
		protected CrawlerExtender()
		{
		}
	}
	public class DocileLocustBeesExtender : MobPlusPatcher<DocileLocustBeesExtender, DocileLocustBeesAI>
	{
		protected DocileLocustBeesExtender()
		{
		}
	}
	public class DoublewingExtender : MobPlusPatcher<DoublewingExtender, DoublewingAI>
	{
		protected DoublewingExtender()
		{
		}
	}
	public class DressGirlExtender : MobPlusPatcher<DressGirlExtender, DressGirlAI>
	{
		protected DressGirlExtender()
		{
		}
	}
	public class FlowermanExtender : MobPlusPatcher<FlowermanExtender, FlowermanAI>
	{
		public enum BehaviorState
		{
			Search,
			Moving,
			Angry
		}

		public event Action<FlowermanAI, PlayerControllerB> AngryAtPlayer;

		public event Action<FlowermanAI, bool> DroppingBody;

		public event Action<FlowermanAI, PlayerControllerB> EvadingPlayer;

		public event Action<FlowermanAI, bool, PlayerControllerB> KilledPlayer;

		public event Action<FlowermanAI, PlayerControllerB> StaringDownPlayer;

		protected FlowermanExtender()
		{
			base.ChangeBehaviorStateLocalClient += OnChangeBehaviorStateLocalClient;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "DropPlayerBody")]
		public static void __DropPlayerBody(FlowermanAI __instance)
		{
			if (__instance.carryingPlayerBody)
			{
				MobPlusPatcher<FlowermanExtender, FlowermanAI>._instance.DroppingBody?.Invoke(__instance, MobPlusPatcher<FlowermanExtender, FlowermanAI>._instance.NearFavoriteSpot(__instance));
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "FinishKillAnimation")]
		public static void __FinishKillAnimation(FlowermanAI __instance, bool carryingBody)
		{
			MobPlusPatcher<FlowermanExtender, FlowermanAI>._instance.KilledPlayer?.Invoke(__instance, carryingBody, __instance.bodyBeingCarried?.playerScript);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FlowermanAI), "LookAtFlowermanTrigger")]
		public static void __LookAtFlowermanTrigger(FlowermanAI __instance, bool __state)
		{
			if (__instance.evadeModeStareDown && !__state)
			{
				MobPlusPatcher<FlowermanExtender, FlowermanAI>._instance.StaringDownPlayer?.Invoke(__instance, ((EnemyAI)__instance).targetPlayer);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "LookAtFlowermanTrigger")]
		public static void __LookAtFlowermanTriggerPrefix(FlowermanAI __instance, ref bool __state)
		{
			__state = __instance.evadeModeStareDown;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FlowermanAI), "Update")]
		public static void __Update(FlowermanAI __instance, bool __state)
		{
			if (__instance.wasInEvadeMode && !__state)
			{
				MobPlusPatcher<FlowermanExtender, FlowermanAI>._instance.EvadingPlayer?.Invoke(__instance, ((EnemyAI)__instance).targetPlayer);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "Update")]
		public static void __UpdatePrefix(FlowermanAI __instance, ref bool __state)
		{
			__state = __instance.wasInEvadeMode;
		}

		private bool NearFavoriteSpot(FlowermanAI ai)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return (double)Vector3.Distance(((Component)ai).transform.position, ((EnemyAI)ai).favoriteSpot.position) < 7.0;
		}

		private void OnChangeBehaviorStateLocalClient(FlowermanAI ai, int state)
		{
			switch ((BehaviorState)state)
			{
			case BehaviorState.Angry:
				this.AngryAtPlayer?.Invoke(ai, ((EnemyAI)ai).targetPlayer);
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning("FlowermanExtender", $"Unknown behavior state: {state}");
				break;
			case BehaviorState.Search:
			case BehaviorState.Moving:
				break;
			}
		}
	}
	public class ForestGiantExtender : MobPlusPatcher<ForestGiantExtender, ForestGiantAI>
	{
		protected ForestGiantExtender()
		{
		}
	}
	public class HoarderBugExtender : MobPlusPatcher<HoarderBugExtender, HoarderBugAI>
	{
		public enum BehaviorState
		{
			Searching,
			Resting,
			Angry
		}

		public event Action<HoarderBugAI, PlayerControllerB> AngryAtPlayer;

		public event Action<HoarderBugAI, PlayerControllerB> ChangedWatchingPlayer;

		public event Action<HoarderBugAI, GrabbableObject> HuntingItem;

		public event Action<HoarderBugAI, HoarderBugItem> ItemDroppedInNest;

		public event Action<HoarderBugAI, HoarderBugItem> ItemGrabbed;

		protected HoarderBugExtender()
		{
			base.ChangeBehaviorStateLocalClient += OnChangeBehaviorStateLocalClient;
		}

		[HarmonyPatch(typeof(HoarderBugAI), "DetectAndLookAtPlayers")]
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> __ChangedWatchingPlayer(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(HoarderBugExtender), "__ChangedWatchingPlayerHook", new Type[1] { typeof(HoarderBugAI) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(RoundManager), "PlayRandomClip", new Type[5]
			{
				typeof(AudioSource),
				typeof(AudioClip[]),
				typeof(bool),
				typeof(float),
				typeof(int)
			}, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, methodInfo2))
				{
					list.RemoveRange(list.Count - 7, 7);
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo));
				}
				else
				{
					list.Add(instruction);
				}
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}

		private static int __ChangedWatchingPlayerHook(HoarderBugAI ai)
		{
			MobPlusPatcher<HoarderBugExtender, HoarderBugAI>._instance.OnChangedWatchingPlayer(ai);
			return int.MinValue;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HoarderBugAI), "DropItem")]
		public static void __DropItem(HoarderBugAI __instance, bool droppingInNest, HoarderBugItem __state)
		{
			if (droppingInNest)
			{
				MobPlusPatcher<HoarderBugExtender, HoarderBugAI>._instance.ItemDroppedInNest?.Invoke(__instance, __state);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HoarderBugAI), "DropItem")]
		public static void __DropItemPrefix(HoarderBugAI __instance, ref HoarderBugItem __state)
		{
			__state = __instance.heldItem;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HoarderBugAI), "GrabTargetItemIfClose")]
		public static void __GrabTargetItemIfClose(HoarderBugAI __instance, bool __result)
		{
			if (__result)
			{
				MobPlusPatcher<HoarderBugExtender, HoarderBugAI>._instance.ItemGrabbed?.Invoke(__instance, __instance.heldItem);
			}
		}

		private void OnChangeBehaviorStateLocalClient(HoarderBugAI ai, int state)
		{
			switch ((BehaviorState)state)
			{
			case BehaviorState.Searching:
				this.HuntingItem?.Invoke(ai, ai.targetItem);
				break;
			case BehaviorState.Angry:
				this.AngryAtPlayer?.Invoke(ai, ((EnemyAI)ai).targetPlayer);
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning("HoarderBugExtender", $"Unknown behavior state: {state}");
				break;
			case BehaviorState.Resting:
				break;
			}
		}

		private void OnChangedWatchingPlayer(HoarderBugAI ai)
		{
			this.ChangedWatchingPlayer?.Invoke(ai, ai.watchingPlayer);
		}
	}
	public class JesterExtender : MobPlusPatcher<JesterExtender, JesterAI>
	{
		protected JesterExtender()
		{
		}
	}
	public class LassoManExtender : MobPlusPatcher<LassoManExtender, LassoManAI>
	{
		protected LassoManExtender()
		{
		}
	}
	public class MaskedPlayerEnemyExtender : MobPlusPatcher<MaskedPlayerEnemyExtender, MaskedPlayerEnemy>
	{
		protected MaskedPlayerEnemyExtender()
		{
		}
	}
	public static class Extensions
	{
		public static Dictionary<Type, EventBroker> InitEventBroker<T>(this Dictionary<Type, EventBroker> collection, T instance, Action<T> initializer) where T : EventBroker, new()
		{
			if (collection.ContainsKey(typeof(T)))
			{
				return collection;
			}
			collection.Add(instance.EnemyType, instance);
			initializer(instance);
			return collection;
		}

		public static Dictionary<Type, MobPlusPatcher> InitPatcher<T>(this Dictionary<Type, MobPlusPatcher> collection, T instance, Action<T> initializer) where T : MobPlusPatcher
		{
			if (collection.ContainsKey(typeof(T)))
			{
				return collection;
			}
			collection.Add(instance.EnemyType, instance);
			initializer(instance);
			return collection;
		}
	}
	public abstract class MobPlusPatcher<TMobPlus, TEnemyAI> : MobPlusPatcher<TEnemyAI> where TMobPlus : MobPlusPatcher<TMobPlus, TEnemyAI> where TEnemyAI : EnemyAI
	{
		protected class CommonModPlusPatches
		{
			public static Harmony HarmonyInstance { get; } = new Harmony(Guid.NewGuid().ToString());


			public static void __OnDestroy(TEnemyAI __instance)
			{
				UnifiedChaosPlugin.Instance.LogDebug("CommonModPlusPatches+" + typeof(TEnemyAI).Name + "::__OnDestroy", $"Instance:'{MobPlusPatcher<TMobPlus, TEnemyAI>._instance.EnemyType.Name}', IsNull:'{(Object)(object)__instance == (Object)null}'", verboseOnly: true);
				MobPlusPatcher<TMobPlus, TEnemyAI>._instance.EndTrackObject(__instance);
			}

			public static void __Start(TEnemyAI __instance)
			{
			}

			public static void __SwitchToBehaviourStateOnLocalClient(TEnemyAI __instance, int stateIndex)
			{
				if (!((Object)(object)MobPlusPatcher<TMobPlus, TEnemyAI>._instance.GetNetworkObject(((NetworkBehaviour)(object)__instance).NetworkObjectId) == (Object)null))
				{
					UnifiedChaosPlugin.Instance.LogDebug("CommonModPlusPatches+" + typeof(TEnemyAI).Name + "::__SwitchToBehaviourStateOnLocalClient", $"Instance:'{MobPlusPatcher<TMobPlus, TEnemyAI>._instance.EnemyType.Name}', IsNull:'{(Object)(object)__instance == (Object)null}'", verboseOnly: true);
					((MobPlusPatcher<TMobPlus, TEnemyAI>)MobPlusPatcher<TMobPlus, TEnemyAI>._instance).ChangeBehaviorStateLocalClient?.Invoke(__instance, stateIndex);
				}
			}

			private static MethodInfo FindMethod(string type, string methodName)
			{
				MethodInfo method = AccessTools.TypeByName(type).GetMethod(methodName);
				if (method?.DeclaringType != null && method.DeclaringType?.Name != type)
				{
					method = AccessTools.TypeByName(method.DeclaringType.Name).GetMethod(methodName);
				}
				return method;
			}

			public static void PatchMethods()
			{
				PostfixMethod(typeof(TEnemyAI).Name, "Start", "__Start");
				PostfixMethod(typeof(TEnemyAI).Name, "OnDestroy", "__OnDestroy");
				PrefixMethod(typeof(TEnemyAI).Name, "SwitchToBehaviourStateOnLocalClient", "__SwitchToBehaviourStateOnLocalClient");
			}

			public static void PostfixMethod(string targetType, string methodName, string newMethodName)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				MethodInfo methodInfo = FindMethod(targetType, methodName);
				MethodInfo method = typeof(CommonModPlusPatches).GetMethod(newMethodName);
				HarmonyInstance.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}

			public static void PrefixMethod(string targetType, string methodName, string newMethodName)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				MethodInfo methodInfo = FindMethod(targetType, methodName);
				MethodInfo method = typeof(CommonModPlusPatches).GetMethod(newMethodName);
				HarmonyInstance.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		protected static TMobPlus _instance;

		private static readonly object _createLock = new object();

		public event Action<TEnemyAI, int> ChangeBehaviorStateLocalClient;

		public virtual void ApplyPatches()
		{
			Harmony.CreateAndPatchAll(typeof(TMobPlus), (string)null);
			CommonModPlusPatches.PatchMethods();
		}

		public static TMobPlus GetInstance()
		{
			if (_instance == null)
			{
				lock (_createLock)
				{
					ConstructorInfo constructor = typeof(TMobPlus).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Array.Empty<Type>(), Array.Empty<ParameterModifier>());
					if (constructor == null)
					{
						throw new Exception("Type '" + typeof(TMobPlus).Name + "' missing protected constructor!");
					}
					_instance = constructor.Invoke(Array.Empty<object>()) as TMobPlus;
					_instance.ApplyPatches();
				}
			}
			return _instance;
		}
	}
	public abstract class MobPlusPatcher<TEnemyAI> : MobPlusPatcher where TEnemyAI : EnemyAI
	{
		public override Type EnemyType => typeof(TEnemyAI);

		protected void BeginTrackObject(TEnemyAI trackedObject)
		{
			if (!((Object)(object)trackedObject == (Object)null))
			{
				ulong? networkId = GetNetworkId(trackedObject);
				if (networkId.HasValue && !_trackedObjects.ContainsKey(networkId.Value))
				{
					_trackedObjects.Add(networkId.Value, (EnemyAI)(object)trackedObject);
				}
			}
		}

		protected void EndTrackObject(TEnemyAI trackedObject)
		{
			if (!((Object)(object)trackedObject == (Object)null))
			{
				ulong? networkId = GetNetworkId(trackedObject);
				if (networkId.HasValue && _trackedObjects.ContainsKey(networkId.Value))
				{
					_trackedObjects.Remove(networkId.Value);
				}
			}
		}

		protected ulong? GetNetworkId(TEnemyAI ai)
		{
			object obj = ai;
			if (obj == null)
			{
				return null;
			}
			NetworkObject networkObject = ((NetworkBehaviour)obj).NetworkObject;
			if (networkObject == null)
			{
				return null;
			}
			return networkObject.NetworkObjectId;
		}

		public new TEnemyAI GetNetworkObject(ulong id)
		{
			if (!_trackedObjects.TryGetValue(id, out var value))
			{
				return default(TEnemyAI);
			}
			return (TEnemyAI)(object)((value is TEnemyAI) ? value : null);
		}
	}
	public abstract class MobPlusPatcher
	{
		protected Dictionary<ulong, EnemyAI> _trackedObjects = new Dictionary<ulong, EnemyAI>();

		public abstract Type EnemyType { get; }

		protected void BeginTrackObject(EnemyAI trackedObject)
		{
			if (!((Object)(object)trackedObject == (Object)null))
			{
				ulong networkId = GetNetworkId(trackedObject);
				if (!_trackedObjects.ContainsKey(networkId))
				{
					_trackedObjects.Add(networkId, trackedObject);
				}
			}
		}

		protected void EndTrackObject(EnemyAI trackedObject)
		{
			if (!((Object)(object)trackedObject == (Object)null))
			{
				ulong networkId = GetNetworkId(trackedObject);
				if (_trackedObjects.ContainsKey(networkId))
				{
					_trackedObjects.Remove(networkId);
				}
			}
		}

		public static ulong GetNetworkId(EnemyAI ai)
		{
			return ((NetworkBehaviour)ai).NetworkObject.NetworkObjectId;
		}

		public EnemyAI GetNetworkObject(ulong id)
		{
			if (!_trackedObjects.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		public void TestDumpTracked()
		{
			UnifiedChaosPlugin.Instance.LogDebug(GetType().Name, "Dumping known objects:");
			foreach (KeyValuePair<ulong, EnemyAI> trackedObject in _trackedObjects)
			{
				UnifiedChaosPlugin instance = UnifiedChaosPlugin.Instance;
				string name = GetType().Name;
				object arg = trackedObject.Key;
				EnemyAI value = trackedObject.Value;
				instance.LogDebug(name, $"\tKey:'{arg}', Value:'{((value != null) ? ((Object)value).name : null)}'");
			}
		}
	}
	public class MouthDogExtender : MobPlusPatcher<MouthDogExtender, MouthDogAI>
	{
		protected MouthDogExtender()
		{
		}
	}
	public class NutcrackerEnemyExtender : MobPlusPatcher<NutcrackerEnemyExtender, NutcrackerEnemyAI>
	{
		protected NutcrackerEnemyExtender()
		{
		}
	}
	public class PufferExtender : MobPlusPatcher<PufferExtender, PufferAI>
	{
		protected PufferExtender()
		{
		}
	}
	public class RedLocustBeesExtender : MobPlusPatcher<RedLocustBeesExtender, RedLocustBees>
	{
		protected RedLocustBeesExtender()
		{
		}
	}
	public class SandSpiderExtender : MobPlusPatcher<SandSpiderExtender, SandSpiderAI>
	{
		protected SandSpiderExtender()
		{
		}
	}
	public class SandWormExtender : MobPlusPatcher<SandWormExtender, SandWormAI>
	{
		protected SandWormExtender()
		{
		}
	}
}
namespace TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus.Notifiers
{
	public class FlowermanAINotifier : Notifier<FlowermanAI, FlowermanEventBroker>
	{
		public enum BehaviorState
		{
			Sneaking,
			Evading,
			Threaten
		}

		private class FlowermanNotifierCoroutineManager : CoroutineManager<FlowermanAINotifier>
		{
			private const float DEFAULT_DELAY = 1.5f;

			private const float DEFAULT_DEVIATION = 0.5f;

			private readonly RandomDelayCoroutine _chase;

			private readonly RandomDelayCoroutine _dropItem;

			protected internal event Action ChaseEventTrigger;

			protected internal event Action DropItemEventTrigger;

			public FlowermanNotifierCoroutineManager(FlowermanAINotifier notifier)
				: base(notifier)
			{
				_chase = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 1f, 2f);
				_dropItem = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 1f, 2f);
			}

			public void ChaseStart(bool restart = false)
			{
				_chase.Start(restart, delegate
				{
					this.ChaseEventTrigger?.Invoke();
				});
			}

			public void ChaseStop()
			{
				_chase.Stop();
			}

			public void DropItemStart(Action action, bool restart = false)
			{
				_dropItem.Start(restart, action);
			}

			public void DropItemStop()
			{
				_dropItem.Stop();
			}
		}

		private readonly FlowermanNotifierCoroutineManager _coroutineManager;

		private BehaviorState _behaviorState;

		public PlayerControllerB PlayerKilled => _ai?.bodyBeingCarried?.playerScript;

		public PlayerControllerB TargetPlayer => ((EnemyAI)(_ai?)).targetPlayer;

		public bool AtFavoriteSpot => (double)Vector3.Distance(((Component)_ai).transform.position, ((EnemyAI)_ai).favoriteSpot.position) < 7.0;

		public bool CarryingBody { get; private set; }

		public FlowermanAINotifier()
		{
			_coroutineManager = new FlowermanNotifierCoroutineManager(this);
			_coroutineManager.ChaseEventTrigger += CoroutineManagerOnChaseEventTrigger;
		}

		public void KilledPlayer(bool carryingBody)
		{
			CarryingBody = carryingBody;
			_broker.AIEventNotify(this, "KilledPlayer");
		}

		public void DroppingBody()
		{
			_broker.AIEventNotify(this, "KilledPlayer");
		}

		public void ChangedWatchingPlayer()
		{
			_broker.AIEventNotify(this, "ChangedWatchingPlayer");
		}

		private void CoroutineManagerOnChaseEventTrigger()
		{
			_broker.AIEventNotify(this, "AngryAtPlayer");
		}

		public override void Update()
		{
		}

		protected override void Initialize()
		{
		}

		protected override void OnChangeBehaviorStateLocalClient(int stateIndex)
		{
			BehaviorState enumValue = GetEnumValue<BehaviorState>(stateIndex);
			BehaviorState previousBehaviorState = GetPreviousBehaviorState<BehaviorState>();
			switch (enumValue)
			{
			case BehaviorState.Threaten:
				_broker.AIEventNotify(this, "AngryAtPlayer");
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning(((object)this).GetType().Name + "::OnChangeBehaviorStateLocalClient", $"Unknown behavior state: {stateIndex}");
				break;
			case BehaviorState.Sneaking:
			case BehaviorState.Evading:
				break;
			}
		}

		public void StaringDownPlayer()
		{
			_broker.AIEventNotify(this, "StaringDownPlayer");
		}

		public void EvadingPlayer()
		{
			_broker.AIEventNotify(this, "EvadingPlayer");
		}
	}
	public class HoarderBugAINotifier : Notifier<HoarderBugAI, HoarderBugEventBroker>
	{
		public enum BehaviorState
		{
			Scavenging,
			Returning,
			Chasing
		}

		private class HoarderBugNotifierCoroutineManager : CoroutineManager<HoarderBugAINotifier>
		{
			private const float DEFAULT_DELAY = 1.5f;

			private const float DEFAULT_DEVIATION = 0.5f;

			private readonly RandomDelayCoroutine _chase;

			private readonly RandomDelayCoroutine _dropItem;

			protected internal event Action ChaseEventTrigger;

			protected internal event Action DropItemEventTrigger;

			public HoarderBugNotifierCoroutineManager(HoarderBugAINotifier notifier)
				: base(notifier)
			{
				_chase = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 1f, 2f);
				_dropItem = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 1f, 2f);
			}

			public void ChaseStart(bool restart = false)
			{
				_chase.Start(restart, delegate
				{
					this.ChaseEventTrigger?.Invoke();
				});
			}

			public void ChaseStop()
			{
				_chase.Stop();
			}

			public void DropItemStart(Action action, bool restart = false)
			{
				_dropItem.Start(restart, action);
			}

			public void DropItemStop()
			{
				_dropItem.Stop();
			}
		}

		private readonly HoarderBugNotifierCoroutineManager _coroutineManager;

		private PlayerControllerB _angryAtPlayer;

		private BehaviorState _behaviorState;

		private HoarderBugItem _heldItem;

		private Notifier<HoarderBugAI, HoarderBugEventBroker> _notifierImplementation;

		public HoarderBugAINotifier()
		{
			_coroutineManager = new HoarderBugNotifierCoroutineManager(this);
			_coroutineManager.ChaseEventTrigger += CoroutineManagerOnChaseEventTrigger;
		}

		public void ChangedWatchingPlayer()
		{
			_broker.AIEventNotify(this, "ChangedWatchingPlayer");
		}

		private void CheckForAngryPlayerChanged()
		{
			BehaviorState behaviorState = GetBehaviorState<BehaviorState>();
			if (_behaviorState != behaviorState)
			{
				_behaviorState = behaviorState;
			}
			if (behaviorState == BehaviorState.Chasing && (Object)(object)_angryAtPlayer != (Object)(object)_ai.angryAtPlayer)
			{
				UnifiedChaosPlugin.Instance.LogWarning(((object)this).GetType().Name + "::CheckForAngryPlayerChanged", "Trigger Change Target");
				_angryAtPlayer = _ai.angryAtPlayer;
				_coroutineManager.ChaseStart(restart: true);
			}
		}

		private void CheckForChangedWatchingPlayer()
		{
		}

		private void CheckForHuntingItem()
		{
		}

		private void CheckForItemDroppedInNest()
		{
		}

		private void CheckForItemGrabbed()
		{
			if (_heldItem != _ai.heldItem)
			{
				_heldItem = _ai.heldItem;
				_broker.AIEventNotify(this, "ItemGrabbed");
			}
		}

		private void CoroutineManagerOnChaseEventTrigger()
		{
			_broker.AIEventNotify(this, "AngryAtPlayer");
		}

		public void DropItem(bool droppingInNest)
		{
			_coroutineManager.DropItemStart(delegate
			{
				_heldItem = _ai.heldItem;
				_broker.AIEventNotify(this, droppingInNest ? "ItemDroppedInNest" : "ItemDropped");
			});
		}

		protected override void Initialize()
		{
		}

		protected override void OnChangeBehaviorStateLocalClient(int stateIndex)
		{
			BehaviorState enumValue = GetEnumValue<BehaviorState>(stateIndex);
			BehaviorState previousBehaviorState = GetPreviousBehaviorState<BehaviorState>();
			switch (enumValue)
			{
			case BehaviorState.Scavenging:
				_coroutineManager.ChaseStop();
				_coroutineManager.DropItemStop();
				break;
			case BehaviorState.Returning:
				_coroutineManager.ChaseStop();
				_coroutineManager.DropItemStop();
				break;
			case BehaviorState.Chasing:
				UnifiedChaosPlugin.Instance.LogInfo(((object)this).GetType().Name + "::OnChangeBehaviorStateLocalClient", "Chase Start");
				_coroutineManager.DropItemStop();
				_angryAtPlayer = _ai.angryAtPlayer;
				_coroutineManager.ChaseStart();
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning(((object)this).GetType().Name + "::OnChangeBehaviorStateLocalClient", $"Unknown behavior state: {stateIndex}");
				break;
			}
		}

		public override void Update()
		{
			CheckForAngryPlayerChanged();
			CheckForChangedWatchingPlayer();
			CheckForHuntingItem();
			CheckForItemDroppedInNest();
			CheckForItemGrabbed();
		}
	}
	public abstract class Notifier : MonoBehaviour
	{
		public abstract ulong NetworkObjectId { get; }

		public abstract void Update();

		protected abstract void Initialize();
	}
	public abstract class Notifier<TEnemyAI> : Notifier where TEnemyAI : EnemyAI
	{
		protected TEnemyAI _ai;

		public TEnemyAI AiInstance => _ai;

		public override ulong NetworkObjectId => ((NetworkBehaviour)(object)_ai).NetworkObjectId;

		protected T GetBehaviorState<T>() where T : struct, Enum
		{
			return GetEnumValue<T>(((EnemyAI)_ai).currentBehaviourStateIndex);
		}

		protected T GetEnumValue<T>(object value) where T : struct, Enum
		{
			if (!Enum.TryParse<T>((value as string) ?? Convert.ToString(value), out var result))
			{
				return default(T);
			}
			return result;
		}

		protected T GetPreviousBehaviorState<T>() where T : struct, Enum
		{
			return GetEnumValue<T>(((EnemyAI)_ai).previousBehaviourStateIndex);
		}
	}
	public abstract class Notifier<TEnemyAI, TEventBroker> : Notifier<TEnemyAI> where TEnemyAI : EnemyAI where TEventBroker : EventBroker
	{
		protected class NotifierPatches
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(EnemyAI), "SwitchToBehaviourStateOnLocalClient")]
			public static void __EnemyAI_SwitchToBehaviourStateOnLocalClient(EnemyAI __instance, int stateIndex)
			{
				if (__instance is TEnemyAI)
				{
					UnifiedChaosPlugin.Instance.LogDebug(string.Format("{0}::{1}", typeof(TEnemyAI), "__EnemyAI_SwitchToBehaviourStateOnLocalClient"), "Method called!", verboseOnly: true);
					Notifier<TEnemyAI, TEventBroker> component = ((Component)__instance).gameObject.GetComponent<Notifier<TEnemyAI, TEventBroker>>();
					if (Object.op_Implicit((Object)(object)component))
					{
						component.OnChangeBehaviorStateLocalClient(stateIndex);
					}
				}
			}
		}

		private static Guid? _patchId;

		private static bool _isPatched;

		private readonly object _patchLock = new object();

		protected TEventBroker _broker;

		static Notifier()
		{
		}

		protected virtual void OnDestroy()
		{
			UnifiedChaosPlugin.Instance.LogDebug(((object)this).GetType().Name + "::OnDestroy", "Method called!");
			_broker.UnregisterNotifier(this);
		}

		protected virtual void ApplyPatches()
		{
			Harmony.CreateAndPatchAll(typeof(NotifierPatches), (string)null);
		}

		public void Initialize(TEnemyAI aiInstance, TEventBroker brokerInstance)
		{
			_ai = aiInstance;
			_broker = brokerInstance;
			Initialize();
			_broker.RegisterNotifier(this);
			lock (_patchLock)
			{
				if (_isPatched)
				{
					return;
				}
				_isPatched = true;
			}
			ApplyPatches();
		}

		protected abstract void OnChangeBehaviorStateLocalClient(int stateIndex);
	}
	public class SpringManAINotifier : Notifier<SpringManAI, SpringManEventBroker>
	{
		public enum BehaviorState
		{
			Roaming,
			Chasing
		}

		private class SpringManNotifierCoroutineManager : CoroutineManager<SpringManAINotifier>
		{
			public enum StareEventArgs
			{
				Short,
				Medium,
				Long
			}

			private readonly RandomDelayCoroutine _stareLong;

			private readonly RandomDelayCoroutine _stareMedium;

			private readonly RandomDelayCoroutine _stareShort;

			protected internal event Action<StareEventArgs> StareEventTrigger;

			protected internal SpringManNotifierCoroutineManager(SpringManAINotifier notifier)
				: base(notifier)
			{
				_stareShort = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 1f, 3f);
				_stareMedium = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 5f, 15f);
				_stareLong = new RandomDelayCoroutine((MonoBehaviour)(object)notifier, 30f, 60f);
			}

			private void StareLStart()
			{
				_stareMedium.Start(delegate
				{
					this.StareEventTrigger?.Invoke(StareEventArgs.Long);
				});
			}

			private void StareMStart()
			{
				_stareMedium.Start(delegate
				{
					this.StareEventTrigger?.Invoke(StareEventArgs.Medium);
					StareLStart();
				});
			}

			private void StareSStart()
			{
				_stareShort.Start(delegate
				{
					this.StareEventTrigger?.Invoke(StareEventArgs.Short);
					StareMStart();
				});
			}

			public void StareStart()
			{
				StareStart(restart: false);
			}

			public void StareStart(bool restart)
			{
				if (restart)
				{
					StareStop();
				}
				_stareShort.Start(StareSStart);
			}

			public void StareStop()
			{
				_stareShort.Stop();
				_stareMedium.Stop();
				_stareLong.Stop();
			}
		}

		private readonly SpringManNotifierCoroutineManager _coroutineManager;

		private bool _lastStoppingMovement;

		public SpringManAINotifier()
		{
			_coroutineManager = new SpringManNotifierCoroutineManager(this);
			_coroutineManager.StareEventTrigger += CoroutineManagerOnStareEventTrigger;
		}

		private void CoroutineManagerOnStareEventTrigger(SpringManNotifierCoroutineManager.StareEventArgs e)
		{
			switch (e)
			{
			case SpringManNotifierCoroutineManager.StareEventArgs.Short:
				_broker.AIEventNotify(this, "StaringAtPlayer");
				break;
			case SpringManNotifierCoroutineManager.StareEventArgs.Medium:
				_broker.AIEventNotify(this, "StaringAtPlayerForAWhile");
				break;
			case SpringManNotifierCoroutineManager.StareEventArgs.Long:
				_broker.AIEventNotify(this, "StaringAtPlayerForALongTime");
				break;
			default:
				throw new ArgumentOutOfRangeException("e", e, null);
			}
		}

		public override void Update()
		{
			CheckForStaringAtPlayer();
		}

		private void CheckForStaringAtPlayer()
		{
			if (_lastStoppingMovement != _ai.stoppingMovement)
			{
				_lastStoppingMovement = _ai.stoppingMovement;
				Action action = (_lastStoppingMovement ? new Action(_coroutineManager.StareStart) : new Action(_coroutineManager.StareStop));
				action();
			}
		}

		protected override void Initialize()
		{
		}

		protected override void OnChangeBehaviorStateLocalClient(int stateIndex)
		{
			BehaviorState enumValue = GetEnumValue<BehaviorState>(stateIndex);
			if ((uint)enumValue > 1u)
			{
				UnifiedChaosPlugin.Instance.LogWarning(((object)this).GetType().Name + "::OnChangeBehaviorStateLocalClient", $"Unknown behavior state: {stateIndex}");
			}
		}
	}
}
namespace TeamChaos.UnifiedChaosPack.PluginManagers.MobPlus.EventBrokers
{
	public abstract class EventBroker
	{
		public abstract Type EnemyType { get; }

		public abstract EnemyAI GetEnemyInstanceByNetworkId(ulong id);

		public abstract void RegisterNotifier(Notifier notifier);

		public abstract void UnregisterNotifier(Notifier notifier);
	}
	public abstract class EventBroker<TNotifier> : EventBroker where TNotifier : Notifier
	{
		protected readonly Dictionary<ulong, TNotifier> _notifiers = new Dictionary<ulong, TNotifier>();

		protected internal abstract void ApplyPatches();

		public override void RegisterNotifier(Notifier notifier)
		{
			if (notifier is TNotifier)
			{
				if (_notifiers.ContainsKey(notifier.NetworkObjectId))
				{
					_notifiers.Remove(notifier.NetworkObjectId);
				}
				_notifiers.Add(notifier.NetworkObjectId, (TNotifier)notifier);
			}
		}

		public override void UnregisterNotifier(Notifier notifier)
		{
			if (notifier is TNotifier && _notifiers.ContainsKey(notifier.NetworkObjectId))
			{
				_notifiers.Remove(notifier.NetworkObjectId);
			}
		}
	}
	public abstract class EventBroker<TNotifier, TEnemyAI, TEventBroker> : EventBroker<TNotifier> where TNotifier : Notifier<TEnemyAI, TEventBroker> where TEnemyAI : EnemyAI where TEventBroker : EventBroker<TNotifier>, new()
	{
		protected class EventBrokerPatches
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(EnemyAI), "Start")]
			public static void __EnemyAI_Start(EnemyAI __instance)
			{
				if (__instance is TEnemyAI)
				{
					UnifiedChaosPlugin.Instance.LogDebug(string.Format("{0}::{1}", typeof(TEnemyAI), "__EnemyAI_Start"), "Method called!");
					((Component)__instance).gameObject.AddComponent<TNotifier>().Initialize((TEnemyAI)(object)__instance, EventBroker<TNotifier, TEnemyAI, TEventBroker>._instance);
					DumpBehaviourStates(__instance);
				}
			}

			public static void Apply()
			{
				throw new NotImplementedException();
			}

			private static void DumpBehaviourStates(EnemyAI instance)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("    /// <summary>");
				stringBuilder.AppendLine("    ///     EnemyBehaviorStates:");
				for (int j = 0; j < instance.enemyBehaviourStates.Length; j++)
				{
					EnemyBehaviourState val = instance.enemyBehaviourStates[j];
					stringBuilder.AppendLine("    ///     --------");
					stringBuilder.AppendLine($"    ///     index:{j}");
					stringBuilder.AppendLine("    ///     Name:" + val.name);
					stringBuilder.AppendLine($"    ///     playOneShotSFX:{val.playOneShotSFX}");
					AudioClip sFXClip = val.SFXClip;
					stringBuilder.AppendLine("    ///     SFXClip:" + (((sFXClip != null) ? ((Object)sFXClip).name : null) ?? "null"));
					stringBuilder.AppendLine($"    ///     playOneShotVoice:{val.playOneShotVoice}");
					AudioClip voiceClip = val.VoiceClip;
					stringBuilder.AppendLine("    ///     VoiceClip:" + (((voiceClip != null) ? ((Object)voiceClip).name : null) ?? "null"));
					stringBuilder.AppendLine($"    ///     boolValue:{val.boolValue}");
					stringBuilder.AppendLine($"    ///     IsAnimTrigger:{val.IsAnimTrigger}");
					stringBuilder.AppendLine("    ///     parameterString:" + val.parameterString);
				}
				stringBuilder.AppendLine("    /// </summary>");
				stringBuilder.Append("    private enum BehaviorState { ").AppendJoin(", ", instance.enemyBehaviourStates.Select((EnemyBehaviourState s, int i) => $"{StringUtilsExtensions.ToPascalCase(s.name)} = {i}")).AppendLine(" }");
				UnifiedChaosPlugin.Instance.LogDebug("EventBrokerPatches+" + typeof(TEnemyAI).Name + "::enemyBehaviourStates", stringBuilder.ToString());
			}
		}

		private static TEventBroker _instance;

		private static readonly object _createLock = new object();

		public override Type EnemyType => typeof(TEnemyAI);

		protected static TNotifier GetNotifierInstance(TEnemyAI enemyAI)
		{
			return ((Component)(object)enemyAI).gameObject.GetComponent<TNotifier>();
		}

		internal abstract void AIEventNotify(TNotifier notifier, string evtName);

		protected internal override void ApplyPatches()
		{
			Harmony.CreateAndPatchAll(typeof(TEventBroker), (string)null);
			Harmony.CreateAndPatchAll(typeof(EventBrokerPatches), (string)null);
		}

		public override EnemyAI GetEnemyInstanceByNetworkId(ulong id)
		{
			object obj;
			if (!_notifiers.TryGetValue(id, out var value))
			{
				obj = default(TEnemyAI);
			}
			else
			{
				TNotifier val = value;
				obj = ((val != null) ? val.AiInstance : default(TEnemyAI));
			}
			return (EnemyAI)(object)(TEnemyAI)obj;
		}

		public static TEventBroker GetInstance()
		{
			if (_instance == null)
			{
				lock (_createLock)
				{
					UnifiedChaosPlugin.Instance.LogDebug("SpringManAINotifier::GetInstance", "Creating Instance.");
					_instance = new TEventBroker();
					_instance.ApplyPatches();
				}
			}
			return _instance;
		}
	}
	public class FlowermanEventBroker : EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>
	{
		public event Action<FlowermanAI, PlayerControllerB> AngryAtPlayer;

		public event Action<FlowermanAI, bool, PlayerControllerB> KilledPlayer;

		public event Action<FlowermanAI, PlayerControllerB> EvadingPlayer;

		public event Action<FlowermanAI, PlayerControllerB> StaringDownPlayer;

		public event Action<FlowermanAI, bool> DroppingBody;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "DropPlayerBody")]
		public static void __DropPlayerBody(FlowermanAI __instance)
		{
			if (__instance.carryingPlayerBody)
			{
				FlowermanAINotifier notifierInstance = EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>.GetNotifierInstance(__instance);
				notifierInstance.DroppingBody();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "FinishKillAnimation")]
		public static void __FinishKillAnimation(FlowermanAI __instance, bool carryingBody)
		{
			FlowermanAINotifier notifierInstance = EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>.GetNotifierInstance(__instance);
			notifierInstance.KilledPlayer(carryingBody);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FlowermanAI), "LookAtFlowermanTrigger")]
		public static void __LookAtFlowermanTrigger(FlowermanAI __instance, bool __state)
		{
			if (!(!__instance.evadeModeStareDown || __state))
			{
				FlowermanAINotifier notifierInstance = EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>.GetNotifierInstance(__instance);
				notifierInstance.StaringDownPlayer();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "LookAtFlowermanTrigger")]
		public static void __LookAtFlowermanTriggerPrefix(FlowermanAI __instance, ref bool __state)
		{
			__state = __instance.evadeModeStareDown;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FlowermanAI), "Update")]
		public static void __Update(FlowermanAI __instance, bool __state)
		{
			if (!(!__instance.wasInEvadeMode || __state))
			{
				FlowermanAINotifier notifierInstance = EventBroker<FlowermanAINotifier, FlowermanAI, FlowermanEventBroker>.GetNotifierInstance(__instance);
				notifierInstance.EvadingPlayer();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FlowermanAI), "Update")]
		public static void __UpdatePrefix(FlowermanAI __instance, ref bool __state)
		{
			__state = __instance.wasInEvadeMode;
		}

		internal override void AIEventNotify(FlowermanAINotifier notifier, string evtName)
		{
			UnifiedChaosPlugin.Instance.LogError(GetType().Name + "::AIEventNotify", string.Format("Event '{0} fired for {1}[{2}]'!", evtName, "HoarderBugAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
			switch (evtName)
			{
			case "KilledPlayer":
				this.KilledPlayer?.Invoke(notifier.AiInstance, notifier.CarryingBody, notifier.PlayerKilled);
				break;
			case "DroppingBody":
				this.DroppingBody?.Invoke(notifier.AiInstance, notifier.AtFavoriteSpot);
				break;
			case "StaringDownPlayer":
				this.StaringDownPlayer?.Invoke(notifier.AiInstance, notifier.TargetPlayer);
				break;
			case "EvadingPlayer":
				this.StaringDownPlayer?.Invoke(notifier.AiInstance, notifier.TargetPlayer);
				break;
			case "AngryAtPlayer":
				this.AngryAtPlayer?.Invoke(notifier.AiInstance, notifier.TargetPlayer);
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning(GetType().Name + "::AIEventNotify", string.Format("Unhandled event '{0} fired for {1}[{2}]'!", evtName, "HoarderBugAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
				break;
			}
		}
	}
	public class HoarderBugEventBroker : EventBroker<HoarderBugAINotifier, HoarderBugAI, HoarderBugEventBroker>
	{
		public event Action<HoarderBugAI, PlayerControllerB> AngryAtPlayer;

		public event Action<HoarderBugAI, PlayerControllerB> ChangedWatchingPlayer;

		public event Action<HoarderBugAI, GrabbableObject> HuntingItem;

		public event Action<HoarderBugAI> GaveUpChase;

		public event Action<HoarderBugAI> GaveUpSearch;

		public event Action<HoarderBugAI, HoarderBugItem> ItemDropped;

		public event Action<HoarderBugAI, HoarderBugItem> ItemDroppedInNest;

		public event Action<HoarderBugAI, HoarderBugItem> ItemGrabbed;

		[HarmonyPatch(typeof(HoarderBugAI), "DetectAndLookAtPlayers")]
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> __ChangedWatchingPlayer(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(HoarderBugEventBroker), "__ChangedWatchingPlayerHook", new Type[1] { typeof(HoarderBugAI) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(RoundManager), "PlayRandomClip", new Type[6]
			{
				typeof(AudioSource),
				typeof(AudioClip[]),
				typeof(bool),
				typeof(float),
				typeof(int),
				typeof(int)
			}, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, methodInfo2))
				{
					list.RemoveRange(list.Count - 8, 8);
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo));
				}
				else
				{
					list.Add(instruction);
				}
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}

		private static int __ChangedWatchingPlayerHook(HoarderBugAI __instance)
		{
			UnifiedChaosPlugin.Instance.LogDebug("HoarderBugEventBroker::__ChangedWatchingPlayerHook", "Method called!");
			HoarderBugAINotifier component = ((Component)__instance).gameObject.GetComponent<HoarderBugAINotifier>();
			component.ChangedWatchingPlayer();
			return int.MinValue;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HoarderBugAI), "DropItemClientRpc")]
		public static void __DropItemClientRpc(HoarderBugAI __instance, bool droppedInNest)
		{
			UnifiedChaosPlugin.Instance.LogDebug("HoarderBugEventBroker::__DropItemClientRpc", "Method called!");
			HoarderBugAINotifier component = ((Component)__instance).gameObject.GetComponent<HoarderBugAINotifier>();
			component.DropItem(droppedInNest);
		}

		internal override void AIEventNotify(HoarderBugAINotifier notifier, string evtName)
		{
			UnifiedChaosPlugin.Instance.LogError(GetType().Name + "::AIEventNotify", string.Format("Event '{0} fired for {1}[{2}]'!", evtName, "HoarderBugAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
			switch (evtName)
			{
			case "AngryAtPlayer":
				this.AngryAtPlayer?.Invoke(notifier.AiInstance, notifier.AiInstance.angryAtPlayer);
				break;
			case "ChangedWatchingPlayer":
				this.ChangedWatchingPlayer?.Invoke(notifier.AiInstance, notifier.AiInstance.watchingPlayer);
				break;
			case "GaveUpChase":
				this.GaveUpChase?.Invoke(notifier.AiInstance);
				break;
			case "GaveUpSearch":
				this.GaveUpSearch?.Invoke(notifier.AiInstance);
				break;
			case "ItemDropped":
				this.ItemDropped?.Invoke(notifier.AiInstance, notifier.AiInstance.heldItem);
				break;
			case "ItemDroppedInNest":
				this.ItemDroppedInNest?.Invoke(notifier.AiInstance, notifier.AiInstance.heldItem);
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning(GetType().Name + "::AIEventNotify", string.Format("Unhandled event '{0} fired for {1}[{2}]'!", evtName, "HoarderBugAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
				break;
			case "HuntingItem":
				break;
			case "ItemGrabbed":
				break;
			}
		}
	}
	public class SpringManEventBroker : EventBroker<SpringManAINotifier, SpringManAI, SpringManEventBroker>
	{
		public event Action<SpringManAI, PlayerControllerB> StaringAtPlayer;

		public event Action<SpringManAI, PlayerControllerB> StaringAtPlayerForALongTime;

		public event Action<SpringManAI, PlayerControllerB> StaringAtPlayerForAWhile;

		internal override void AIEventNotify(SpringManAINotifier notifier, string evtName)
		{
			UnifiedChaosPlugin.Instance.LogDebug(GetType().Name + "::AIEventNotify", string.Format("Event '{0} fired for {1}[{2}]'!", evtName, "SpringManAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
			switch (evtName)
			{
			case "StaringAtPlayer":
				this.StaringAtPlayer?.Invoke(notifier.AiInstance, IsLookingAtSpringMan(notifier.AiInstance));
				break;
			case "StaringAtPlayerForAWhile":
				this.StaringAtPlayerForAWhile?.Invoke(notifier.AiInstance, IsLookingAtSpringMan(notifier.AiInstance));
				break;
			case "StaringAtPlayerForALongTime":
				this.StaringAtPlayerForALongTime?.Invoke(notifier.AiInstance, IsLookingAtSpringMan(notifier.AiInstance));
				break;
			default:
				UnifiedChaosPlugin.Instance.LogWarning(GetType().Name + "::AIEventNotify", string.Format("Unhandled event '{0} fired for {1}[{2}]'!", evtName, "SpringManAI", ((NetworkBehaviour)notifier.AiInstance).NetworkObjectId));
				break;
			}
		}

		[CanBeNull]
		private PlayerControllerB IsLookingAtSpringMan(SpringManAI ai)
		{
			//IL_0019: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			Vector3 lineOfSightPosition = ((Component)ai).transform.position + Vector3.up * 1.6f;
			float lineOfSightRange = 68