Decompiled source of ExperimentalEnemyInteractions v0.5.30
DLLs/fandovec03.NaturalSelection.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CleaningCompany; using EnhancedMonsters.Monobehaviours; using GameNetcodeStuff; using HarmonyLib; using LethalNetworkAPI; using LobbyCompatibility.Enums; using LobbyCompatibility.Features; using Microsoft.CodeAnalysis; using NaturalSelection.Compatibility; using NaturalSelection.EnemyPatches; using NaturalSelection.Generics; using NaturalSelectionLib; using ReXuvination.src; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("EnhancedMonsters")] [assembly: IgnoresAccessChecksTo("ReXuvination")] [assembly: IgnoresAccessChecksTo("SellBodies")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("fandovec03.NaturalSelection")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.4.6.0")] [assembly: AssemblyInformationalVersion("0.4.6+54ff48bd0614f776f9058a0d8edf5dfd364673d9")] [assembly: AssemblyProduct("NaturalSelection")] [assembly: AssemblyTitle("fandovec03.NaturalSelection")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.6.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NaturalSelection { [BepInPlugin("fandovec03.NaturalSelection", "NaturalSelection", "0.4.6")] [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.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Script : BaseUnityPlugin { public static ManualLogSource Logger = null; internal static bool stableToggle; private static bool isExperimental = false; private static bool isPrerelease = false; private static bool debugBool = false; private static bool debugKillSwitch = false; private static bool spammyLogs = false; private static bool debugNetworking = false; private static bool debugLibrary = false; private static bool debugLibraryTrigger = false; private static bool debugTriggerFlags = false; private static bool debugGiants = false; private static bool debugHygrodere = false; private static bool debugNutcrackers = false; private static bool debugRedBees = false; private static bool debugSandworms = false; private static bool debugSpiders = false; private static bool debugSpiderWebs = false; private static bool debugUnspecified = false; internal static bool enhancedMonstersPresent = false; internal static bool sellBodiesPresent = false; internal static bool rexuvinationPresent = false; internal static bool CompatibilityAutoToggle = false; internal static bool LobbyCompatibilityPresent = false; internal static bool usePathfindingLib = false; internal static bool usePathToFindClosestEnemy = false; internal static Dictionary<string, bool> Bools = new Dictionary<string, bool>(); internal static List<EnemyAI> loadedEnemyList = new List<EnemyAI>(); public static Action<string, bool>? OnConfigSettingChanged; private static bool debugKillSwitchScript = false; public static Script Instance { get; private set; } = null; internal static Harmony? Harmony { get; set; } internal static MyModConfig BoundingConfig { get; set; } = null; private static void SubscribeDebugConfigBools(ConfigEntry<bool> entryKey, bool boolParam, string entry) { ConfigEntry<bool> entryKey2 = entryKey; string entry2 = entry; entryKey2.SettingChanged += delegate { boolParam = entryKey2.Value; Logger.LogMessage((object)$"Updating with entry.Value {entryKey2.Value}. Result: {boolParam}"); OnConfigSettingChanged?.Invoke(entry2, entryKey2.Value); }; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; BoundingConfig = new MyModConfig(((BaseUnityPlugin)this).Config); stableToggle = BoundingConfig.stableMode.Value; Bools.Add("debugBool", debugBool); Bools.Add("debugKillSwitch", debugKillSwitch); Bools.Add("spammyLogs", spammyLogs); Bools.Add("debugNetworking", debugNetworking); Bools.Add("debugLibraryTrigger", debugLibraryTrigger); Bools.Add("debugLibrary", debugLibrary); Bools.Add("debugTriggerFlags", debugTriggerFlags); Bools.Add("debugGiants", debugGiants); Bools.Add("debugHygrodere", debugHygrodere); Bools.Add("debugNutcrackers", debugNutcrackers); Bools.Add("debugRedBees", debugRedBees); Bools.Add("debugSandworms", debugSandworms); Bools.Add("debugSpiders", debugSpiders); Bools.Add("debugSpiderWebs", debugSpiderWebs); Bools.Add("debugUnspecified", debugUnspecified); CompatibilityAutoToggle = BoundingConfig.CompatibilityAutoToggle.Value; usePathfindingLib = BoundingConfig.usePathfindinglibCoroutines.Value; usePathToFindClosestEnemy = BoundingConfig.usePathToFindClosestEnemy.Value; foreach (KeyValuePair<string, ConfigEntry<bool>> debugEntry in BoundingConfig.debugEntries) { if (Bools.ContainsKey(debugEntry.Key)) { Bools[debugEntry.Key] = debugEntry.Value.Value; SubscribeDebugConfigBools(debugEntry.Value, Bools[debugEntry.Key], debugEntry.Key); } else { Logger.LogError((object)("Failed to find bool for config entry " + debugEntry.Key)); } } char[] array = "0.4.6".ToCharArray(); if ((array[0] == '9' && array[1] == '9') || (array[0] == '8' && array[1] == '8')) { if (array[0] == '9' && array[1] == '9') { isExperimental = true; } if (array[0] == '8' && array[1] == '8') { isPrerelease = true; } array[0] = '0'; array[1] = '0'; } Patch(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(array); Logger.LogInfo((object)string.Format("{0} v{1} has loaded!", "fandovec03.NaturalSelection", stringBuilder)); OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } internal static void Patch() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("fandovec03.NaturalSelection"); } Logger.LogInfo((object)"Patching NaturalSelection..."); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { string text = ""; if (!CompatibilityAutoToggle) { break; } switch (pluginInfo.Key) { case "com.velddev.enhancedmonsters": enhancedMonstersPresent = true; text = "Found Enhanced Monsters"; break; case "Entity378.sellbodies": sellBodiesPresent = true; text = "Found SellbodiesFixed"; break; case "XuuXiaolan.ReXuvination": rexuvinationPresent = true; text = "Found ReXuvination"; break; case "BMX.LobbyCompatibility": LobbyCompatibilityPresent = true; text = "Found LobbyCompatibility"; break; } if (text != "") { Logger.LogInfo((object)(text + ". Automatically loading compatibility.")); } } try { LobbyCompCompatibility.RegisterLobbyComp("fandovec03.NaturalSelection", Version.Parse("0.4.6")); } catch { } foreach (KeyValuePair<string, ConfigEntry<bool>> compatibilityEntry in BoundingConfig.CompatibilityEntries) { string text2 = ""; if (compatibilityEntry.Value.Value) { switch (compatibilityEntry.Key) { case "com.velddev.enhancedmonsters": enhancedMonstersPresent = true; break; case "Entity378.sellbodies": sellBodiesPresent = true; break; case "XuuXiaolan.ReXuvination": rexuvinationPresent = true; break; } text2 = "Manually enabling compatibility for " + compatibilityEntry.Key + "."; } if (text2 != "") { Logger.LogInfo((object)text2); } } if (isExperimental) { Logger.LogFatal((object)("LOADING EXPERIMENTAL BUILD OF " + "NaturalSelection".ToUpper() + ", DOWNLOAD NATURAL SELECTION INSTEAD FOR MORE STABLE EXPERIENCE!")); } if (isPrerelease) { Logger.LogWarning((object)("LOADING PRERELASE BUILD OF " + "NaturalSelection".ToUpper() + ", DOWNLOAD NATURAL SELECTION INSTEAD FOR MORE STABLE EXPERIENCE!")); } Harmony.PatchAll(typeof(AICollisionDetectPatch)); Harmony.PatchAll(typeof(EnemyAIPatch)); Harmony.PatchAll(typeof(Networking)); Harmony.PatchAll(typeof(NetworkingMethods)); Harmony.PatchAll(typeof(InitializeGamePatch)); try { NaturalSelectionLib.SetLibraryLoggers(Logger, spammyLogs, debugLibrary, usePathfindingLib); Logger.LogMessage((object)("Library successfully setup! Version " + NaturalSelectionLib.ReturnVersion())); } catch { Logger.LogError((object)"Failed to setup library!"); } Harmony.PatchAll(typeof(RoundManagerPatch)); if (BoundingConfig.enableLeviathan.Value) { Harmony.PatchAll(typeof(SandWormAIPatch)); } if (BoundingConfig.enableSlime.Value) { Harmony.PatchAll(typeof(BlobAIPatch)); } if (BoundingConfig.enableHoardingBug.Value) { Harmony.PatchAll(typeof(HoarderBugPatch)); } if (BoundingConfig.enableRedBees.Value) { Harmony.PatchAll(typeof(BeeAIPatch)); } if (BoundingConfig.enableGiant.Value) { Harmony.PatchAll(typeof(ForestGiantPatch)); } if (BoundingConfig.enableSpiderWebs.Value) { Harmony.PatchAll(typeof(SandSpiderWebTrapPatch)); } if (BoundingConfig.enableSpider.Value) { Harmony.PatchAll(typeof(SandSpiderAIPatch)); } if (enhancedMonstersPresent) { Harmony.PatchAll(typeof(EnhancedMonstersCompatibility)); Logger.LogInfo((object)"Loading compatibility for Enhanced Monsters"); } if (sellBodiesPresent) { SellBodiesFixedCompatibility.AddTracerScriptToPrefabs(); Logger.LogInfo((object)"Loading compatibility for SellbodiesFixed"); } if (rexuvinationPresent) { Harmony.PatchAll(typeof(ReXuvinationPatch)); Logger.LogInfo((object)"Loading compatibility for Rexuvination"); } if (!stableToggle) { if (isExperimental) { if (BoundingConfig.enableNutcracker.Value) { Harmony.PatchAll(typeof(NutcrackerAIPatch)); } if (BoundingConfig.enableSporeLizard.Value) { Harmony.PatchAll(typeof(PufferAIPatch)); } } else { Logger.LogWarning((object)"Limited access. Some patches cannot be enabled in stable branch."); } Logger.LogInfo((object)"Stable mode off. Loaded all patches."); } else { Logger.LogInfo((object)"Stable mode on. Excluded unstable and WIP patches from loading."); } Logger.LogInfo((object)"Finished patching NaturalSelection !"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } public static void LogNS(LogLevel logLevel, string log, object? source = null, bool toggle = true, bool moreDetail = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (toggle && !debugKillSwitchScript) { Logger.Log(logLevel, (object)(LibraryCalls.DebugStringHead(source, !moreDetail) + " " + log)); } } private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugKillSwitch") { debugKillSwitchScript = value; } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "fandovec03.NaturalSelection"; public const string PLUGIN_NAME = "NaturalSelection"; public const string PLUGIN_VERSION = "0.4.6"; } } namespace NaturalSelection.Generics { internal class InitializeGamePatch { private static bool finishedLoading = false; private static List<string> loadedEnemyNamesFromConfig = new List<string>(); private static List<string> beeBlacklistLoaded = Script.BoundingConfig.beeBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> blobBlacklistLoaded = Script.BoundingConfig.blobBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> sandwormBlacklistLoaded = Script.BoundingConfig.sandwormBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> spiderWebBlacklistLoaded = Script.BoundingConfig.spiderWebBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> speedModifierLoaded = Script.BoundingConfig.speedModifierList.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> spiderBlacklistLoaded = Script.BoundingConfig.spiderBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> customSizeOverrideListLoaded = Script.BoundingConfig.customSizeOverrideList.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); internal static List<string> beeBlacklist = new List<string>(); internal static List<string> blobBlacklist = new List<string>(); internal static List<string> sandwormBlacklist = new List<string>(); internal static List<string> spiderWebBlacklist = new List<string>(); internal static List<string> speedModifier = new List<string>(); internal static List<string> spiderBlacklist = new List<string>(); internal static List<string> customSizeOverrideList = new List<string>(); public static Dictionary<string, float> speedModifierDictionay = new Dictionary<string, float>(); public static Dictionary<string, int> customSizeOverrideListDictionary = new Dictionary<string, int>(); public static List<EnemyAI> tryFindLater = new List<EnemyAI>(); [HarmonyPatch(typeof(InitializeGame), "Start")] [HarmonyPostfix] public static void InitializeGameStartPatch() { Script.loadedEnemyList = Resources.FindObjectsOfTypeAll<EnemyAI>().ToList(); if (!finishedLoading) { Script.Logger.Log((LogLevel)8, (object)"Reading/Checking/Writing entries for enemies."); ReadConfigLists(); CheckConfigLists(Script.loadedEnemyList); WriteToConfigLists(); } LibraryCalls.SubscribeToConfigChanges(); Networking.SubscribeToConfigChanges(); finishedLoading = true; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void StartOfRoundPatch() { if (tryFindLater.Count > 0) { Script.Logger.Log((LogLevel)8, (object)"Secondary list is not empty. Checking/Writing entries for skipped enemies"); try { CheckConfigLists(tryFindLater); WriteToConfigLists(); tryFindLater.Clear(); } catch { Script.Logger.Log((LogLevel)2, (object)"An error has occured while working with the list."); tryFindLater.Clear(); } } } public static void ReadConfigLists() { foreach (string item in speedModifierLoaded) { try { string text = item.Split(":")[0]; float num = float.Parse(item.Split(":")[1].Replace(".", ",")); speedModifierDictionay.Add(text, num); Script.Logger.Log((LogLevel)32, (object)$"Found {text}, {num}"); } catch (Exception ex) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into speedModifierDictionary"); Script.Logger.Log((LogLevel)2, (object)item); Script.Logger.Log((LogLevel)2, (object)item.Split(":")[0]); Script.Logger.Log((LogLevel)2, (object)item.Split(":")[1]); Script.Logger.Log((LogLevel)2, (object)ex); } } foreach (string item2 in beeBlacklistLoaded) { try { beeBlacklist.Add(item2); Script.Logger.Log((LogLevel)32, (object)("Found " + item2)); } catch (Exception ex2) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into beeBlacklist"); Script.Logger.Log((LogLevel)2, (object)item2); Script.Logger.Log((LogLevel)2, (object)ex2); } } foreach (string item3 in blobBlacklistLoaded) { try { blobBlacklist.Add(item3); Script.Logger.Log((LogLevel)32, (object)("Found " + item3)); } catch (Exception ex3) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into blobBlacklist"); Script.Logger.Log((LogLevel)2, (object)item3); Script.Logger.Log((LogLevel)2, (object)ex3); } } foreach (string item4 in sandwormBlacklistLoaded) { try { sandwormBlacklist.Add(item4); Script.Logger.Log((LogLevel)32, (object)("Found " + item4)); } catch (Exception ex4) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into sandwormBlacklist"); Script.Logger.Log((LogLevel)2, (object)item4); Script.Logger.Log((LogLevel)2, (object)ex4); } } foreach (string item5 in spiderWebBlacklistLoaded) { try { spiderWebBlacklist.Add(item5); Script.Logger.Log((LogLevel)32, (object)("Found " + item5)); } catch (Exception ex5) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into spiderWebBlacklist"); Script.Logger.Log((LogLevel)2, (object)item5); Script.Logger.Log((LogLevel)2, (object)ex5); } } foreach (string item6 in spiderBlacklistLoaded) { try { spiderBlacklist.Add(item6); Script.Logger.Log((LogLevel)32, (object)("Found " + item6)); } catch (Exception ex6) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into spiderBlacklist"); Script.Logger.Log((LogLevel)2, (object)item6); Script.Logger.Log((LogLevel)2, (object)ex6); } } foreach (string item7 in customSizeOverrideListLoaded) { try { string text2 = item7.Split(":")[0]; int num2 = int.Parse(item7.Split(":")[1]); if (num2 < 0 || num2 > 5) { Script.Logger.Log((LogLevel)2, (object)$"Invalid size value {num2}. Defaulting to (0 || {CustomEnemySize.Undefined})"); num2 = 0; } customSizeOverrideListDictionary.Add(text2, num2); Script.Logger.Log((LogLevel)32, (object)$"Found {text2}, {(CustomEnemySize)num2}"); } catch (Exception ex7) { Script.Logger.Log((LogLevel)2, (object)"Failed to add enemy into customSizeOverrideListList"); Script.Logger.Log((LogLevel)2, (object)item7); Script.Logger.Log((LogLevel)2, (object)item7.Split(":")[0]); Script.Logger.Log((LogLevel)2, (object)item7.Split(":")[1]); Script.Logger.Log((LogLevel)2, (object)ex7); } } } public static void CheckConfigLists(List<EnemyAI> listOfEnemies) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected I4, but got Unknown foreach (EnemyAI listOfEnemy in listOfEnemies) { string enemyName; try { enemyName = listOfEnemy.enemyType.enemyName; } catch { Script.Logger.Log((LogLevel)4, (object)("Failed to get enemy name from " + ((Object)listOfEnemy).name + ". Adding to list for 2nd attempt.")); tryFindLater.Add(listOfEnemy); continue; } if (customSizeOverrideListLoaded.Count < 1) { EnemySize enemySize = listOfEnemy.enemyType.EnemySize; EnemySize val = enemySize; switch ((int)val) { case 0: if (!listOfEnemy.enemyType.canDie) { customSizeOverrideListDictionary[enemyName] = 0; } else if (listOfEnemy is FlowerSnakeEnemy || listOfEnemy is DoublewingAI || listOfEnemy is RedLocustBees || listOfEnemy is DocileLocustBeesAI || listOfEnemy is ButlerBeesEnemyAI) { customSizeOverrideListDictionary[enemyName] = 1; } else if (listOfEnemy.enemyHP <= 3) { customSizeOverrideListDictionary[enemyName] = 2; } else if (listOfEnemy.enemyHP <= 15) { customSizeOverrideListDictionary[enemyName] = 3; } else if (listOfEnemy.enemyHP <= 30) { customSizeOverrideListDictionary[enemyName] = 4; } else if (listOfEnemy.enemyHP > 30) { customSizeOverrideListDictionary[enemyName] = 5; } else { customSizeOverrideListDictionary[enemyName] = 0; } break; case 2: customSizeOverrideListDictionary[enemyName] = 3; break; case 1: customSizeOverrideListDictionary[enemyName] = 5; break; default: customSizeOverrideListDictionary[enemyName] = 0; break; } } if (!loadedEnemyNamesFromConfig.Contains(enemyName)) { loadedEnemyNamesFromConfig.Add(enemyName); } } foreach (string item in loadedEnemyNamesFromConfig) { Script.Logger.Log((LogLevel)16, (object)("Checking config entries for enemy: " + item)); if (!speedModifierDictionay.Keys.Contains(item)) { Script.Logger.Log((LogLevel)32, (object)("Generating new web speed modifier entry for " + item)); speedModifierDictionay.Add(item, 1f); } if (beeBlacklist.Count <= 0) { Script.Logger.Log((LogLevel)32, (object)("Generating new bee blacklist entry for " + item)); if (beeBlacklist.Contains("Earth Leviathan") || beeBlacklist.Contains("Docile Locust Bees")) { beeBlacklist.Add(item); } } if (!customSizeOverrideListDictionary.Keys.Contains(item)) { Script.Logger.Log((LogLevel)32, (object)("Generating new custom enemy size entry for " + item)); customSizeOverrideListDictionary.Add(item, 0); } } if (!Script.BoundingConfig.debugBool.Value) { return; } foreach (string item2 in beeBlacklist) { Script.Logger.Log((LogLevel)32, (object)("checking blacklist beeBlacklist -> " + item2)); } foreach (string item3 in sandwormBlacklist) { Script.Logger.Log((LogLevel)32, (object)("checking blacklist sandwormBlacklist -> " + item3)); } foreach (string item4 in spiderWebBlacklist) { Script.Logger.Log((LogLevel)32, (object)("checking blacklist spiderWebBlacklist -> " + item4)); } foreach (string item5 in spiderBlacklist) { Script.Logger.Log((LogLevel)32, (object)("checking blacklist spiderBlacklist -> " + item5)); } foreach (KeyValuePair<string, float> item6 in speedModifierDictionay) { Script.Logger.Log((LogLevel)32, (object)string.Format("checking speed modifier dictionary {0} -> {1}, {2}", "speedModifierDictionay", item6.Key, item6.Value)); } } public static void WriteToConfigLists() { string text = ""; string text2 = ""; string text3 = ""; string text4 = ""; string text5 = ""; string text6 = ""; string text7 = ""; string text8 = ""; try { foreach (string item in loadedEnemyNamesFromConfig) { text = text + item + ","; } Script.BoundingConfig.enemyNames.Value = text; foreach (KeyValuePair<string, float> item2 in speedModifierDictionay) { text2 = $"{text2}{item2.Key}:{item2.Value},"; } Script.BoundingConfig.speedModifierList.Value = text2; foreach (string item3 in beeBlacklist) { text3 = text3 + item3 + ","; } Script.BoundingConfig.beeBlacklist.Value = text3; foreach (string item4 in blobBlacklist) { text4 = text4 + item4 + ","; } Script.BoundingConfig.blobBlacklist.Value = text4; foreach (string item5 in sandwormBlacklist) { text5 = text5 + item5 + ","; } Script.BoundingConfig.sandwormBlacklist.Value = text5; foreach (string item6 in spiderWebBlacklist) { text6 = text6 + item6 + ","; } Script.BoundingConfig.spiderWebBlacklist.Value = text6; foreach (string item7 in spiderBlacklist) { text7 = text7 + item7 + ","; } Script.BoundingConfig.spiderBlacklist.Value = text7; foreach (KeyValuePair<string, int> item8 in customSizeOverrideListDictionary) { text8 = $"{text8}{item8.Key}:{item8.Value},"; } Script.BoundingConfig.customSizeOverrideList.Value = text8; Script.Logger.Log((LogLevel)16, (object)"Finished generating configucations."); } catch (Exception ex) { Script.Logger.Log((LogLevel)2, (object)"Failed to generate configucations."); Script.Logger.Log((LogLevel)2, (object)ex); } } } public class LibraryCalls { private static bool debugSpam = Script.Bools["spammyLogs"]; private static bool debugLibraryCalls = Script.Bools["debugLibrary"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "spammyLogs") { debugSpam = value; NaturalSelectionLib.SetLibraryLoggers(Script.Logger, value, debugLibraryCalls, false); } if (entryKey == "debugLibraryTrigger") { debugLibraryCalls = value; NaturalSelectionLib.SetLibraryLoggers(Script.Logger, debugSpam, value, false); } } public static void SubscribeToConfigChanges() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } public static string DebugStringHead(object? source, bool shortFormat = true) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library DebugStringHead!"); } return NaturalSelectionLib.DebugStringHead(source, shortFormat); } public static List<EnemyAI> GetCompleteList(EnemyAI instance, bool FilterThemselves = true, int includeOrReturnThedDead = 0) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library GetCompleteList!"); } return NaturalSelectionLib.GetCompleteList(instance, FilterThemselves, includeOrReturnThedDead); } public static void GetInsideOrOutsideEnemyList(ref List<EnemyAI> importEnemyList, EnemyAI instance) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library GetInsideOrOutsideEnemyList!"); } NaturalSelectionLib.GetInsideOrOutsideEnemyList(ref importEnemyList, instance); } public static EnemyAI? FindClosestEnemy(ref List<EnemyAI> importEnemyList, EnemyAI? importClosestEnemy, EnemyAI instance, int maxIterations = 6, bool useThreatVisibility = true, bool usePathLenghtAsDistance = false, bool includeTheDead = false) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library findClosestEnemy!"); } return NaturalSelectionLib.FindClosestEnemy(ref importEnemyList, importClosestEnemy, instance, maxIterations, useThreatVisibility, usePathLenghtAsDistance, includeTheDead); } public static void FilterEnemyList(ref List<EnemyAI> importEnemyList, List<string>? blacklist, EnemyAI instance, bool filterOutImmortal = true, bool filterTheSameType = true) { if (debugLibraryCalls) { Script.Logger.LogInfo((object)"Called library filterEnemyList!"); } if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library filterEnemyList!"); } NaturalSelectionLib.FilterEnemyList(ref importEnemyList, blacklist, instance, filterOutImmortal, filterTheSameType); } public static void FilterEnemySizes(ref Dictionary<EnemyAI, int> importEnemySizeDict, int[] enemySizes, EnemyAI instance, bool inverseToggle = false) { if (debugLibraryCalls) { Script.Logger.LogInfo((object)"Called library FilterEnemySizes!"); } if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library FilterEnemySizes!"); } NaturalSelectionLib.FilterEnemySizes(ref importEnemySizeDict, enemySizes, instance, inverseToggle); } public static void FilterEnemySizes(ref List<EnemyAI> importEnemySizeDict, EnemySize[] enemySizes, EnemyAI instance, bool inverseToggle = false) { if (debugLibraryCalls) { Script.Logger.LogInfo((object)"Called library FilterEnemySizes!"); } if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library FilterEnemySizes!"); } NaturalSelectionLib.FilterEnemySizes(ref importEnemySizeDict, enemySizes, instance, inverseToggle); } public static Dictionary<EnemyAI, float> GetEnemiesInLOS(EnemyAI instance, ref List<EnemyAI> importEnemyList, float width = 45f, int importRange = 0, float proximityAwareness = -1f, float importRadius = 0f, Vector3? importEyePosition = null) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library GetEnemiesInLOS!"); } return NaturalSelectionLib.GetEnemiesInLOS(instance, ref importEnemyList, width, (float)importRange, proximityAwareness, importRadius, importEyePosition); } public static Dictionary<EnemyAI, float> GetEnemiesInLOS(EnemyAI instance, float width = 45f, int importRange = 0, float proximityAwareness = -1f, float importRadius = 0f, Vector3? importEyePosition = null) { if (debugLibraryCalls) { Script.Logger.Log((LogLevel)16, (object)"Called library GetEnemiesInLOS!"); } return NaturalSelectionLib.GetEnemiesInLOS(instance, width, (float)importRange, proximityAwareness, importRadius, importEyePosition); } public static IEnumerator FindClosestEnemyEnumerator(Action<EnemyAI>? ReturnOwnerResult, List<EnemyAI> importEnemyList, EnemyAI? importClosestEnemy, EnemyAI instance, int maxIterations = 6, bool useThreatVisibility = true, bool usePathLenghtAsDistance = false, bool includeTheDead = false) { return NaturalSelectionLib.FindClosestEnemy(ReturnOwnerResult, importEnemyList, importClosestEnemy, instance, maxIterations, useThreatVisibility, usePathLenghtAsDistance, includeTheDead); } public static List<EnemyAI> GetEnemyList(Type type) { return NaturalSelectionLib.GetEnemyList(type); } } internal class MyModConfig { public readonly ConfigEntry<bool> useExperimentalCoroutines; public readonly ConfigEntry<bool> usePathfindinglibCoroutines; public readonly ConfigEntry<bool> usePathToFindClosestEnemy; public readonly ConfigEntry<bool> sandwormCollisionOverride; public readonly ConfigEntry<float> blobAIOpeningDoorsMultiplier; public readonly ConfigEntry<bool> stableMode; public readonly ConfigEntry<bool> IgnoreImmortalEnemies; public readonly ConfigEntry<float> agentRadiusModifier; public readonly ConfigEntry<float> globalListsUpdateInterval; public readonly ConfigEntry<string> customSizeOverrideList; public readonly ConfigEntry<bool> enableSpider; public readonly ConfigEntry<bool> enableSlime; public readonly ConfigEntry<bool> enableLeviathan; public readonly ConfigEntry<bool> enableSporeLizard; public readonly ConfigEntry<bool> enableRedBees; public readonly ConfigEntry<bool> enableNutcracker; public readonly ConfigEntry<bool> enableGiant; public readonly ConfigEntry<bool> enableHoardingBug; public readonly ConfigEntry<float> beesSetGiantsOnFireMinChance; public readonly ConfigEntry<float> beesSetGiantsOnFireMaxChance; public readonly ConfigEntry<int> giantExtinguishChance; public readonly ConfigEntry<bool> blobConsumesCorpses; public readonly ConfigEntry<bool> blobPathfindToCorpses; public readonly ConfigEntry<bool> blobPathfind; public readonly ConfigEntry<bool> sandwormDoNotEatPlayersInsideLeavingShip; public readonly ConfigEntry<bool> enableSpiderWebs; public readonly ConfigEntry<string> speedModifierList; public readonly ConfigEntry<float> webStrength; public readonly ConfigEntry<float> chaseAfterEnemiesModifier; public readonly ConfigEntry<string> enemyNames; public readonly ConfigEntry<string> beeBlacklist; public readonly ConfigEntry<string> blobBlacklist; public readonly ConfigEntry<string> sandwormBlacklist; public readonly ConfigEntry<string> spiderWebBlacklist; public readonly ConfigEntry<string> spiderBlacklist; public ConfigEntry<bool> debugBool; public ConfigEntry<bool> debugKillSwitch; public ConfigEntry<bool> spammyLogs; public ConfigEntry<bool> debugTriggerFlags; public ConfigEntry<bool> debugNetworking; public ConfigEntry<bool> debugRedBees; public ConfigEntry<bool> debugSandworms; public ConfigEntry<bool> debugHygrodere; public ConfigEntry<bool> debugNutcrackers; public ConfigEntry<bool> debugSpiders; public ConfigEntry<bool> debugGiants; public ConfigEntry<bool> debugUnspecified; public ConfigEntry<bool> debugLibrary; public ConfigEntry<bool> debugLibraryTrigger; public ConfigEntry<bool> debugSpiderWebs; public Dictionary<string, ConfigEntry<bool>> debugEntries = new Dictionary<string, ConfigEntry<bool>>(); public Dictionary<string, ConfigEntry<bool>> CompatibilityEntries = new Dictionary<string, ConfigEntry<bool>>(); public ConfigEntry<bool> CompatibilityAutoToggle; public ConfigEntry<bool> enhancedMonstersCompToggle; public ConfigEntry<bool> sellBodiesFixedCompToggle; public ConfigEntry<bool> ReXuvinationCompToggle; public Dictionary<string, ConfigEntry<string>> enemyDict = new Dictionary<string, ConfigEntry<string>>(); public MyModConfig(ConfigFile cfg) { //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Expected O, but got Unknown cfg.SaveOnConfigSet = false; sandwormCollisionOverride = cfg.Bind<bool>("Experimental Fixes", "Sandworm collision override", false, "Override vanilla sandworm collisions. May fix lag when sandworm collides with multiple enemies at once. \n \n May be removed in the future."); useExperimentalCoroutines = cfg.Bind<bool>("Experimental", "Enable experimental library coroutines", false, "Use experimental coroutines for finding closest enemy. May improve performance."); usePathfindinglibCoroutines = cfg.Bind<bool>("Experimental", "Enable pathfindinglib coroutines", false, "Use experimental pathfindinglib coroutines."); usePathToFindClosestEnemy = cfg.Bind<bool>("Experimental", "Use paths to find closest enemy", false, "Enemies will use pathfinding to find closest enemy. May be performance heavy."); stableMode = cfg.Bind<bool>("General Settings", "Toggle stable mode", true, "When true, the mod will exlude patches that are WIP or are experimental from loading. Requires restart."); IgnoreImmortalEnemies = cfg.Bind<bool>("General Settings", "Ignore Immortal Enemies", false, "All immortal enemies will be ignored by majority of entities."); agentRadiusModifier = cfg.Bind<float>("General Settings", "Agent radius modifier", 0.5f, "Modifies agent radius of entities for more reliable collisions."); globalListsUpdateInterval = cfg.Bind<float>("General Settings", "Global lists update interval", 1f, "Set a period how often are global lists updated. Default is one second."); customSizeOverrideList = cfg.Bind<string>("DEV", "Custom size override list", "", "Set what size the enemy is considered as. Generates automatically."); enableSpider = cfg.Bind<bool>("Entity settings", "Enable spider", true, "Enable changes to apply to to spider and modify it's behavior."); enableSlime = cfg.Bind<bool>("Entity settings", "Enable slime", true, "Enable changes to apply to to slime and modify it's behavior."); enableLeviathan = cfg.Bind<bool>("Entity settings", "Enable leviathan", true, "Enable changes to apply to to leviathan and modify it's behavior."); enableSporeLizard = cfg.Bind<bool>("DEV", "Enable SporeLizard", false, "Enable changes to apply to to spore lizard. \n\n Early build. DEV ONLY"); enableRedBees = cfg.Bind<bool>("Entity settings", "Enable Red bees (Circuit bees)", true, "Enable changes to apply to red bees and modify it's behavior."); enableNutcracker = cfg.Bind<bool>("DEV", "Enable Nutcracker", false, "Enable changes to nutcracker to apply to and modify its behavior. \n\n Early build. DEV ONLY"); enableGiant = cfg.Bind<bool>("Entity settings", "Enable Giant", true, "Enable changes to apply to to forest giant."); enableHoardingBug = cfg.Bind<bool>("DEV", "Enable Hoarding bug", false, "Enable changes to apply to to hoarding bug"); enableSpiderWebs = cfg.Bind<bool>("Entity settings", "Enable Spider Webs", true, "Enables changes to apply to to spider webs. Webs will stick to and slow down enemies."); giantExtinguishChance = cfg.Bind<int>("Entity settings | Giant", "Extinguish chance", 33, new ConfigDescription("Chance of giants extinguishing themselves in percent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); beesSetGiantsOnFireMinChance = cfg.Bind<float>("Entity settings | Giant", "Ignite giants min chace", 1.5f, new ConfigDescription("The minimum chance bees will set giant on fire on hit in percent. Applies to calm bees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); beesSetGiantsOnFireMaxChance = cfg.Bind<float>("Entity settings | Giant", "Ignite giants max chace", 8f, new ConfigDescription("The minimum chance bees will set giant on fire on hit in percent. Applies to angry bees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); blobConsumesCorpses = cfg.Bind<bool>("Entity settings | Hygrodere", "Consume corpses", true, "Hygrodere consume dead enemy corpses."); blobPathfindToCorpses = cfg.Bind<bool>("Entity settings | Hygrodere", "Pathfind to corpses", true, "Hygrodere move towards corpses to consume."); blobPathfind = cfg.Bind<bool>("Entity settings | Hygrodere", "Pathfind", true, "Pathfind to other entities."); blobAIOpeningDoorsMultiplier = cfg.Bind<float>("Entity settings | Hygrodere", "Open door multiplier", 0.7f, "Open door speed multiplier. Default value is vanilla."); sandwormDoNotEatPlayersInsideLeavingShip = cfg.Bind<bool>("Entity settings | Sandworm", "Do not eat players inside leaving ship", false, "Worms do not eat players inside ship leaving moon."); chaseAfterEnemiesModifier = cfg.Bind<float>("Entity settings | Spider/Spider Web", "Chase after enemies modifier", 3f, "Modifies chase timer for chasing enemies. When chasing another enemy, hunter's chase timer is divided by set number."); speedModifierList = cfg.Bind<string>("Entity settings | Spider/Spider Web", "Web speed modifiers", "", "Modifies final speed of enemy caught in web. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:Speed ] \n This config generates automatically."); webStrength = cfg.Bind<float>("Entity settings | Spider/Spider Web", "Spider Web Strenght", 1.3f, "Strength of spider webs. Stronger spider web slows enemies more."); enemyNames = cfg.Bind<string>("Blacklists", "Enemy names", "", "List of enemy names. \n This config generates automatically."); beeBlacklist = cfg.Bind<string>("Blacklists", "Bees Blacklist", "", "Any enemy with set value to true will be ignored by circuit bees. \n \n [The Character ',' acts as a separator between each entry.]"); blobBlacklist = cfg.Bind<string>("Blacklists", "Blob Blacklist", "", "Any enemy with set value to true will be ignored by hygroderes. \n \n [The Character ',' acts as a separator between each entry.]"); sandwormBlacklist = cfg.Bind<string>("Blacklists", "Sandworm Blacklist", "", "Any enemy with set value to true will be ignored by sandworms. \n \n [The Character ',' acts as a separator between each entry.]"); spiderWebBlacklist = cfg.Bind<string>("Blacklists", "Web blacklist", "", "Any enemy with set value to true will be ignored by webs. \n \n [The Character ',' acts as a separator between each entry.]"); spiderBlacklist = cfg.Bind<string>("Blacklists", "Spider blacklist", "", "Any enemy with set value to true will be ignored by spider. \n \n [The Character ',' acts as a separator between each entry.]"); debugBool = cfg.Bind<bool>("Debug", "Debug mode", false, "Enables debug mode for more debug logs. Can be changed at runtime via config mods."); debugEntries.Add("debugBool", debugBool); debugKillSwitch = cfg.Bind<bool>("Debug", "Debug killswitch", false, "Kills all debug logs"); debugEntries.Add("debugKillSwitch", debugKillSwitch); spammyLogs = cfg.Bind<bool>("Debug", "Spammy logs", false, "Enables spammy logs for extra logs. Can be changed at runtime via config mods."); debugEntries.Add("spammyLogs", spammyLogs); debugNetworking = cfg.Bind<bool>("Debug", "Debug networking", false, "Enables debug logs for networking. Can be changed at runtime via config mods."); debugEntries.Add("debugNetworking", debugNetworking); debugTriggerFlags = cfg.Bind<bool>("Debug", "Trigger flags", false, "Enables logs with trigger flag."); debugEntries.Add("debugTriggerFlags", debugTriggerFlags); debugUnspecified = cfg.Bind<bool>("Debug", "Log unspecified", false, "Enables logs for unspecified. Can be changed at runtime via config mods."); debugEntries.Add("debugUnspecified", debugUnspecified); debugLibrary = cfg.Bind<bool>("Debug", "Log library", false, "Enables logs for the library. Can be changed at runtime via config mods."); debugEntries.Add("debugLibrary", debugLibrary); debugLibraryTrigger = cfg.Bind<bool>("Debug", "Log library trigger", false, "Enables logs for the library calls. Can be changed at runtime via config mods."); debugEntries.Add("debugLibraryTrigger", debugLibraryTrigger); debugRedBees = cfg.Bind<bool>("Debug", "Log bees", false, "Enables logs for bees. Can be changed at runtime via config mods."); debugEntries.Add("debugRedBees", debugRedBees); debugSandworms = cfg.Bind<bool>("Debug", "Log sandworms", false, "Enables logs for sandowrms. Can be changed at runtime via config mods."); debugEntries.Add("debugSandworms", debugSandworms); debugHygrodere = cfg.Bind<bool>("Debug", "Log hydrogere", false, "Enables logs for hydrogere. Can be changed at runtime via config mods."); debugEntries.Add("debugHygrodere", debugHygrodere); debugNutcrackers = cfg.Bind<bool>("Debug", "Log nutcrackers", false, "Enables logs for nutcrackers. Can be changed at runtime via config mods."); debugEntries.Add("debugNutcrackers", debugNutcrackers); debugSpiders = cfg.Bind<bool>("Debug", "Log spiders", false, "Enables logs for spiders. Can be changed at runtime via config mods."); debugEntries.Add("debugSpiders", debugSpiders); debugGiants = cfg.Bind<bool>("Debug", "Log giants", false, "Enables logs for giants. Can be changed at runtime via config mods."); debugEntries.Add("debugGiants", debugGiants); debugSpiderWebs = cfg.Bind<bool>("Debug", "Log spider webs", false, "Enables logs for spider webs. Can be changed at runtime via config mods."); debugEntries.Add("debugSpiderWebs", debugSpiderWebs); CompatibilityAutoToggle = cfg.Bind<bool>("Compatibility toggles", "Auto load compatibilities", true, "Automatically load compatibilites for detected mods"); ReXuvinationCompToggle = cfg.Bind<bool>("Compatibility toggles", "ReXuvination compatibility", false, "Manually toggles compatibility patches for ReXuvination."); CompatibilityEntries.Add("XuuXiaolan.ReXuvination", ReXuvinationCompToggle); enhancedMonstersCompToggle = cfg.Bind<bool>("Compatibility toggles", "Enhanced monsters compatibility", false, "Manually toggles compatibility patches for Enhanced monsters."); CompatibilityEntries.Add("com.velddev.enhancedmonsters", enhancedMonstersCompToggle); sellBodiesFixedCompToggle = cfg.Bind<bool>("Compatibility toggles", "Sellbodiesfixed compatibility", false, "Manually toggles compatibility patches for Sellbodiesfixed."); CompatibilityEntries.Add("Entity378.sellbodies", sellBodiesFixedCompToggle); ClearOrphanedEntries(cfg); cfg.Save(); cfg.SaveOnConfigSet = true; } public void ClearOrphanedEntries(ConfigFile cfg) { PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries"); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg); foreach (KeyValuePair<ConfigDefinition, string> item in dictionary) { if (!item.Key.Section.Contains("!ORPHANED ENTRIES!")) { Script.Logger.LogFatal((object)("Found orphaned entry of " + item.Key.Section + ": " + item.Key.Key + ", " + item.Value + ". Orphaned entries will be cleared on the next bootup! All values in the settings within the orphaned entries will be lost!")); cfg.Bind<string>("!ORPHANED ENTRIES!", item.Key.Key, item.Value, "!THIS ORPHANED ENTRY WILL BE DELETED!"); } } dictionary.Clear(); } } internal class Networking_New : NetworkBehaviour { } public class Networking { public static Dictionary<string, Type> NetworkingDictionary = new Dictionary<string, Type>(); private static bool logNetworking = Script.Bools["debugNetworking"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugNetworking") { logNetworking = value; } } public static void SubscribeToConfigChanges() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } public static LNetworkVariable<T> NSEnemyNetworkVariable<T>(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, typeof(T)); } return LNetworkVariable<T>.Connect(NWID, default(T), (LNetworkVariableWritePerms)0, (Action<T, T>)null); } public static LNetworkEvent NSEnemyNetworkEvent(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, typeof(LNetworkEvent)); } return LNetworkEvent.Connect(NWID, (Action<ulong>)null, (Action)null, (Action<ulong>)null); } public static void ClearSubscribtionsInDictionary() { foreach (KeyValuePair<string, Type> item in NetworkingDictionary) { if (item.Value == typeof(LNetworkEvent)) { if (logNetworking) { Script.Logger.Log((LogLevel)32, (object)("Clearing subscriptions of event " + item.Key)); } LNetworkEvent.Connect(item.Key, (Action<ulong>)null, (Action)null, (Action<ulong>)null).ClearSubscriptions(); continue; } if (logNetworking) { Script.Logger.Log((LogLevel)32, (object)$"Disposing of network {item.Value} {item.Key}"); } if (item.Value == typeof(int)) { LNetworkVariable<int>.Connect(item.Key, 0, (LNetworkVariableWritePerms)0, (Action<int, int>)null).Dispose(); } else if (item.Value == typeof(float)) { LNetworkVariable<float>.Connect(item.Key, 0f, (LNetworkVariableWritePerms)0, (Action<float, float>)null).Dispose(); } else if (item.Value == typeof(bool)) { LNetworkVariable<bool>.Connect(item.Key, false, (LNetworkVariableWritePerms)0, (Action<bool, bool>)null).Dispose(); } else { Script.Logger.Log((LogLevel)4, (object)$"Unsupported type {item.Value}"); } } Script.Logger.Log((LogLevel)16, (object)"/Networking/ Finished clearing dictionary."); NetworkingDictionary.Clear(); } } internal class NetworkingMethods { [HarmonyPatch(typeof(GameNetworkManager), "ResetGameValuesToDefault")] [HarmonyPostfix] private static void ResetGameValuesToDefaultPatch() { Script.Logger.Log((LogLevel)16, (object)"/ResetGameValuesToDefault/ Clearing all subscribtions, globalEnemyLists and data dictionaries."); Networking.ClearSubscribtionsInDictionary(); NaturalSelectionLib.ClearAllEnemyLists(); EnemyAIPatch.enemyDataDict.Clear(); } [HarmonyPatch(typeof(RoundManager), "ResetEnemyVariables")] [HarmonyPostfix] private static void ResetEnemyVariablesPatch() { Script.Logger.Log((LogLevel)16, (object)"/ResetEnemyVariables/ Clearing all subscribtions, globalEnemyLists and data dictionaries."); Networking.ClearSubscribtionsInDictionary(); NaturalSelectionLib.ClearAllEnemyLists(); EnemyAIPatch.enemyDataDict.Clear(); } } [HarmonyPatch(typeof(RoundManager))] internal class RoundManagerPatch { private static float nextUpdate = 0f; private static Dictionary<Type, List<EnemyAI>> checkedTypes = new Dictionary<Type, List<EnemyAI>>(); public static float updateListInterval = Script.BoundingConfig.globalListsUpdateInterval.Value; private static bool logSpam = Script.Bools["spammyLogs"]; private static bool logUnspecified = Script.Bools["debugNetworking"]; public static List<GameObject> deadEnemiesList = new List<GameObject>(); private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugNetworking") { logUnspecified = value; } if (entryKey == "spammyLogs") { logSpam = value; } } [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfixPatch() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPrefix] private static void UpdatePatch() { if (!(Time.realtimeSinceStartup >= nextUpdate)) { return; } foreach (Type item in checkedTypes.Keys.ToList()) { NaturalSelectionLib.UpdateEnemyList(item, checkedTypes[item]); } checkedTypes.Clear(); nextUpdate = Time.realtimeSinceStartup + updateListInterval; } public static bool RequestUpdate(EnemyAI instance) { if (!checkedTypes.ContainsKey(((object)instance).GetType()) && ((NetworkBehaviour)instance).IsOwner) { checkedTypes.Add(((object)instance).GetType(), new List<EnemyAI>()); if (logUnspecified && logSpam) { Script.Logger.Log((LogLevel)8, (object)$"/RoundManager/ request was Accepted. Requested by {LibraryCalls.DebugStringHead(instance)} at {Time.realtimeSinceStartup}"); } return true; } if (logUnspecified && logSpam && !((NetworkBehaviour)instance).IsOwner) { Script.Logger.Log((LogLevel)32, (object)"/RoundManager/ request was Denied. Not owner of the instance."); } else if (logUnspecified && logSpam) { Script.Logger.Log((LogLevel)32, (object)$"/RoundManager/ request was Denied. Requested by {LibraryCalls.DebugStringHead(instance)} at {Time.realtimeSinceStartup}"); } return false; } public static void ScheduleGlobalListUpdate(EnemyAI instance, ref List<EnemyAI> list) { if (checkedTypes.ContainsKey(((object)instance).GetType())) { checkedTypes[((object)instance).GetType()] = list; } if (!NaturalSelectionLib.EnemyListContainsKey(((object)instance).GetType())) { Script.LogNS((LogLevel)4, LibraryCalls.DebugStringHead(instance) + " global enemy list for this enemy does not exist! Creating a new one."); NaturalSelectionLib.CreateEnemyList(((object)instance).GetType(), checkedTypes[((object)instance).GetType()]); } else { NaturalSelectionLib.UpdateEnemyList(((object)instance).GetType(), checkedTypes[((object)instance).GetType()]); } } } public enum CustomEnemySize { Undefined, Tiny, Small, Medium, Large, Giant } public class EnemyDataBase { private object? owner; private int CustomBehaviorStateIndex = 0; public EnemyAI? closestEnemy; public EnemyAI? targetEnemy; public CustomEnemySize customEnemySize = CustomEnemySize.Small; public string enemyID = ""; internal Action<EnemyAI?>? ChangeClosestEnemyAction; private bool subscribed; public float coroutineTimer = 0f; public void SetOwner(object owner) { if (this.owner == null) { this.owner = owner; } } public void Subscribe() { if (!subscribed) { subscribed = true; ChangeClosestEnemyAction = (Action<EnemyAI>)Delegate.Combine(ChangeClosestEnemyAction, new Action<EnemyAI>(UpdateClosestEnemy)); } } public void Unsubscribe() { if (subscribed) { ChangeClosestEnemyAction = (Action<EnemyAI>)Delegate.Remove(ChangeClosestEnemyAction, new Action<EnemyAI>(UpdateClosestEnemy)); } } public void UpdateClosestEnemy(EnemyAI? importClosestEnemy) { if (owner == null) { Script.LogNS((LogLevel)4, "NULL owner! Unsubscribing...", owner); Unsubscribe(); } closestEnemy = importClosestEnemy; } public void ReactToAttack(EnemyAI owner, EnemyAI attacker, int damage = 0) { Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(attacker)} hit {LibraryCalls.DebugStringHead(attacker)} with {damage} damage"); } public string GetOrSetId(EnemyAI instance) { if (string.IsNullOrEmpty(enemyID)) { enemyID = instance.enemyType.enemyName + ((NetworkBehaviour)instance).NetworkObjectId; } return enemyID; } public string GetOrSetId(string id) { if (string.IsNullOrEmpty(enemyID)) { enemyID = id; } return enemyID; } public string GetOrSetId(SandSpiderWebTrap instance) { if (string.IsNullOrEmpty(enemyID)) { enemyID = ((EnemyAI)instance.mainScript).enemyType.enemyName + ((NetworkBehaviour)instance.mainScript).NetworkObjectId + instance.trapID; } return enemyID; } public string GetOrSetId(GrabbableObject instance) { if (string.IsNullOrEmpty(enemyID)) { enemyID = instance.itemProperties.itemName + ((NetworkBehaviour)instance).NetworkObjectId; } return enemyID; } } public class Utilities { public delegate bool IsEnemyReachableDelegate(EnemyAI enemy); public static Dictionary<string, EnemyDataBase> enemyDataDict = new Dictionary<string, EnemyDataBase>(); public static bool IsEnemyReachable(EnemyAI enemy, IsEnemyReachableDelegate? outputDelegate = null) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (enemy is CentipedeAI && ((CentipedeAI)enemy).clingingToCeiling) { return false; } if (enemy is SandWormAI) { return false; } if (enemy is DoublewingAI && ((DoublewingAI)enemy).flyLayerWeight > 0f) { return false; } if (enemy is RadMechAI && ((RadMechAI)enemy).inFlyingMode) { return false; } if (enemy is SandSpiderAI && ((SandSpiderAI)enemy).onWall) { return false; } return outputDelegate?.Invoke(enemy) ?? true; } public static bool IsEnemyVisible(EnemyAI enemy, Transform? checkFrom = null, IsEnemyReachableDelegate? outputDelegate = null) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (enemy is DressGirlAI) { return false; } if (enemy is ClaySurgeonAI) { if ((Object)(object)checkFrom != (Object)null) { return Vector3.Distance(((Component)enemy).transform.position, checkFrom.position) < 10f; } return false; } return outputDelegate?.Invoke(enemy) ?? true; } public static bool IsVanilla(EnemyAI checkInput) { Script.LogNS((LogLevel)32, checkInput.enemyType.enemyName + ">" + ((object)checkInput).GetType().Assembly.FullName, "IsVanillaCheck"); return ((object)checkInput).GetType().Assembly.FullName == "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; } public static EnemyDataBase GetEnemyData(object __instance, EnemyDataBase enemyData, bool returnToEnemyAIType = false) { string dataID = GetDataID(__instance, returnToEnemyAIType); if (dataID == "-1" || __instance == null) { return null; } if (!enemyDataDict.ContainsKey(dataID)) { Script.LogNS((LogLevel)16, "Missing data container for " + LibraryCalls.DebugStringHead(__instance) + ". Creating new data container..."); enemyDataDict.Add(dataID, enemyData); enemyDataDict[dataID].SetOwner(__instance); enemyDataDict[dataID].Subscribe(); } return enemyDataDict[dataID]; } public static void TryGetEnemyData(object __instance, out EnemyDataBase temp, bool returnToEnemyAIType = false) { string dataID = GetDataID(__instance, returnToEnemyAIType); enemyDataDict.TryGetValue(dataID, out temp); } public static void DeleteData(object instance, bool returnToEnemyAIType = false) { string dataID = GetDataID(instance, returnToEnemyAIType); if (enemyDataDict.ContainsKey(dataID)) { enemyDataDict.Remove(dataID); } } public static string GetDataID(object instance, bool returnToEnemyAIType = false) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) string text = "-1"; if (instance is EnemyAI) { text = ((EnemyAI)instance).enemyType.enemyName + ((NetworkBehaviour)(EnemyAI)instance).NetworkObjectId; if (returnToEnemyAIType) { text += ".base"; } } else if (instance is SandSpiderWebTrap) { text = ((EnemyAI)((SandSpiderWebTrap)instance).mainScript).enemyType.enemyName + ((NetworkBehaviour)((SandSpiderWebTrap)instance).mainScript).NetworkObjectId + "SpiderWeb" + ((SandSpiderWebTrap)instance).trapID; } else if (instance is string) { text = (string)instance; } return text; } } } namespace NaturalSelection.EnemyPatches { internal class BeeValues : EnemyDataBase { internal Vector3 lastKnownEnemyPosition = Vector3.zero; internal int customBehaviorStateIndex = 0; internal Dictionary<EnemyAI, float> hitRegistry = new Dictionary<EnemyAI, float>(); internal float LostLOSOfEnemy = 0f; internal float delayTimer = 0.2f; } [HarmonyPatch(typeof(RedLocustBees))] internal class BeeAIPatch { private static bool logBees = Script.Bools["debugRedBees"]; private static bool debugSpam = Script.Bools["spammyLogs"]; private static bool debugTriggers = Script.Bools["debugTriggerFlags"]; private static List<string> beeBlacklist = InitializeGamePatch.beeBlacklist; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugRedBees") { logBees = value; } if (entryKey == "spammyLogs") { debugSpam = value; } if (entryKey == "debugTriggerFlags") { debugTriggers = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch(RedLocustBees __instance) { BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePatch(RedLocustBees __instance) { BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); if (RoundManagerPatch.RequestUpdate((EnemyAI)(object)__instance)) { List<EnemyAI> importEnemyList = LibraryCalls.GetCompleteList((EnemyAI)(object)__instance); LibraryCalls.FilterEnemyList(ref importEnemyList, beeBlacklist, (EnemyAI)(object)__instance, Script.BoundingConfig.IgnoreImmortalEnemies.Value); RoundManagerPatch.ScheduleGlobalListUpdate((EnemyAI)(object)__instance, ref importEnemyList); } foreach (KeyValuePair<EnemyAI, float> item in new Dictionary<EnemyAI, float>(beeValues.hitRegistry)) { if (item.Value > 1.7f) { beeValues.hitRegistry.Remove(item.Key); } else { beeValues.hitRegistry[item.Key] += Time.deltaTime; } } } [HarmonyPatch("DoAIInterval")] [HarmonyPrefix] private static bool DoAIIntervalPrefixPatch(RedLocustBees __instance) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); if ((Object)(object)beeValues.targetEnemy != (Object)null && !((EnemyAI)__instance).movingTowardsTargetPlayer && beeValues.customBehaviorStateIndex != 0) { Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " DoAIInterval: Prefix triggered false", __instance, logBees && debugSpam && debugTriggers); if (((EnemyAI)__instance).moveTowardsDestination) { ((EnemyAI)__instance).agent.SetDestination(((EnemyAI)__instance).destination); } ((EnemyAI)__instance).SyncPositionToClients(); return false; } Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " DoAIInterval: Prefix triggered true", __instance, logBees && debugSpam && debugTriggers); return true; } [HarmonyPatch("DoAIInterval")] [HarmonyPostfix] private static void DoAIIntervalPostfixPatch(RedLocustBees __instance) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_04ad: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_06d8: Unknown result type (might be due to invalid IL or missing references) //IL_0706: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_0906: Unknown result type (might be due to invalid IL or missing references) //IL_08ca: Unknown result type (might be due to invalid IL or missing references) //IL_0823: Unknown result type (might be due to invalid IL or missing references) //IL_0828: Unknown result type (might be due to invalid IL or missing references) //IL_082f: Unknown result type (might be due to invalid IL or missing references) //IL_059f: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) if (((EnemyAI)__instance).isEnemyDead) { return; } BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); Type type = ((object)__instance).GetType(); List<EnemyAI> importEnemyList = LibraryCalls.GetEnemyList(type); LibraryCalls.GetInsideOrOutsideEnemyList(ref importEnemyList, (EnemyAI)(object)__instance); Dictionary<EnemyAI, float> enemyDictionary = new Dictionary<EnemyAI, float>(LibraryCalls.GetEnemiesInLOS((EnemyAI)(object)__instance, ref importEnemyList, 360f, 16, 1f)); switch (((EnemyAI)__instance).currentBehaviourStateIndex) { case 0: if (enemyDictionary.Count > 0) { beeValues.targetEnemy = enemyDictionary.Keys.First(); Script.LogNS((LogLevel)16, LibraryCalls.DebugStringHead(__instance) + " case0: Checked LOS for enemies. Enemy found: " + LibraryCalls.DebugStringHead(beeValues.targetEnemy), __instance, logBees); } if (__instance.wasInChase) { __instance.wasInChase = false; } if (Vector3.Distance(((Component)__instance).transform.position, __instance.lastKnownHivePosition) > 2f) { ((EnemyAI)__instance).SetDestinationToPosition(__instance.lastKnownHivePosition, true); } if (__instance.IsHiveMissing() || (Object)(object)__instance.hive.parentObject != (Object)null) { ((EnemyAI)__instance).SwitchToBehaviourState(2); beeValues.customBehaviorStateIndex = 2; Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} case0: HIVE IS MISSING! CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } else if ((Object)(object)beeValues.targetEnemy != (Object)null && Vector3.Distance(((Component)beeValues.targetEnemy).transform.position, ((Component)__instance.hive).transform.position) < (float)__instance.defenseDistance) { ((EnemyAI)__instance).SetDestinationToPosition(((Component)beeValues.targetEnemy).transform.position, true); Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} case0: Moving towards {beeValues.targetEnemy}", __instance, logBees); beeValues.customBehaviorStateIndex = 1; ((EnemyAI)__instance).SwitchToBehaviourState(1); beeValues.LostLOSOfEnemy = 0f; Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case0: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } break; case 1: if ((Object)(object)((EnemyAI)__instance).targetPlayer != (Object)null && ((EnemyAI)__instance).movingTowardsTargetPlayer) { break; } if ((Object)(object)beeValues.targetEnemy == (Object)null || beeValues.targetEnemy.isEnemyDead || Vector3.Distance(((Component)beeValues.targetEnemy).transform.position, ((Component)__instance.hive).transform.position) > (float)__instance.defenseDistance + 5f) { beeValues.targetEnemy = null; __instance.wasInChase = false; if (__instance.IsHiveMissing() || (Object)(object)__instance.hive.parentObject != (Object)null) { beeValues.customBehaviorStateIndex = 2; ((EnemyAI)__instance).SwitchToBehaviourState(2); Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} case1: HIVE IS MISSING! CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } else { beeValues.customBehaviorStateIndex = 0; ((EnemyAI)__instance).SwitchToBehaviourState(0); Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case1: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } } else if ((Object)(object)__instance.hive.parentObject != (Object)null) { beeValues.customBehaviorStateIndex = 2; ((EnemyAI)__instance).SwitchToBehaviourState(2); } else { ((EnemyAI)__instance).SetDestinationToPosition(((Component)beeValues.targetEnemy).transform.position, true); } break; case 2: { if ((Object)(object)((EnemyAI)__instance).targetPlayer != (Object)null || ((EnemyAI)__instance).movingTowardsTargetPlayer) { Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " case2: target player found or moving towards target player", __instance, logBees && debugSpam); break; } if (__instance.IsHivePlacedAndInLOS() && !Object.op_Implicit((Object)(object)__instance.hive.parentObject)) { if (__instance.wasInChase) { __instance.wasInChase = false; } __instance.lastKnownHivePosition = ((Component)__instance.hive).transform.position + Vector3.up * 0.5f; Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " case2: IsHivePlacedAndInLOS triggered", __instance, logBees); EnemyAI val = null; Collider[] array = Physics.OverlapSphere(((Component)__instance.hive).transform.position, (float)__instance.defenseDistance, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)2); if (array != null && array.Length != 0) { for (int i = 0; i < array.Length; i++) { EnemyAI component = ((Component)array[i]).gameObject.GetComponent<EnemyAI>(); if ((Object)(object)component != (Object)null && (Object)(object)component != (Object)(object)__instance) { val = component; Script.LogNS((LogLevel)16, LibraryCalls.DebugStringHead(__instance) + " case2: CollisionArray triggered. Enemy found: " + LibraryCalls.DebugStringHead(val), __instance, logBees); break; } } } if ((Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, ((Component)__instance.hive).transform.position) < (float)__instance.defenseDistance) { ((EnemyAI)__instance).SetDestinationToPosition(((Component)val).transform.position, true); Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} case2: Moving towards: {val}", __instance, logBees); beeValues.customBehaviorStateIndex = 1; ((EnemyAI)__instance).SwitchToBehaviourState(1); __instance.syncedLastKnownHivePosition = false; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); beeValues.LostLOSOfEnemy = 0f; Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } else { beeValues.customBehaviorStateIndex = 0; ((EnemyAI)__instance).SwitchToBehaviourState(0); Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}", __instance, logBees); } break; } bool flag = false; EnemyAI val2 = ChaseEnemyWithPriorities(ref enemyDictionary, __instance); Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: {val2} is closest to hive.", __instance, logBees); if ((Object)(object)val2 != (Object)null && (Object)(object)beeValues.targetEnemy != (Object)(object)val2) { flag = true; __instance.wasInChase = false; beeValues.targetEnemy = val2; ((EnemyAI)__instance).SetDestinationToPosition(((Component)beeValues.targetEnemy).transform.position, true); ((EnemyAI)__instance).StopSearch(__instance.searchForHive, true); __instance.syncedLastKnownHivePosition = false; beeValues.LostLOSOfEnemy = 0f; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} case2: Targeting {val2}. Synced hive position", __instance, logBees); break; } if ((Object)(object)beeValues.targetEnemy != (Object)null) { ((EnemyAI)__instance).agent.acceleration = 16f; if (!flag && enemyDictionary.Count == 0) { Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: lost LOS of {beeValues.targetEnemy}, started timer.", __instance, logBees && debugSpam); beeValues.LostLOSOfEnemy += ((EnemyAI)__instance).AIIntervalTime; if (beeValues.LostLOSOfEnemy >= 4.5f) { beeValues.targetEnemy = null; beeValues.LostLOSOfEnemy = 0f; Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: lost LOS of {beeValues.targetEnemy}, Stopped and reset timer.", __instance, logBees); } } else { __instance.wasInChase = true; beeValues.lastKnownEnemyPosition = ((Component)beeValues.targetEnemy).transform.position; ((EnemyAI)__instance).SetDestinationToPosition(beeValues.lastKnownEnemyPosition, true); beeValues.LostLOSOfEnemy = 0f; Script.LogNS((LogLevel)32, $"{LibraryCalls.DebugStringHead(__instance)} case2: lost {beeValues.targetEnemy}", __instance, logBees); } break; } ((EnemyAI)__instance).agent.acceleration = 13f; if (!__instance.searchForHive.inProgress) { Script.LogNS((LogLevel)16, LibraryCalls.DebugStringHead(__instance) + " case2: set new search for hive", __instance, logBees); if (__instance.wasInChase) { ((EnemyAI)__instance).StartSearch(beeValues.lastKnownEnemyPosition, __instance.searchForHive); Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " case2: Started search for hive.", __instance, logBees); } else { ((EnemyAI)__instance).StartSearch(((Component)__instance).transform.position, __instance.searchForHive); Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " case2: Started search for hive.", __instance, logBees); } } break; } } } private static LNetworkVariable<float> NSSetOnFireChance(RedLocustBees instance) { string nWID = "NSSetOnFireChance" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkVariable<float>(nWID); } private static LNetworkVariable<float> NSSetOnFireMaxChance(RedLocustBees instance) { string nWID = "NSSetOnFireMaxChance" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkVariable<float>(nWID); } private static LNetworkEvent NetworkSetGiantOnFire(ForestGiantAI forestGiantAI) { string nWID = "NSSetGiantOnFire" + ((NetworkBehaviour)forestGiantAI).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } public static void OnCustomEnemyCollision(RedLocustBees __instance, EnemyAI mainscript2) { //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Expected O, but got Unknown if (((object)mainscript2).GetType() == typeof(RedLocustBees)) { return; } BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); if (!Utilities.enemyDataDict.ContainsKey(beeValues.enemyID) || beeBlacklist.Contains(mainscript2.enemyType.enemyName) || (((beeValues.hitRegistry.ContainsKey(mainscript2) && !(beeValues.hitRegistry[mainscript2] > 1.7f)) || ((EnemyAI)__instance).currentBehaviourStateIndex <= 0 || mainscript2.isEnemyDead) && ((beeValues.hitRegistry.ContainsKey(mainscript2) && !(beeValues.hitRegistry[mainscript2] > 1.2f)) || ((EnemyAI)__instance).currentBehaviourStateIndex != 2 || mainscript2.isEnemyDead))) { return; } mainscript2.HitEnemy(1, (PlayerControllerB)null, true, -1); if (!beeValues.hitRegistry.ContainsKey(mainscript2)) { beeValues.hitRegistry.Add(mainscript2, 0f); } else { beeValues.hitRegistry[mainscript2] = 0f; } if (!(mainscript2 is ForestGiantAI) || mainscript2.currentBehaviourStateIndex == 2) { return; } if (((NetworkBehaviour)__instance).IsOwner) { NSSetOnFireChance(__instance).Value = Random.Range(0f, 100f); if (((EnemyAI)__instance).currentBehaviourStateIndex != 2) { NSSetOnFireMaxChance(__instance).Value = Script.BoundingConfig.beesSetGiantsOnFireMinChance.Value; } else { NSSetOnFireMaxChance(__instance).Value = Script.BoundingConfig.beesSetGiantsOnFireMaxChance.Value; } Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} OnCustomEnemyCollision: Giant hit. Chance to set on fire: {NSSetOnFireMaxChance(__instance).Value} , rolled {NSSetOnFireChance(__instance)}", __instance); } else { Script.LogNS((LogLevel)8, "Client not elligible to determine chance to set giant on fire", __instance, logBees); } if (NSSetOnFireChance(__instance).Value <= NSSetOnFireMaxChance(__instance).Value && ((NetworkBehaviour)__instance).IsOwner) { Script.LogNS((LogLevel)16, $"{LibraryCalls.DebugStringHead(__instance)} OnCustomEnemyCollision: SET GIANT ON FIRE! Random number: {NSSetOnFireChance(__instance).Value}", __instance); ForestGiantAI forestGiantAI = (ForestGiantAI)mainscript2; NetworkSetGiantOnFire(forestGiantAI).InvokeServer(); } } public static EnemyAI? ChaseEnemyWithPriorities(ref Dictionary<EnemyAI, float> enemyDictionary, RedLocustBees instance) { //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) EnemyAI val = null; if (enemyDictionary.Count < 1) { return null; } foreach (KeyValuePair<EnemyAI, float> item in enemyDictionary) { if ((Object)(object)item.Key == (Object)(object)instance) { continue; } IVisibleThreat component = ((Component)item.Key).GetComponent<IVisibleThreat>(); if (component != null && (Object)(object)component.GetHeldObject() != (Object)null && (Object)(object)component.GetHeldObject() == (Object)(object)instance.hive && !component.IsThreatDead()) { if (debugTriggers) { Script.LogNS((LogLevel)16, "ChaseEnemiesWithPriorities: Returning " + LibraryCalls.DebugStringHead(item.Key) + " |threatComp|", instance); } return item.Key; } if ((Object)(object)instance.hive.parentObject != (Object)null && (Object)(object)((Component)instance.hive.parentObject).gameObject.GetComponentInParent<EnemyAI>() == (Object)(object)item.Key) { if (debugTriggers) { Script.LogNS((LogLevel)16, "ChaseEnemiesWithPriorities: Returning " + LibraryCalls.DebugStringHead(item.Key) + " |GetComponentInParent|", instance); } return item.Key; } if (instance.IsHivePlacedAndInLOS() && !item.Key.isEnemyDead) { if ((Object)(object)val == (Object)null) { val = item.Key; } else if (Vector3.Distance(((Component)item.Key).transform.position, ((Component)instance.hive).transform.position) < Vector3.Distance(((Component)val).transform.position, ((Component)instance.hive).transform.position)) { val = item.Key; } } } if (!Object.op_Implicit((Object)(object)val)) { val = enemyDictionary.Keys.First(); } if (debugTriggers) { Script.LogNS((LogLevel)16, "ChaseEnemiesWithPriorities: Returning " + LibraryCalls.DebugStringHead(val) + " |returnEnemy|", instance); } return val; } } internal class BlobData : EnemyDataBase { internal bool playSound = false; internal Dictionary<EnemyAI, float> hitRegistry = new Dictionary<EnemyAI, float>(); } [HarmonyPatch(typeof(BlobAI))] internal class BlobAIPatch { private static bool logBlob = Script.Bools["debugHygrodere"]; private static bool triggerFlag = Script.Bools["debugTriggerFlags"]; private static List<string> blobBlacklist = InitializeGamePatch.blobBlacklist; private static LNetworkEvent BlobEatCorpseEvent(BlobAI instance) { string nWID = "NSSlimeEatEvent" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugHygrodere") { logBlob = value; } if (entryKey == "debugTriggerFlags") { triggerFlag = value; } } [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPatch(BlobAI __instance) { BlobAI __instance2 = __instance; BlobData blobData = (BlobData)Utilities.GetEnemyData(__instance2, new BlobData()); blobData.SetOwner(__instance2); blobData.Subscribe(); ((EnemyAI)__instance2).enemyType.doorSpeedMultiplier = Script.BoundingConfig.blobAIOpeningDoorsMultiplier.Value; BlobEatCorpseEvent(__instance2).OnClientReceived += EventReceived; BlobData blobData2 = blobData; blobData2.ChangeClosestEnemyAction = (Action<EnemyAI>)Delegate.Combine(blobData2.ChangeClosestEnemyAction, new Action<EnemyAI>(getClosestEnemyResult)); Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); void EventReceived() { blobData.playSound = true; } void getClosestEnemyResult(EnemyAI? closestEnemy) { Script.LogNS((LogLevel)16, $"Set {closestEnemy} as closestEnemy", __instance2); Utilities.GetEnemyData(__instance2, new BlobData()).closestEnemy = closestEnemy; } } [HarmonyPatch("DoAIInterval")] [HarmonyPrefix] private static bool DoAIIntervalPrefixPatch(BlobAI __instance) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) if (((EnemyAI)__instance).isEnemyDead) { return true; } BlobData blobData = (BlobData)Utilities.GetEnemyData(__instance, new BlobData()); if (Script.BoundingConfig.blobPathfind.Value) { GameObject val = null; if (RoundManagerPatch.deadEnemiesList.Count > 0) { foreach (GameObject deadEnemies in RoundManagerPatch.deadEnemiesList) { if ((Object)(object)val == (Object)null || Vector3.Distance(val.transform.position, ((Component)__instance).transform.position) > Vector3.Distance(deadEnemies.transform.position, ((Component)__instance).transform.position)) { val = deadEnemies; } } } if (((Object)(object)((EnemyAI)__instance).GetClosestPlayer(false, false, false) != (Object)null && (!((EnemyAI)__instance).PlayerIsTargetable(((EnemyAI)__instance).GetClosestPlayer(false, false, false), false, false) || ((Object)(object)blobData.closestEnemy != (Object)null && Vector3.Distance(((Component)blobData.closestEnemy).transform.position, ((Component)__instance).transform.position) < Vector3.Distance(((Component)((EnemyAI)__instance).GetClosestPlayer(false, false, false)).transform.position, ((Component)__instance).transform.position)) || ((Object)(object)val != (Object)null && Vector3.Distance(val.transform.position, ((Component)__instance).transform.position) < Vector3.Distance(((Component)((EnemyAI)__instance).GetClosestPlayer(false, false, false)).transform.position, ((Component)__instance).transform.position)))) || (Object)(object)((EnemyAI)__instance).GetClosestPlayer(false, false, false) == (Object)null) { if (((EnemyAI)__instance).moveTowardsDestination) { ((EnemyAI)__instance).agent.SetDestination(((EnemyAI)__instance).destination); } ((EnemyAI)__instance).SyncPositionToClients(); if (__instance.searchForPlayers.inProgress) { ((EnemyAI)__instance).StopSearch(__instance.searchForPlayers, true); } if ((Object)(object)blobData.closestEnemy != (Object)null) { float num = Vector3.Distance(((Component)blobData.closestEnemy).transform.position, ((Component)__instance).transform.position); float num2 = 0f; if ((Object)(object)val != (Object)null) { num2 = Vector3.Distance(val.transform.position, ((Component)__instance).transform.position); } if ((Object)(object)val != (Object)null && num > num2) { ((EnemyAI)__instance).SetDestinationToPosition(val.transform.position, true); } else { ((EnemyAI)__instance).SetDestinationToPosition(((Component)blobData.closestEnemy).transform.position, true); } } else if ((Object)(object)val != (Object)null) { ((EnemyAI)__instance).SetDestinationToPosition(val.transform.position, true); } return false; } } return true; } [HarmonyPatch("Update")] [HarmonyPrefix] private static void BlobUpdatePatch(BlobAI __instance) { if (((EnemyAI)__instance).isEnemyDead) { return; } BlobData blobData = (BlobData)Utilities.GetEnemyData(__instance, new BlobData()); Type type = ((object)__instance).GetType(); foreach (KeyValuePair<EnemyAI, float> item in new Dictionary<EnemyAI, float>(blobData.hitRegistry)) { if (item.Value > 1.5f) { blobData.hitRegistry.Remove(item.Key); } else { blobData.hitRegistry[item.Key] += Time.deltaTime; } } if (RoundManagerPatch.RequestUpdate((EnemyAI)(object)__instance)) { List<EnemyAI> importEnemyList = LibraryCalls.GetCompleteList((EnemyAI)(object)__instance, FilterThemselves: true, 1); LibraryCalls.FilterEnemyList(ref importEnemyList, blobBlacklist, (EnemyAI)(object)__instance); RoundManagerPatch.ScheduleGlobalListUpdate((EnemyAI)(object)__instance, ref importEnemyList); } if (((NetworkBehaviour)__instance).IsOwner) { List<EnemyAI> importEnemyList2 = NaturalSelectionLib.GetEnemyList(type); LibraryCalls.GetInsideOrOutsideEnemyList(ref importEnemyList2, (EnemyAI)(object)__instance); if (Script.BoundingConfig.useExperimentalCoroutines.Value) { if (blobData.coroutineTimer < Time.realtimeSinceStartup) { ((MonoBehaviour)__instance).StartCoroutine(LibraryCalls.FindClosestEnemyEnumerator(blobData.ChangeClosestEnemyAction, importEnemyList2, blobData.closestEnemy, (EnemyAI)(object)__instance, 6, useThreatVisibility: true, Script.usePathToFindClosestEnemy)); blobData.coroutineTimer = Time.realtimeSinceStartup + 0.2f; } } else { blobData.closestEnemy = LibraryCalls.FindClosestEnemy(ref importEnemyList2, blobData.closestEnemy, (EnemyAI)(object)__instance, 6, useThreatVisibility: true, Script.usePathToFindClosestEnemy); } } if (blobData.playSound) { Script.LogNS((LogLevel)8, "Playing sound.", __instance); ((EnemyAI)__instance).creatureVoice.PlayOneShot(__instance.killPlayerSFX); blobData.playSound = false; } } public static void OnCustomEnemyCollision(BlobAI __instance, EnemyAI mainscript2) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) BlobData blobData = (BlobData)Utilities.GetEnemyData(__instance, new BlobData()); if (blobData.hitRegistry.ContainsKey(mainscript2) || blobBlacklist.Contains(mainscript2.enemyType.enemyName)) { return; } if (mainscript2.isEnemyDead && !IsEnemyImmortal.EnemyIsImmortal(mainscript2) && Vector3.Distance(((Component)__instance).transform.position, ((Component)mainscript2).transform.position) <= 2.8f && Script.BoundingConfig.blobConsumesCorpses.Value) { if (((NetworkBehaviour)__instance).IsOwner && mainscript2.thisNetworkObject.IsSpawned) { BlobEatCorpseEvent(__instance).InvokeClients(); Script.LogNS((LogLevel)8, "consumed dead body of " + mainscript2.enemyType.enemyName, __instance); mainscript2.thisNetworkObject.Despawn(true); } } else { if (mainscript2.isEnemyDead || mainscript2 is NutcrackerEnemyAI || mainscript2 is CaveDwellerAI) { return; } blobData.hitRegistry.Add(mainscript2, 0f); if (mainscript2 is FlowermanAI) { FlowermanAI val = (FlowermanAI)(object)((mainscript2 is FlowermanAI) ? mainscript2 : null); if ((Object)(object)val != (Object)null) { float angerMeter = val.angerMeter; bool isInAngerMode = val.isInAngerMode; ((EnemyAI)val).HitEnemy(1, (PlayerControllerB)null, true, -1); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } ((EnemyAI)val).targetPlayer = null; ((EnemyAI)val).movingTowardsTargetPlayer = false; val.isInAngerMode = false; val.angerMeter = angerMeter; val.isInAngerMode = isInAngerMode; return; } } if (mainscript2 is HoarderBugAI) { HoarderBugAI val2 = (HoarderBugAI)(object)((mainscript2 is HoarderBugAI) ? mainscript2 : null); if ((Object)(object)val2 != (Object)null) { HoarderBugPatch.CustomOnHit(1, (EnemyAI)(object)__instance, playHitSFX: false, val2); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } } } else { mainscript2.HitEnemy(1, (PlayerControllerB)null, true, -1); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } } } } public static void OnEnemyCorpseCollision(BlobAI __instance, GameObject corpse) { NetworkObject component = corpse.GetComponent<NetworkObject>(); if (((NetworkBehaviour)__instance).IsOwner && component.IsSpawned) { BlobEatCorpseEvent(__instance).InvokeClients(); Script.LogNS((LogLevel)8, "consumed dead body " + LibraryCalls.DebugStringHead(corpse), __instance); component.Despawn(true); } } } internal class OnCollideWithUniversal { private class EnemyCollisionData { internal bool subscribed = false; } private static bool enableSpider = Script.BoundingConfig.enableSpider.Value; private static bool enableSlime = Script.BoundingConfig.enableSlime.Value; private static bool enableBees = Script.BoundingConfig.enableRedBees.Value; private static bool logUnspecified = Script.Bools["debugUnspecified"]; private static bool triggerFlag = Script.Bools["debugTriggerFlags"]; private static bool debugSpam = Script.Bools["spammyLogs"]; private static void Event_OnConfigSettingChanged() { logUnspecified = Script.Bools["debugUnspecified"]; debugSpam = Script.Bools["spammyLogs"]; triggerFlag = Script.Bools["debugTriggerFlags"]; } public static void Collide(string text, EnemyAI? mainscript, EnemyAI? mainscript2, GameObject? gameObject = null) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown if (logUnspecified && debugSpam && triggerFlag) { Script.Logger.Log((LogLevel)32, (object)(LibraryCalls.DebugStringHead(mainscript) + " hit collider of " + LibraryCalls.DebugStringHead(mainscript2) + " Tag: " + text)); } if (!((Object)(object)mainscript != (Object)null) || text == "Player") { } if ((Object)(object)mainscript != (Object)null && text == "Corpse" && mainscript is BlobAI && enableSlime && (Object)(object)gameObject != (Object)null) { BlobAIPatch.OnEnemyCorpseCollision((BlobAI)mainscript, gameObject); } if ((Object)(object)mainscript != (Object)null && (Object)(object)mainscript2 != (Object)null) { if (mainscript is SandSpiderAI && (Object)(object)mainscript2 != (Object)null && enableSpider) { SandSpiderAIPatch.OnCustomEnemyCollision((SandSpiderAI)mainscript, mainscript2); } if (mainscript is BlobAI && (Object)(object)mainscript2 != (Object)null && enableSlime) { BlobAIPatch.OnCustomEnemyCollision((BlobAI)mainscript, mainscript2); } if (mainscript is RedLocustBees && (Object)(object)mainscript2 != (Object)null && enableBees) { BeeAIPatch.OnCustomEnemyCollision((RedLocustBees)mainscript, mainscript2); } } } } [HarmonyPatch(typeof(EnemyAICollisionDetect))] public class AICollisionDetectPatch { [HarmonyPatch("OnTriggerStay")] [HarmonyPrefix] private static bool OnTriggerStayPrefix(Collider other, EnemyAICollisionDetect __instance) { if ((Object)(object)other == (Object)null) { Script.Logger.Log((LogLevel)2, (object)(LibraryCalls.DebugStringHead(__instance.mainScript) + " Collider is null! Using original function...")); return true; } EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent<EnemyAICollisionDetect>(); if ((Object)(object)__instance != (Object)null) { EnemyAI val = null; DeadBodyTrackerScript component2 = ((Component)other).GetComponent<DeadBodyTrackerScript>(); if ((Object)(object)component2 != (Object)null) { if (Script.Bools["spammyLogs"] && Script.Bools["debugTriggerFlags"]) { Script.Logger.LogInfo((object)"Collided with corpse"); } OnCollideWithUniversal.Collide("Corpse", __instance.mainScript, null, ((Component)component2).gameObject); } if (((Component)other).CompareTag("Player") && !__instance.mainScript.isEnemyDead) { OnCollideWithUniversal.Collide("Player", null, null); return true; } if ((Object)(object)component != (Object)null) { val = ((!((Object)(object)component?.mainScript == (Object)null)) ? ((Component)other).gameObject.GetComponentInParent<EnemyAI>() : component?.mainScript); if (((Component)other).CompareTag("Enemy") && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance.mainScript && !IsEnemyImmortal.EnemyIsImmortal(val) && !__instance.mainScript.isEnemyDead) { OnCollideWithUniversal.Collide("Enemy", __instance.mainScript, val); return true; } } } return true; } } public class IsEnemyImmortal { public static bool EnemyIsImmortal(EnemyAI instance) { if (instance is NutcrackerEnemyAI && instance.currentBehaviourStateIndex == 0) { return true; } if (instance is JesterAI) { return true; } if (instance is BlobAI) { return true; } if (instance is SpringManAI) { return true; } if (instance is SandWormAI) { return true; } if (instance is ButlerBeesEnemyAI) { return true; } return false; } } internal class EnemyData : EnemyDataBase { internal float originalAgentRadius = 0f; } [HarmonyPatch(typeof(EnemyAI))] internal class EnemyAIPatch { private static bool debugUnspecified = Script.Bools["debugUnspecified"]; private static bool debugTriggerFlags = Script.Bools["debugTriggerFlags"]; public static Dictionary<string, EnemyDataBase> enemyDataDict = new Dictionary<string, EnemyDataBase>(); private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugUnspecified") { debugUnspecified = value; } if (entryKey == "debugTriggerFlags") { debugTriggerFlags = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPostfix(EnemyAI __instance) { EnemyData enemyData = (EnemyData)Utilities.GetEnemyData(__instance, new EnemyData(), returnToEnemyAIType: true); enemyData.originalAgentRadius = __instance.agent.radius; if (InitializeGamePatch.customSizeOverrideListDictionary.ContainsKey(__instance.enemyType.enemyName)) { enemyData.customEnemySize = (CustomEnemySize)InitializeGamePatch.customSizeOverrideListDictionary[__instance.enemyType.enemyName]; } Script.LogNS((LogLevel)32, $"Final size: {enemyData.customEnemySize}", __instance); __instance.agent.radius = __instance.agent.radius * Script.BoundingConfig.agentRadiusModifier.Value; Script.LogNS((LogLevel)8, $"Modified agent radius. Original: {enemyData.originalAgentRadius}, Modified: {__instance.agent.radius}", null, debugUnspecified && debugTriggerFlags); Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("OnDestroy")] [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { Script.LogNS((LogLevel)32, LibraryCalls.DebugStringHead(__instance) + " destroyed. Unsubscribing and destroying data containers...", __instance); Utilities.TryGetEnemyData(__instance, out EnemyDataBase temp); Utilities.TryGetEnemyData(__instance, out EnemyDataBase temp2, returnToEnemyAIType: true); if (temp2 != null) { temp2.Unsubscribe(); Utilities.DeleteData(Utilities.GetDataID(__instance, returnToEnemyAIType: true)); } if (temp != null) { temp.Unsubscribe(); Utilities.DeleteData(Utilities.GetDataID(__instance)); } } public static int ReactToHit(int force = 0, EnemyAI? enemyAI = null, PlayerControllerB? player = null) { if (force > 0) { return 1; } if (force > 1) { return 2; } return 0; } [HarmonyPatch("HitEnemy")] [HarmonyPostfix] public static void HitEnemyPatch(EnemyAI __instance, int force, PlayerControllerB playerWhoHit, bool playHitSFX, int hitID) { string text = "unknown"; if ((Object)(object)playerWhoHit != (Object)null) { text = $"{playerWhoHit.playerUsername}(SteamID: {playerWhoHit.playerSteamId}, playerClientID: {playerWhoHit.playerClientId})"; } Script.LogNS((LogLevel)16, $"registered hit by {text} with force of {force}. playHitSFX:{playHitSFX}, hitID:{hitID}.", __instance, debugTriggerFlags); } public static void ReactToAttack(EnemyAI instance, Collider other) { string _instance = ((Component)other).gameObject.GetComponent<EnemyAICollisionDetect>().mainScript.enemyType.enemyName + ((NetworkBehaviour)((Component)other).gameObject.GetComponent<EnemyAICollisionDetect>().mainScript).NetworkObjectId; Utilities.TryGetEnemyData(_instance, out EnemyDataBase temp); temp?.ReactToAttack(instance, ((Component)other).gameObject.GetComponent<EnemyAICollisionDetect>().mainScript, 1); } } public class ReversePatchAI { public static Action<EnemyAI> originalUpdate; static ReversePatchAI() { MethodInfo meth = AccessTools.Method(typeof(EnemyAI), "Update", (Type[])null, (Type[])null); DynamicMethod dynamicMethod = new DynamicMethod("Base.Update", null, new Type[1] { typeof(EnemyAI) }, typeof(EnemyAI)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, meth); iLGenerator.Emit(OpCodes
DLLs/fandovec03.NaturalSelectionLib.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using Microsoft.CodeAnalysis; using NaturalSelectionLib.Comp; using NaturalSelectionLib.Tools; using PathfindingLib.API.SmartPathfinding; using PathfindingLib.Utilities; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Fandovec03")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Personal Library with functions for getting, sorting and filtering enemies")] [assembly: AssemblyFileVersion("0.7.1.0")] [assembly: AssemblyInformationalVersion("0.7.1+727149db34d38517c3808c53fda0dd65fc54042b")] [assembly: AssemblyProduct("NaturalSelectionLib")] [assembly: AssemblyTitle("fandovec03.NaturalSelectionLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Fandovec03/NaturalSelectionLib.git")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.7.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NaturalSelectionLib { [BepInPlugin("fandovec03.NaturalSelectionLib", "NaturalSelectionLib", "0.7.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NaturalSelectionLib : BaseUnityPlugin { [CompilerGenerated] private sealed class <>c__DisplayClass24_0 { public EnemyAI __instance; internal float <FindClosestEnemy>b__0(EnemyAI x) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(((Component)__instance).transform.position, ((Component)x).transform.position); } } [CompilerGenerated] private sealed class <FindClosestEnemy>d__24 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Action<EnemyAI?> ReturnOwnerResultPairDelegate; public List<EnemyAI> importEnemyList; public EnemyAI importClosestEnemy; public EnemyAI __instance; public int maxIterations; public bool useThreatVisibility; public bool usePathLengthAsDistance; public bool includeTheDead; private <>c__DisplayClass24_0 <>8__1; private int <iterations>5__2; private List<EnemyAI>.Enumerator <>s__3; private EnemyAI <enemy>5__4; private int <i>5__5; private bool <noValidPaths>5__6; private float[] <distance>5__7; private int <j>5__8; private bool[] <validPath>5__9; private PathfindingCalculator <calculator>5__10; private IVisibleThreat <threatImportEnemyList>5__11; private IVisibleThreat <threatImportClosestEnemy>5__12; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FindClosestEnemy>d__24(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>s__3 = default(List<EnemyAI>.Enumerator); <enemy>5__4 = null; <distance>5__7 = null; <validPath>5__9 = null; <calculator>5__10 = null; <threatImportEnemyList>5__11 = null; <threatImportClosestEnemy>5__12 = null; <>1__state = -2; } private bool MoveNext() { //IL_07d8: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Unknown result type (might be due to invalid IL or missing references) //IL_0815: Unknown result type (might be due to invalid IL or missing references) //IL_0825: Unknown result type (might be due to invalid IL or missing references) //IL_0657: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_069e; } <>1__state = -1; <>8__1 = new <>c__DisplayClass24_0(); <>8__1.__instance = __instance; <>s__3 = importEnemyList.GetEnumerator(); try { while (<>s__3.MoveNext()) { <enemy>5__4 = <>s__3.Current; if (debugLibrary) { LibraryLogger.LogInfo((object)$"{DebugStringHead(<>8__1.__instance)}/FindClosestEnemyCoroutine/ item {DebugStringHead(<enemy>5__4)} inside importEnemyList. IsEnemyDead: {<enemy>5__4.isEnemyDead}"); } <enemy>5__4 = null; } } finally { ((IDisposable)<>s__3).Dispose(); } <>s__3 = default(List<EnemyAI>.Enumerator); if (debugLibrary && (Object)(object)importClosestEnemy != (Object)null) { LibraryLogger.LogInfo((object)$"{DebugStringHead(<>8__1.__instance)}/FindClosestEnemyCoroutine/ {DebugStringHead(importClosestEnemy)} inside importClosestEnemy. IsEnemyDead: {importClosestEnemy.isEnemyDead}"); } if (importEnemyList.Count < 1) { if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(<>8__1.__instance) + "importEnemyList is empty!")); } if ((Object)(object)importClosestEnemy != (Object)null && importClosestEnemy.isEnemyDead) { if (!includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogError((object)(DebugStringHead(<>8__1.__instance) + " " + DebugStringHead(importClosestEnemy) + " is dead and importEnemyList is empty! Setting importClosestEnemy to null...")); } ReturnOwnerResultPairDelegate?.Invoke(null); return false; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(<>8__1.__instance) + " " + DebugStringHead(importClosestEnemy) + " is dead and importEnemyList is empty!")); } ReturnOwnerResultPairDelegate?.Invoke(importClosestEnemy); return false; } } importEnemyList.OrderBy((EnemyAI x) => Vector3.Distance(((Component)<>8__1.__instance).transform.position, ((Component)x).transform.position)); <iterations>5__2 = importEnemyList.Count; if (<iterations>5__2 > maxIterations) { <iterations>5__2 = maxIterations; } <i>5__5 = 0; goto IL_0994; IL_069e: if (!<calculator>5__10.CalculationnStatus(0, out <distance>5__7[0], out <validPath>5__9[0]) && !<calculator>5__10.CalculationnStatus(1, out <distance>5__7[1], out <validPath>5__9[1])) { <>2__current = null; <>1__state = 1; return true; } if (<validPath>5__9[0] == <validPath>5__9[1] && <distance>5__7[0] == -1f) { <noValidPaths>5__6 = true; } if (debugLibrary) { LibraryLogger.LogMessage((object)$"(E) Distance[0] = {<distance>5__7[0]}, Distance[1] = {<distance>5__7[1]}"); } <validPath>5__9 = null; <calculator>5__10 = null; goto IL_0772; IL_0982: <i>5__5++; goto IL_0994; IL_0994: if (<i>5__5 < <iterations>5__2) { if ((Object)(object)importClosestEnemy == (Object)null) { if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(<>8__1.__instance) + " No enemy assigned. Assigning new closestEnemy...")); } <j>5__8 = <i>5__5; while (<j>5__8 < importEnemyList.Count) { if (importEnemyList[<j>5__8].isEnemyDead && !includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(<>8__1.__instance) + " Found dead enemy. Skipping...")); } <j>5__8++; continue; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(<>8__1.__instance) + " New closestEnemy found!")); } importClosestEnemy = importEnemyList[<j>5__8]; break; } } else { if (importClosestEnemy.isEnemyDead) { if (!includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogError((object)(DebugStringHead(<>8__1.__instance) + ", " + DebugStringHead(importClosestEnemy) + " is dead! Assigning new tempClosestEnemy from importEnemyList...")); } importClosestEnemy = importEnemyList[<i>5__5]; goto IL_0982; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(<>8__1.__instance) + " " + DebugStringHead(importClosestEnemy) + " is dead! The dead enemy will be included. ")); } } if ((Object)(object)importClosestEnemy == (Object)(object)importEnemyList[<i>5__5]) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(<>8__1.__instance) + " " + DebugStringHead(importEnemyList[<i>5__5]) + " is already assigned as closestEnemy")); } } else { if (!((Object)(object)importEnemyList[<i>5__5] == (Object)null)) { <noValidPaths>5__6 = false; <distance>5__7 = new float[2]; if (usePathLengthAsDistance && ((Behaviour)<>8__1.__instance.agent).isActiveAndEnabled) { <validPath>5__9 = new bool[2]; <calculator>5__10 = PathfindingCalculator.Create(<>8__1.__instance, new List<Vector3>(2) { ((Component)importEnemyList[<i>5__5]).transform.position, ((Component)importClosestEnemy).transform.position }); goto IL_069e; } goto IL_0772; } if (debugLibrary) { LibraryLogger.LogError((object)(DebugStringHead(<>8__1.__instance) + " Enemy not found! Skipping...")); } } } goto IL_0982; } if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(<>8__1.__instance) + " FindClosestEnemyCoroutine returning " + DebugStringHead(importClosestEnemy))); } ReturnOwnerResultPairDelegate?.Invoke(importClosestEnemy); return false; IL_0772: if (!((Object)(object)importClosestEnemy == (Object)null) && !((Object)(object)importEnemyList[<i>5__5] == (Object)null)) { if (<noValidPaths>5__6 || !usePathLengthAsDistance) { <distance>5__7[0] = Vector3.Distance(((Component)<>8__1.__instance).transform.position, ((Component)importEnemyList[<i>5__5]).transform.position); <distance>5__7[1] = Vector3.Distance(((Component)<>8__1.__instance).transform.position, ((Component)importClosestEnemy).transform.position); } if (useThreatVisibility) { ((Component)importEnemyList[<i>5__5]).TryGetComponent<IVisibleThreat>(ref <threatImportEnemyList>5__11); ((Component)importClosestEnemy).TryGetComponent<IVisibleThreat>(ref <threatImportClosestEnemy>5__12); if (<threatImportEnemyList>5__11 != null) { <distance>5__7[0] *= <threatImportEnemyList>5__11.GetVisibility(); } if (<threatImportClosestEnemy>5__12 != null) { <distance>5__7[1] *= <threatImportClosestEnemy>5__12.GetVisibility(); } <threatImportEnemyList>5__11 = null; <threatImportClosestEnemy>5__12 = null; } if (<distance>5__7[0] < <distance>5__7[1]) { importClosestEnemy = importEnemyList[<i>5__5]; if (debugLibrary) { LibraryLogger.LogInfo((object)(DebugStringHead(<>8__1.__instance) + " Assigned " + DebugStringHead(importEnemyList[<i>5__5]) + " as new closestEnemy. Distance: " + <distance>5__7[0])); } } <distance>5__7 = null; } goto IL_0982; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static bool debugLibrary = false; public static bool debugSpam = false; public static bool usePathfindingLib = false; public static ManualLogSource LibraryLogger = new ManualLogSource("NaturalSelectionLib"); private static Dictionary<Type, List<EnemyAI>> globalEnemyLists = new Dictionary<Type, List<EnemyAI>>(); public static string ReturnVersion() { return "0.7.1"; } public static void UpdateEnemyList(Type instanceType, List<EnemyAI> list) { if (globalEnemyLists[instanceType].SequenceEqual(list)) { if (debugSpam && debugLibrary) { LibraryLogger.LogInfo((object)("/updateListInsideDictionary/ Sequence in " + instanceType?.ToString() + " is equal. Skipping.")); } return; } globalEnemyLists[instanceType] = list; if (debugSpam && debugLibrary) { LibraryLogger.LogInfo((object)("/updateListInsideDictionary/ updating list for " + instanceType)); } } public static void CreateEnemyList(Type instanceType, List<EnemyAI> list) { if (!globalEnemyLists.ContainsKey(instanceType)) { globalEnemyLists.Add(instanceType, list); if (debugSpam && debugLibrary) { LibraryLogger.LogInfo((object)("/updateListInsideDictionary/ created new list for " + instanceType)); } } } public static void DestroyEnemyList(Type instanceType, List<EnemyAI> list) { if (globalEnemyLists.ContainsKey(instanceType)) { globalEnemyLists.Remove(instanceType); if (debugSpam && debugLibrary) { LibraryLogger.LogInfo((object)("/updateListInsideDictionary/ created new list for " + instanceType)); } } } public static bool EnemyListContainsKey(Type instanceType) { return globalEnemyLists.ContainsKey(instanceType); } public static List<EnemyAI> GetEnemyList(Type instanceType) { return globalEnemyLists[instanceType]; } public static void ClearAllEnemyLists() { globalEnemyLists.Clear(); } public static void SetLibraryLoggers(ManualLogSource importLogger, bool spammyLogs = false, bool debuglibrary = false, bool usePathfindinglib = false) { LibraryLogger = importLogger; debugSpam = spammyLogs; debugLibrary = debuglibrary; usePathfindingLib = usePathfindinglib; } public static string DebugStringHead(object? source, bool shortFormat = true) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown string result = ""; if (source != null) { string text = ""; if (source is EnemyAI) { EnemyAI val = (EnemyAI)source; text = $"{val.enemyType.enemyName}|ID: {((NetworkBehaviour)val).NetworkObjectId}|ThisEnemyIndex: {val.thisEnemyIndex}"; if (shortFormat) { text = $"{val?.enemyType.enemyName}|ID: {((val != null) ? new ulong?(((NetworkBehaviour)val).NetworkObjectId) : null)}"; } } else if (source is SandSpiderWebTrap) { SandSpiderWebTrap val2 = (SandSpiderWebTrap)source; text = $"Spider web {val2.trapID}"; if (!shortFormat) { text = $"Spider web {val2.trapID}, Owner {DebugStringHead(val2.mainScript)}"; } } else if (!(source is GrabbableObject)) { text = ((!(source is string)) ? "Unknown source" : ((string)source)); } else { GrabbableObject val3 = (GrabbableObject)source; text = $"{val3.itemProperties.itemName}, ID: {((NetworkBehaviour)val3).NetworkObjectId}"; if (!shortFormat) { text = $"{val3.itemProperties.itemName}|ID: {((NetworkBehaviour)val3).NetworkObjectId}|ItemID: {val3.itemProperties.itemId}"; } } result = "(" + text + ")"; } return result; } public static List<EnemyAI> GetCompleteList(EnemyAI instance, bool filterThemselves = true, int includeOrReturnTheDead = 0) { List<EnemyAI> list = new List<EnemyAI>(RoundManager.Instance.SpawnedEnemies); for (int i = 0; i < list.Count; i++) { if ((Object)(object)list[i] == (Object)(object)instance) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found itself in the list. Removing...")); } list.Remove(list[i]); } else if (((object)list[i]).GetType() == ((object)instance).GetType() && filterThemselves) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found its type in the list. Removing...")); } list.Remove(list[i]); } else { if (!list[i].isEnemyDead) { continue; } switch (includeOrReturnTheDead) { case 0: if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(instance) + " Found dead enemy in the list. Removing...")); } list.Remove(list[i]); break; case 1: if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(instance) + " Found dead enemy in the list. Proceeding...")); } break; case 2: if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(instance) + " Found living enemy in the list. Removing..")); } list.Remove(list[i]); break; } } } return list; } public static List<EnemyAI> GetNearbyEnemies(EnemyAI instance, float radius = 0f, Vector3? importEyePosition = null, int includeOrReturnTheDead = 0) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) List<EnemyAI> list = new List<EnemyAI>(); Vector3 val = instance.eye.position; if (importEyePosition.HasValue) { val = importEyePosition.Value; } int mask = LayerMask.GetMask(new string[1] { "Enemies" }); int num = Physics.OverlapSphereNonAlloc(val, radius, RoundManager.Instance.tempColliderResults, mask, (QueryTriggerInteraction)2); EnemyAICollisionDetect val2 = default(EnemyAICollisionDetect); for (int i = 0; i < num; i++) { if (!((Component)RoundManager.Instance.tempColliderResults[i]).gameObject.TryGetComponent<EnemyAICollisionDetect>(ref val2)) { continue; } EnemyAI mainScript = val2.mainScript; if ((Object)(object)mainScript == (Object)(object)instance || list.Contains(mainScript)) { continue; } if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " /GetEnemiesInLOS/: Enemy not found in imported enemy list! Skipping...")); } switch (includeOrReturnTheDead) { case 0: if (!mainScript.isEnemyDead) { list.Add(mainScript); } break; case 1: list.Add(mainScript); break; case 2: if (mainScript.isEnemyDead) { list.Add(mainScript); } break; } } return list; } public static bool GetPathLength(NavMeshAgent agent, Vector3 targetDestination, out float PathLength, out bool validPathOut) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) NavMeshPath val = new NavMeshPath(); bool flag = false; bool flag2 = false; Vector3[] array = Array.Empty<Vector3>(); PathLength = -1f; validPathOut = false; if (!((Behaviour)agent).enabled || !((Behaviour)agent).isActiveAndEnabled) { LibraryLogger.LogWarning((object)"Agent is disabled!"); PathLength = -1f; return false; } flag2 = (validPathOut = agent.CalculatePath(targetDestination, val) && (int)val.status == 0); array = val.corners; if (flag2) { float num = 0f; for (int i = 1; i < array.Length; i++) { float num2 = Vector3.Distance(array[i - 1], array[i]); num += num2; } PathLength = num; if (debugLibrary) { LibraryLogger.LogMessage((object)$"Found path length: {PathLength}"); } return true; } return false; } public static void GetInsideOrOutsideEnemyList(ref List<EnemyAI> importEnemyList, EnemyAI instance) { foreach (EnemyAI item in importEnemyList.ToList()) { if ((Object)(object)item == (Object)(object)instance || item.isOutside != instance.isOutside) { importEnemyList.Remove(item); if (debugLibrary && debugSpam) { LibraryLogger.LogDebug((object)(DebugStringHead(instance) + "/GetInsideOrOutsideEnemyList/ removed " + DebugStringHead(item))); } } } } public static EnemyAI? FindClosestEnemy(ref List<EnemyAI> importEnemyList, EnemyAI? importClosestEnemy, EnemyAI __instance, int maxIterations = 6, bool useThreatVisibility = true, bool usePathLengthAsDistance = false, bool includeTheDead = false) { //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_0560: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0597: Unknown result type (might be due to invalid IL or missing references) EnemyAI __instance2 = __instance; foreach (EnemyAI importEnemy in importEnemyList) { if (debugLibrary) { LibraryLogger.LogInfo((object)$"{DebugStringHead(__instance2)}/FindClosestEnemy/ item {DebugStringHead(importEnemy)} inside importEnemyList. IsEnemyDead: {importEnemy.isEnemyDead}"); } } if (debugLibrary && (Object)(object)importClosestEnemy != (Object)null) { LibraryLogger.LogInfo((object)$"{DebugStringHead(__instance2)}/FindClosestEnemy/ {DebugStringHead(importClosestEnemy)} inside importClosestEnemy. IsEnemyDead: {importClosestEnemy.isEnemyDead}"); } if (importEnemyList.Count < 1) { if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(__instance2) + "importEnemyList is empty!")); } if ((Object)(object)importClosestEnemy != (Object)null && importClosestEnemy.isEnemyDead) { if (!includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogError((object)(DebugStringHead(__instance2) + " " + DebugStringHead(importClosestEnemy) + " is dead and importEnemyList is empty! Setting importClosestEnemy to null...")); } return null; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(__instance2) + " " + DebugStringHead(importClosestEnemy) + " is dead and importEnemyList is empty!")); } return importClosestEnemy; } } importEnemyList.OrderBy((EnemyAI x) => Vector3.Distance(((Component)__instance2).transform.position, ((Component)x).transform.position)); int num = importEnemyList.Count; if (num > maxIterations) { num = maxIterations; } IVisibleThreat val = default(IVisibleThreat); IVisibleThreat val2 = default(IVisibleThreat); for (int i = 0; i < num; i++) { if ((Object)(object)importClosestEnemy == (Object)null) { if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(__instance2) + " No enemy assigned. Assigning new closestEnemy...")); } for (int j = i; j < importEnemyList.Count; j++) { if (importEnemyList[j].isEnemyDead && !includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(__instance2) + " Found dead enemy. Skipping...")); } continue; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(__instance2) + " New closestEnemy found!")); } importClosestEnemy = importEnemyList[j]; break; } continue; } if (importClosestEnemy.isEnemyDead) { if (!includeTheDead) { if (debugLibrary && debugSpam) { LibraryLogger.LogError((object)(DebugStringHead(__instance2) + ", " + DebugStringHead(importClosestEnemy) + " is dead! Assigning new tempClosestEnemy from importEnemyList...")); } importClosestEnemy = importEnemyList[i]; continue; } if (debugLibrary && debugSpam) { LibraryLogger.LogInfo((object)(DebugStringHead(__instance2) + " " + DebugStringHead(importClosestEnemy) + " is dead! The dead enemy will be included. ")); } } if ((Object)(object)importClosestEnemy == (Object)(object)importEnemyList[i]) { if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(__instance2) + " " + DebugStringHead(importEnemyList[i]) + " is already assigned as closestEnemy")); } continue; } if ((Object)(object)importEnemyList[i] == (Object)null) { if (debugLibrary) { LibraryLogger.LogError((object)(DebugStringHead(__instance2) + " Enemy not found! Skipping...")); } continue; } bool flag = false; float[] array = new float[2]; if (usePathLengthAsDistance && ((Behaviour)__instance2.agent).isActiveAndEnabled && GetPathLength(__instance2.agent, ((Component)importEnemyList[i]).transform.position, out array[0], out var _) && GetPathLength(__instance2.agent, ((Component)importClosestEnemy).transform.position, out array[1], out var _)) { if (array[0] == array[1] && array[0] == -777.77f) { flag = true; } if (debugLibrary) { LibraryLogger.LogMessage((object)$"Distance[0] = {array[0]}, Distance[1] = {array[1]}"); } } if (flag || !usePathLengthAsDistance) { array[0] = Vector3.Distance(((Component)__instance2).transform.position, ((Component)importEnemyList[i]).transform.position); array[1] = Vector3.Distance(((Component)__instance2).transform.position, ((Component)importClosestEnemy).transform.position); } if (useThreatVisibility) { ((Component)importEnemyList[i]).TryGetComponent<IVisibleThreat>(ref val); ((Component)importClosestEnemy).TryGetComponent<IVisibleThreat>(ref val2); if (val != null) { array[0] *= val.GetVisibility(); } if (val2 != null) { array[1] *= val2.GetVisibility(); } } if (array[0] < array[1]) { importClosestEnemy = importEnemyList[i]; if (debugLibrary) { LibraryLogger.LogInfo((object)(DebugStringHead(__instance2) + " Assigned " + DebugStringHead(importEnemyList[i]) + " as new closestEnemy. Distance: " + array[0])); } } } if (debugLibrary && debugSpam) { LibraryLogger.LogWarning((object)(DebugStringHead(__instance2) + " findClosestEnemy returning " + DebugStringHead(importClosestEnemy))); } return importClosestEnemy; } public static void FilterEnemyList(ref List<EnemyAI> importEnemyList, List<string>? blacklist, EnemyAI instance, bool filterOutImmortal = true, bool filterTheSameType = true) { List<EnemyAI> list = new List<EnemyAI>(importEnemyList); for (int i = 0; i < list.Count; i++) { if ((Object)(object)list[i] == (Object)(object)instance) { if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found itself in importEnemyList! Skipping...")); } importEnemyList.Remove(list[i]); continue; } if (filterTheSameType && ((object)list[i]).GetType() == ((object)instance).GetType()) { if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found its own type in importEnemyList! Skipping...")); } importEnemyList.Remove(list[i]); continue; } try { if (blacklist != null && (Object)(object)list[i] != (Object)null && (blacklist.Contains(list[i].enemyType.enemyName) || blacklist.Contains(((Object)list[i].enemyType).name) || ((Object)(object)((Component)list[i]).GetComponentInChildren<ScanNodeProperties>() != (Object)null && blacklist.Contains(((Component)list[i]).GetComponentInChildren<ScanNodeProperties>().headerText)))) { if (debugLibrary && blacklist.Contains(list[i].enemyType.enemyName)) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found blacklisted enemy in importEnemyList by EnemyType enemyName! Skipping...")); } if (debugLibrary && blacklist.Contains(((Object)list[i].enemyType).name)) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found blacklisted enemy in importEnemyList by EnemyType name! Skipping...")); } if (debugLibrary && blacklist.Contains(((Component)list[i]).GetComponentInChildren<ScanNodeProperties>().headerText)) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " Found blacklisted enemy in importEnemyList by scan node headertext! Skipping...")); } importEnemyList.Remove(list[i]); continue; } } catch (Exception ex) { LibraryLogger.LogError((object)(DebugStringHead(instance) + " Something went wrong.")); LibraryLogger.LogError((object)blacklist); LibraryLogger.LogError((object)list[i]); LibraryLogger.LogError((object)list[i].enemyType.enemyName.ToUpper()); LibraryLogger.LogError((object)((Component)list[i]).GetComponentInChildren<ScanNodeProperties>().headerText.ToUpper()); LibraryLogger.LogError((object)ex.ToString()); } if (filterOutImmortal && !list[i].enemyType.canDie) { if (debugLibrary) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} Caught and filtered out immortal Enemy of type {((object)list[i]).GetType()}"); } importEnemyList.Remove(list[i]); } } } public static void FilterEnemySizes(ref List<EnemyAI> importEnemyList, EnemySize[] enemySizes, EnemyAI instance, bool inverseToggle = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) List<EnemyAI> list = new List<EnemyAI>(importEnemyList); for (int i = 0; i < list.Count; i++) { if (enemySizes != null && enemySizes.Length != 0 && ((!inverseToggle && enemySizes.Contains(list[i].enemyType.EnemySize)) || (inverseToggle && !enemySizes.Contains(list[i].enemyType.EnemySize)))) { if (debugLibrary) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} Enemy of size {list[i].enemyType.EnemySize} passed the filter. inverseToggle: {inverseToggle}"); } } else if (enemySizes != null && enemySizes.Length != 0) { if (debugLibrary) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} Caught and filtered out Enemy of size {list[i].enemyType.EnemySize}"); } importEnemyList.Remove(list[i]); continue; } if (enemySizes == null || enemySizes.Length < 1) { if (debugLibrary && enemySizes != null && enemySizes.Length < 1) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} enemySizes is empty. Adding enemy of size {list[i].enemyType.EnemySize} by default"); } if (debugLibrary && enemySizes == null) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} enemySizes is NULL. Adding enemy of size {list[i].enemyType.EnemySize} by default"); } } } } public static void FilterEnemySizes(ref Dictionary<EnemyAI, int> importEnemySizeDict, int[] enemySizes, EnemyAI instance, bool inverseToggle = false) { Dictionary<EnemyAI, int> dictionary = new Dictionary<EnemyAI, int>(importEnemySizeDict); foreach (KeyValuePair<EnemyAI, int> item in dictionary) { if (enemySizes != null && enemySizes.Length != 0 && ((!inverseToggle && enemySizes.Contains(item.Value)) || (inverseToggle && !enemySizes.Contains(item.Value)))) { if (debugLibrary) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} Enemy of size {item.Value} passed the filter. inverseToggle: {inverseToggle}"); } } else if (enemySizes != null && enemySizes.Length != 0) { if (debugLibrary) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} Caught and filtered out Enemy of size {item.Value}"); } importEnemySizeDict.Remove(item.Key); continue; } if (enemySizes == null || enemySizes.Length < 1) { if (debugLibrary && enemySizes != null && enemySizes.Length < 1) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} enemySizes is empty. Adding enemy of size {item.Value} by default"); } if (debugLibrary && enemySizes == null) { LibraryLogger.LogInfo((object)$"{DebugStringHead(instance)} enemySizes is NULL. Adding enemy of size {item.Value} by default"); } } } } public static Dictionary<EnemyAI, float> GetEnemiesInLOS(EnemyAI instance, ref List<EnemyAI> importEnemyList, float width = 45f, float importRange = 0f, float proximityAwareness = -1f, float importRadius = 0f, Vector3? importEyePosition = null) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) Dictionary<EnemyAI, float> tempDictionary = new Dictionary<EnemyAI, float>(); float num = importRange; float num2 = importRadius; Vector3 val = instance.eye.position; if (importEyePosition.HasValue) { val = importEyePosition.Value; } int mask = LayerMask.GetMask(new string[1] { "Enemies" }); if (instance.isOutside && !instance.enemyType.canSeeThroughFog && (int)TimeOfDay.Instance.currentLevelWeather == 3) { num = Mathf.Clamp(importRange, 0f, 30f); } if (num2 <= 0f) { num2 = num * 2f; } int num3 = Physics.OverlapSphereNonAlloc(val, num2, RoundManager.Instance.tempColliderResults, mask, (QueryTriggerInteraction)2); EnemyAICollisionDetect val2 = default(EnemyAICollisionDetect); for (int i = 0; i < num3; i++) { if (!((Component)RoundManager.Instance.tempColliderResults[i]).gameObject.TryGetComponent<EnemyAICollisionDetect>(ref val2)) { continue; } EnemyAI mainScript = val2.mainScript; if ((Object)(object)mainScript == (Object)(object)instance) { continue; } if (!importEnemyList.Contains(mainScript)) { if (debugLibrary) { LibraryLogger.LogWarning((object)(DebugStringHead(instance) + " /GetEnemiesInLOS/: Enemy not found in imported enemy list! Skipping...")); } continue; } Vector3 position = ((Component)mainScript).transform.position; if (!(Vector3.Distance(position, instance.eye.position) < num) || Physics.Linecast(instance.eye.position, position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) || !instance.CheckLineOfSightForPosition(position, width, (int)num, proximityAwareness, instance.eye)) { continue; } if (!tempDictionary.ContainsKey(mainScript)) { tempDictionary.Add(mainScript, Vector3.Distance(((Component)instance).transform.position, position)); if (debugLibrary && debugSpam) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: Added {mainScript} to tempDictionary"); } } if (tempDictionary.ContainsKey(mainScript) && debugLibrary && debugSpam && debugLibrary) { LibraryLogger.LogWarning((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: {mainScript} is already in tempDictionary"); } } if (tempDictionary.Count > 1) { tempDictionary.OrderBy<KeyValuePair<EnemyAI, float>, Dictionary<EnemyAI, float>.ValueCollection>((KeyValuePair<EnemyAI, float> value) => tempDictionary.Values).Reverse(); if (debugLibrary) { foreach (KeyValuePair<EnemyAI, float> item in tempDictionary) { if (debugLibrary && debugSpam) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: Final list: {item.Key}, range: {item.Value}"); } } } } return tempDictionary; } public static Dictionary<EnemyAI, float> GetEnemiesInLOS(EnemyAI instance, float width = 45f, float importRange = 0f, float proximityAwareness = -1f, float importRadius = 0f, Vector3? importEyePosition = null) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) Dictionary<EnemyAI, float> tempDictionary = new Dictionary<EnemyAI, float>(); float num = importRange; float num2 = importRadius; Vector3 val = instance.eye.position; if (importEyePosition.HasValue) { val = importEyePosition.Value; } int mask = LayerMask.GetMask(new string[1] { "Enemies" }); if (instance.isOutside && !instance.enemyType.canSeeThroughFog && (int)TimeOfDay.Instance.currentLevelWeather == 3) { num = Mathf.Clamp(importRange, 0f, 30f); } if (num2 <= 0f) { num2 = num * 2f; } int num3 = Physics.OverlapSphereNonAlloc(val, num2, RoundManager.Instance.tempColliderResults, mask, (QueryTriggerInteraction)2); EnemyAICollisionDetect val2 = default(EnemyAICollisionDetect); for (int i = 0; i < num3; i++) { if (!((Component)RoundManager.Instance.tempColliderResults[i]).gameObject.TryGetComponent<EnemyAICollisionDetect>(ref val2)) { continue; } EnemyAI mainScript = val2.mainScript; if ((Object)(object)mainScript == (Object)(object)instance) { continue; } Vector3 position = ((Component)mainScript).transform.position; if (!(Vector3.Distance(position, instance.eye.position) < num) || Physics.Linecast(instance.eye.position, position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) || !instance.CheckLineOfSightForPosition(position, width, (int)num, proximityAwareness, instance.eye)) { continue; } if (!tempDictionary.ContainsKey(mainScript)) { tempDictionary.Add(mainScript, Vector3.Distance(((Component)instance).transform.position, position)); if (debugLibrary && debugSpam) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: Added {mainScript} to tempDictionary"); } } if (tempDictionary.ContainsKey(mainScript) && debugLibrary && debugSpam && debugLibrary) { LibraryLogger.LogWarning((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: {mainScript} is already in tempDictionary"); } } if (tempDictionary.Count > 1) { tempDictionary.OrderBy<KeyValuePair<EnemyAI, float>, Dictionary<EnemyAI, float>.ValueCollection>((KeyValuePair<EnemyAI, float> value) => tempDictionary.Values).Reverse(); if (debugLibrary) { foreach (KeyValuePair<EnemyAI, float> item in tempDictionary) { if (debugLibrary && debugSpam) { LibraryLogger.LogDebug((object)$"{DebugStringHead(instance)} /GetEnemiesInLOS/: Final list: {item.Key}, range: {item.Value}"); } } } } return tempDictionary; } [IteratorStateMachine(typeof(<FindClosestEnemy>d__24))] public static IEnumerator FindClosestEnemy(Action<EnemyAI?>? ReturnOwnerResultPairDelegate, List<EnemyAI> importEnemyList, EnemyAI? importClosestEnemy, EnemyAI __instance, int maxIterations = 6, bool useThreatVisibility = true, bool usePathLengthAsDistance = false, bool includeTheDead = false) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FindClosestEnemy>d__24(0) { ReturnOwnerResultPairDelegate = ReturnOwnerResultPairDelegate, importEnemyList = importEnemyList, importClosestEnemy = importClosestEnemy, __instance = __instance, maxIterations = maxIterations, useThreatVisibility = useThreatVisibility, usePathLengthAsDistance = usePathLengthAsDistance, includeTheDead = includeTheDead }; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "fandovec03.NaturalSelectionLib"; public const string PLUGIN_NAME = "NaturalSelectionLib"; public const string PLUGIN_VERSION = "0.7.1"; } } namespace NaturalSelectionLib.Comp { internal static class PathfindingLibHelper { public static PathfindingCalculatorAsyncPathfindingLib ReturnPathfindingLibalculator(EnemyAI instance, List<Vector3> destinations) { return new PathfindingCalculatorAsyncPathfindingLib(instance, destinations); } } internal class PathfindingCalculatorAsyncPathfindingLib : PathfindingCalculator { private SmartPathTask pathfindingTask = new SmartPathTask(); internal PathfindingCalculatorAsyncPathfindingLib(EnemyAI instance, List<Vector3> destinations) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) pathfindingTask.StartPathTask(instance.agent, AgentExtensions.GetPathOrigin(instance.agent), destinations, (SmartPathfindingLinkFlags)0); } public override bool CalculationnStatus(int index, out float pathLengthResult, out bool validPath) { pathLengthResult = -1f; validPath = false; if (!pathfindingTask.IsResultReady(index)) { return true; } if (pathfindingTask.PathSucceeded(index)) { pathLengthResult = pathfindingTask.GetPathLength(index); validPath = pathfindingTask.PathSucceeded(index); return true; } return true; } public override void Dispose() { base.Dispose(); pathfindingTask.Dispose(); } } } namespace NaturalSelectionLib.Tools { internal abstract class PathfindingCalculator : IDisposable { internal static PathfindingCalculator Create(EnemyAI instance, List<Vector3> destinations) { if (Chainloader.PluginInfos.ContainsKey("Zaggy1024.PathfindingLib") && !NaturalSelectionLib.usePathfindingLib) { return PathfindingLibHelper.ReturnPathfindingLibalculator(instance, destinations); } return new PathfindingCalculatorAsync(instance, destinations); } public abstract bool CalculationnStatus(int index, out float pathLengthResult, out bool validPath); public virtual void Dispose() { } } internal class PathfindingCalculatorAsync : PathfindingCalculator { [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private EnemyAI <instance>P; [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private List<Vector3> <destinations>P; private NavMeshPath path; public PathfindingCalculatorAsync(EnemyAI instance, List<Vector3> destinations) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown <instance>P = instance; <destinations>P = destinations; path = new NavMeshPath(); base..ctor(); } public override bool CalculationnStatus(int index, out float pathLengthResult, out bool validPath) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) pathLengthResult = -1f; validPath = false; <instance>P.agent.CalculatePath(<destinations>P[index], path); if ((int)path.status > 0) { return true; } pathLengthResult = 0f; for (int i = 1; i < path.corners.Length; i++) { validPath = true; pathLengthResult += Vector3.Distance(path.corners[i - 1], path.corners[i]); } return true; } } }