Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Natural selection v0.4.18
DLLs/fandovec03.NaturalSelection.dll
Decompiled 2 months 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.18.0")] [assembly: AssemblyInformationalVersion("0.4.18+8609b5f5d89031bc791709eaaf73117893ea343c")] [assembly: AssemblyProduct("NaturalSelection")] [assembly: AssemblyTitle("fandovec03.NaturalSelection")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.18.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.18")] [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 usePathToFindClosestEnemy = false; internal static bool useCoroutines = 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 object[] loggerBlacklist = Array.Empty<object>(); 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; usePathToFindClosestEnemy = BoundingConfig.usePathToFindClosestEnemy.Value; useCoroutines = BoundingConfig.useCoroutines.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.18".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.18")); } 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 { Library.SetLibraryLoggers(Logger, spammyLogs, debugLibrary, usePathToFindClosestEnemy); Logger.LogMessage((object)("Library successfully setup! Version " + Library.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_0098: Unknown result type (might be due to invalid IL or missing references) if (toggle && !loggerBlacklist.Contains<object>(source) && !debugKillSwitchScript) { if (source != null && !(source is EnemyAI) && !(source is SandSpiderWebTrap) && !(source is GrabbableObject) && !(source is Item) && !(source is string)) { Logger.LogError((object)$"! Unsupported type {source.GetType()} found in LogNS! Blacklisting source: {source}"); CollectionExtensions.AddItem<object>((IEnumerable<object>)loggerBlacklist, source); } Logger.Log(logLevel, (object)(LibraryCalls.DebugStringHead(source, !moreDetail) + " " + log)); } } public static void ClearLogBlacklist() { Array.Clear(loggerBlacklist, 0, loggerBlacklist.Length); } 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.18"; } } 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; Library.SetLibraryLoggers(Script.Logger, value, debugLibraryCalls, false); } if (entryKey == "debugLibraryTrigger") { debugLibraryCalls = value; Library.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 LibraryMethods.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 LibraryMethods.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!"); } LibraryMethods.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 LibraryMethods.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!"); } LibraryMethods.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!"); } LibraryMethods.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!"); } LibraryMethods.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 LibraryMethods.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 LibraryMethods.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 LibraryMethods.FindClosestEnemy(ReturnOwnerResult, importEnemyList, importClosestEnemy, instance, maxIterations, useThreatVisibility, usePathLenghtAsDistance, includeTheDead); } public static List<EnemyAI> GetEnemyList(Type type) { return Library.GetEnemyList(type); } } internal class MyModConfig { public readonly ConfigEntry<bool> useCoroutines; 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_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Expected O, but got Unknown //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: 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."); useCoroutines = cfg.Bind<bool>("Beta", "Enable experimental library coroutines", false, "Use coroutines to closest enemy. Might improve performance slightly."); usePathToFindClosestEnemy = cfg.Bind<bool>("Beta", "Use pathfinding to find closest enemy", false, "Enemies will use pathfinding to find closest enemy. Uses PathfindingLib if present. \n \n [Might cause performance drops without PathfindingLib]"); stableMode = cfg.Bind<bool>("General Settings", "Toggle stable mode", true, "When true, the mod will exlude patches that are WIP or 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 an interval how often are internal global enemy lists updated. Default is one second."); customSizeOverrideList = cfg.Bind<string>("DEV", "Custom size override list", "", "Set what size the enemy is considered as by the mod. Generates automatically empty."); enableSpider = cfg.Bind<bool>("Entity settings", "Enable spider", true, "Apply changes to spider and modify it's behavior."); enableSlime = cfg.Bind<bool>("Entity settings", "Enable slime", true, "Apply changes to slime and modify it's behavior."); enableLeviathan = cfg.Bind<bool>("Entity settings", "Enable leviathan", true, "Apply changes to to leviathan and modify it's behavior."); enableSporeLizard = cfg.Bind<bool>("DEV", "Enable SporeLizard", false, "Apply changes to spore lizard. \n\n Early build. DEV ONLY"); enableRedBees = cfg.Bind<bool>("Entity settings", "Enable Red bees (Circuit bees)", true, "Apply changes to red bees and modify it's behavior."); enableNutcracker = cfg.Bind<bool>("DEV", "Enable Nutcracker", false, "Apply changes to apply to and modify its behavior. \n\n Early build. DEV ONLY"); enableGiant = cfg.Bind<bool>("Entity settings", "Enable Giant", true, "Apply changes to to forest giant."); enableHoardingBug = cfg.Bind<bool>("DEV", "Enable Hoarding bug", false, "Apply changes to hoarding bug"); enableSpiderWebs = cfg.Bind<bool>("Entity settings", "Enable Spider Webs", true, "Apply changes to spider webs. Webs will stick to and slow enemies down."); giantExtinguishChance = cfg.Bind<int>("Entity settings | Giant", "Extinguish chance", 33, new ConfigDescription("Chance of giants extinguishing themselves. Values are 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("Default chance bees will set giant on fire.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); beesSetGiantsOnFireMaxChance = cfg.Bind<float>("Entity settings | Giant", "Ignite giants max chace", 8f, new ConfigDescription("Chance bees will set giant on fire when bees are enraged.", (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, "Hygrodere will move towards other organisms to consume."); blobAIOpeningDoorsMultiplier = cfg.Bind<float>("Entity settings | Hygrodere", "Open door multiplier", 0.7f, "Multiplier opening doors speed. 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 when leaving the moon."); chaseAfterEnemiesModifier = cfg.Bind<float>("Entity settings | Spider/Spider Web", "Enemy chase timer modifier", 3f, "Set the chase timer for enemies from player chase timer by dividing it with set number. \n Formula: [Player chase timer : set number = Enemy chase timer]"); speedModifierList = cfg.Bind<string>("Entity settings | Spider/Spider Web", "Web speed modifiers", "", "Modify the final speed for enemy when stuck in spider webs. \n Formula: [Enemy speed when touching spider web : ((1 + number of web enemy is stuck in) * web strength) * set number] \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 web slow downs. Stronger spider webs slow enemies more. \n Formula: [Enemy speed when touching spider web : ((1 + number of web enemy is stuck in) * set number ) * web speed modifier]"); 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(); Library.ClearAllEnemyLists(); EnemyAIPatch.enemyDataDict.Clear(); Script.ClearLogBlacklist(); } [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(); Library.ClearAllEnemyLists(); EnemyAIPatch.enemyDataDict.Clear(); Script.ClearLogBlacklist(); } } [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()) { Library.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 (!Library.EnemyListContainsKey(((object)instance).GetType())) { Script.LogNS((LogLevel)4, LibraryCalls.DebugStringHead(instance) + " global enemy list for this enemy does not exist! Creating a new one."); Library.CreateEnemyList(((object)instance).GetType(), checkedTypes[((object)instance).GetType()]); } else { Library.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); temp = null; if (dataID != "-1") { 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) string text = "-1"; if (instance == null) { return text; } if (instance is EnemyAI) { text = ((EnemyAI)instance).enemyType.enemyName + ((NetworkBehaviour)(EnemyAI)instance).NetworkObjectId; if (returnToEnemyAIType) { text += ".base"; } } else if (instance is SandSpiderWebTrap && (Object)(object)((SandSpiderWebTrap)instance).mainScript != (Object)null) { 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_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected O, but got Unknown if (((object)mainscript2).GetType() == typeof(RedLocustBees)) { return; } BeeValues beeValues = (BeeValues)Utilities.GetEnemyData(__instance, new BeeValues()); if (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 bool spammyLogs = Script.Bools["spammyLogs"]; 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 == "spammyLogs") { spammyLogs = 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, logBlob && spammyLogs); 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 = LibraryCalls.GetEnemyList(type); LibraryCalls.GetInsideOrOutsideEnemyList(ref importEnemyList2, (EnemyAI)(object)__instance); if (Script.useCoroutines) { 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 && ((NetworkBehaviour)mainscript2).IsOwner) { if (((NetworkBehaviour)__instance).IsOwner && mainscript2.thisNetworkObject.IsSpawned) { BlobEatCorpseEvent(__instance).InvokeClients(); Script.LogNS((LogLevel)8, "consumed dead body of " + mainscript2.enemyType.enemyName, __instance); if (((NetworkBehaviour)mainscript2).IsServer) { mainscript2.KillEnemy(true); } else { mainscript2.KillEnemyServerRpc(true); } 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