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