Please disclose if any significant portion of your mod was created 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 Anomalies v1.0.0
Y4NGZDreadweaver.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Y4NGZDreadweaver.AI; using Y4NGZDreadweaver.NetcodePatcher; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZDreadweaver")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZDreadweaver")] [assembly: AssemblyTitle("Y4NGZDreadweaver")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZDreadweaver { internal sealed class DreadweaverConfig { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<float> SpawnWeightMultiplier { get; } public ConfigEntry<int> MaxCount { get; } public ConfigEntry<float> PowerLevel { get; } public ConfigEntry<int> Health { get; } public ConfigEntry<float> SightingIntervalMinSeconds { get; } public ConfigEntry<float> SightingIntervalMaxSeconds { get; } public ConfigEntry<float> AttackDelayMinSeconds { get; } public ConfigEntry<float> AttackDelayMaxSeconds { get; } public ConfigEntry<float> StalkMoveSpeed { get; } public ConfigEntry<float> CrawlSpeed { get; } public ConfigEntry<float> AttackSpeed { get; } public ConfigEntry<int> AttackDamage { get; } public ConfigEntry<float> AttackCooldown { get; } public ConfigEntry<bool> CreatureSpotlightEnabled { get; } public ConfigEntry<bool> FlashlightHarassEnabled { get; } public ConfigEntry<bool> DebugLogs { get; } public DreadweaverConfig(ConfigFile config) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Expected O, but got Unknown //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Expected O, but got Unknown bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { DreadweaverConfigMigration.TryMigrate(config, Plugin.Log); ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Dreadweaver"); Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Dreadweaver encounter."); SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Dreadweaver's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Dreadweavers at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>())); PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.8f, new ConfigDescription("Indoor enemy power budget cost for each Dreadweaver.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits the Dreadweaver can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); SightingIntervalMinSeconds = config.Bind<float>("Encounter Pacing", "SightingIntervalMinSeconds", 45f, new ConfigDescription("Minimum hidden time between completed sightings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 120f), Array.Empty<object>())); SightingIntervalMaxSeconds = config.Bind<float>("Encounter Pacing", "SightingIntervalMaxSeconds", 65f, new ConfigDescription("Maximum hidden time between completed sightings; values below the minimum are raised at runtime.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 150f), Array.Empty<object>())); AttackDelayMinSeconds = config.Bind<float>("Encounter Pacing", "AttackDelayMinSeconds", 15f, new ConfigDescription("Minimum hidden time between the final sighting and attack reveal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>())); AttackDelayMaxSeconds = config.Bind<float>("Encounter Pacing", "AttackDelayMaxSeconds", 30f, new ConfigDescription("Maximum hidden time before attack reveal; values below the minimum are raised at runtime.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), Array.Empty<object>())); StalkMoveSpeed = config.Bind<float>("Movement", "StalkMoveSpeed", 1.5f, new ConfigDescription("Movement speed outside committed attacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 4f), Array.Empty<object>())); CrawlSpeed = config.Bind<float>("Movement", "CrawlSpeed", 2.1f, new ConfigDescription("Movement speed during a crawl attack reveal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 4f), Array.Empty<object>())); AttackSpeed = config.Bind<float>("Movement", "AttackSpeed", 5.15f, new ConfigDescription("Movement speed during committed pursuit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 9f), Array.Empty<object>())); AttackDamage = config.Bind<int>("Combat", "AttackDamage", 40, new ConfigDescription("Damage dealt by a successful strike.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.8f, new ConfigDescription("Minimum recovery between attack attempts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>())); CreatureSpotlightEnabled = config.Bind<bool>("Presentation", "CreatureSpotlightEnabled", true, "Light the visible Dreadweaver so the encounter remains readable in dark interiors."); FlashlightHarassEnabled = config.Bind<bool>("Presentation", "FlashlightHarassEnabled", true, "Briefly glitch the stalked player's flashlight or helmet lamp when it cloaks nearby."); DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Log detailed Dreadweaver targeting and setup diagnostics."); } finally { config.SaveOnConfigSet = saveOnConfigSet; if (saveOnConfigSet) { config.Save(); } } } } internal static class DreadweaverConfigMigration { private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight"); private static readonly ConfigDefinition[] RetainedLegacyDefinitions = (ConfigDefinition[])(object)new ConfigDefinition[15] { new ConfigDefinition("Spawning", "MaxCount"), new ConfigDefinition("Spawning", "PowerLevel"), new ConfigDefinition("Stats", "Health"), new ConfigDefinition("Movement", "StalkMoveSpeed"), new ConfigDefinition("Movement", "CrawlSpeed"), new ConfigDefinition("Movement", "AttackSpeed"), new ConfigDefinition("Sightings", "SightingIntervalMinSeconds"), new ConfigDefinition("Sightings", "SightingIntervalMaxSeconds"), new ConfigDefinition("Attack", "AttackDelayMinSeconds"), new ConfigDefinition("Attack", "AttackDelayMaxSeconds"), new ConfigDefinition("Attack", "AttackDamage"), new ConfigDefinition("Attack", "AttackCooldown"), new ConfigDefinition("Visuals", "CreatureSpotlightEnabled"), new ConfigDefinition("Visuals", "FlashlightHarassEnabled"), new ConfigDefinition("Debug", "DebugLogs") }; private static readonly Dictionary<ConfigDefinition, string> RemovedDefaults = new Dictionary<ConfigDefinition, string> { { new ConfigDefinition("Spawning", "LevelMask"), "-1" }, { new ConfigDefinition("Stats", "ModelScale"), "1.75" }, { new ConfigDefinition("Movement", "TurnSpeed"), "420" }, { new ConfigDefinition("Movement", "Acceleration"), "18" }, { new ConfigDefinition("Sightings", "LongSightingMinDistance"), "30" }, { new ConfigDefinition("Sightings", "LongSightingMaxDistance"), "50" }, { new ConfigDefinition("Sightings", "LongSightingHoldSeconds"), "1.35" }, { new ConfigDefinition("Sightings", "MediumSightingMinDistance"), "15" }, { new ConfigDefinition("Sightings", "MediumSightingMaxDistance"), "30" }, { new ConfigDefinition("Sightings", "MediumSightingHoldSeconds"), "1.15" }, { new ConfigDefinition("Sightings", "ShortSightingMinDistance"), "4" }, { new ConfigDefinition("Sightings", "ShortSightingMaxDistance"), "8" }, { new ConfigDefinition("Sightings", "ShortSightingHoldSeconds"), "1" }, { new ConfigDefinition("Sightings", "SightingRetryMinSeconds"), "15" }, { new ConfigDefinition("Sightings", "SightingRetryMaxSeconds"), "30" }, { new ConfigDefinition("Sightings", "SightingTimeoutSeconds"), "12" }, { new ConfigDefinition("Sightings", "PlayerSpotAngle"), "25" }, { new ConfigDefinition("Sightings", "CreatureSightRange"), "60" }, { new ConfigDefinition("Stalking ambience", "LightFlickerRadius"), "18" }, { new ConfigDefinition("Stalking ambience", "LightFlickerIntervalMinSeconds"), "40" }, { new ConfigDefinition("Stalking ambience", "LightFlickerIntervalMaxSeconds"), "70" }, { new ConfigDefinition("Stalking ambience", "DoorSlamRadius"), "14" }, { new ConfigDefinition("Stalking ambience", "DoorSlamIntervalMinSeconds"), "35" }, { new ConfigDefinition("Stalking ambience", "DoorSlamIntervalMaxSeconds"), "70" }, { new ConfigDefinition("Attack", "AttackRevealMinDistance"), "8" }, { new ConfigDefinition("Attack", "AttackRevealMaxDistance"), "16" }, { new ConfigDefinition("Attack", "CrawlAdvanceSeconds"), "3" }, { new ConfigDefinition("Attack", "AttackRange"), "2.35" }, { new ConfigDefinition("Attack", "AttackDamageDelay"), "0.48" }, { new ConfigDefinition("Attack", "AttackHitArcDegrees"), "120" }, { new ConfigDefinition("Attack", "AttackLoseDistance"), "48" }, { new ConfigDefinition("Attack", "AttackLostSightGraceSeconds"), "12" }, { new ConfigDefinition("Attack", "PursuitRepositionCooldownMinSeconds"), "2" }, { new ConfigDefinition("Attack", "PursuitRepositionCooldownMaxSeconds"), "5" }, { new ConfigDefinition("Attack", "PursuitRepositionMinDistance"), "10" }, { new ConfigDefinition("Attack", "ChainAttackRadius"), "13" }, { new ConfigDefinition("Camo", "VanishFlickerSeconds"), "0.65" }, { new ConfigDefinition("Camo", "DecloakFlickerSeconds"), "0.55" }, { new ConfigDefinition("Animation", "MatchAnimationToMovement"), "true" }, { new ConfigDefinition("Animation", "AuthoredWalkSpeed"), "1.9" }, { new ConfigDefinition("Animation", "AuthoredCrawlSpeed"), "1.9" }, { new ConfigDefinition("Animation", "AuthoredRunSpeed"), "3.6" }, { new ConfigDefinition("Visuals", "CreatureSpotlightIntensity"), "18" }, { new ConfigDefinition("Visuals", "CreatureSpotlightRange"), "14" }, { new ConfigDefinition("Visuals", "CreatureSpotlightAngle"), "42" }, { new ConfigDefinition("Visuals", "CreatureSpotlightHeight"), "5" }, { new ConfigDefinition("Visuals", "DramaticSpotlightChance"), "0.35" } }; internal static bool TryMigrate(ConfigFile config, ManualLogSource log) { string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return false; } Dictionary<ConfigDefinition, string> dictionary = null; string text = null; try { dictionary = ReadValues(configFilePath); if (!ContainsLegacyConfig(dictionary)) { return false; } text = GetBackupPath(configFilePath); File.Copy(configFilePath, text, overwrite: false); File.WriteAllText(configFilePath, BuildMigratedConfig(dictionary), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } catch (Exception ex) { string text2 = "The original config was not modified."; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Copy(text, configFilePath, overwrite: true); config.Reload(); text2 = "The original config was restored from its backup."; } catch (Exception ex2) { text2 = "Automatic restore also failed: " + ex2.GetBaseException().Message + ". Recover manually from " + text + "."; } } if (log != null) { log.LogWarning((object)("[Dreadweaver] Could not migrate legacy config: " + ex.GetBaseException().Message + " " + text2)); } return false; } List<string> list = FindCustomizedDroppedKeys(dictionary); if (log != null) { log.LogInfo((object)("[Dreadweaver] Migrated legacy config to the compact DawnLib layout. Backup: " + text)); } if (list.Count > 0 && log != null) { log.LogWarning((object)("[Dreadweaver] These customized legacy settings are now authored source tuning and were not carried forward: " + string.Join(", ", list))); } return true; } private static bool ContainsLegacyConfig(Dictionary<ConfigDefinition, string> values) { if (values.ContainsKey(LegacySpawnWeight)) { return true; } for (int i = 0; i < RetainedLegacyDefinitions.Length; i++) { if (values.ContainsKey(RetainedLegacyDefinitions[i])) { return true; } } foreach (ConfigDefinition key in RemovedDefaults.Keys) { if (values.ContainsKey(key)) { return true; } } return false; } private static string BuildMigratedConfig(Dictionary<ConfigDefinition, string> values) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_010b: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown //IL_0145: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Expected O, but got Unknown //IL_0190: Expected O, but got Unknown //IL_01bd: 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) //IL_01db: Expected O, but got Unknown //IL_01db: Expected O, but got Unknown //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected O, but got Unknown //IL_0215: Expected O, but got Unknown //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown //IL_024f: Expected O, but got Unknown //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Expected O, but got Unknown //IL_0289: Expected O, but got Unknown //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Expected O, but got Unknown //IL_02d4: Expected O, but got Unknown //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Expected O, but got Unknown //IL_030e: Expected O, but got Unknown //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Expected O, but got Unknown //IL_0348: Expected O, but got Unknown //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Expected O, but got Unknown //IL_0393: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Expected O, but got Unknown //IL_03cd: Expected O, but got Unknown //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Expected O, but got Unknown //IL_0418: Expected O, but got Unknown //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Expected O, but got Unknown //IL_0452: Expected O, but got Unknown //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_048e: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Expected O, but got Unknown //IL_049d: Expected O, but got Unknown string text = GetValue(values, new ConfigDefinition("10 - Spawning", "SpawnWeightMultiplier"), null, null); if (string.IsNullOrWhiteSpace(text)) { text = ((!float.TryParse(GetValue(values, LegacySpawnWeight, null, "12"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) ? "1" : Math.Max(0f, Math.Min(5f, result / 12f)).ToString("0.###", CultureInfo.InvariantCulture)); } StringBuilder stringBuilder = new StringBuilder(); AppendSection(stringBuilder, "00 - General", ("Enabled", GetValue(values, new ConfigDefinition("00 - General", "Enabled"), null, "true"))); AppendSection(stringBuilder, "10 - Spawning", ("SpawnWeightMultiplier", text), ("MaxCount", GetValue(values, new ConfigDefinition("10 - Spawning", "MaxCount"), new ConfigDefinition("Spawning", "MaxCount"), "1")), ("PowerLevel", GetValue(values, new ConfigDefinition("10 - Spawning", "PowerLevel"), new ConfigDefinition("Spawning", "PowerLevel"), "2.8"))); AppendSection(stringBuilder, "20 - Core Stats", ("Health", GetValue(values, new ConfigDefinition("20 - Core Stats", "Health"), new ConfigDefinition("Stats", "Health"), "5"))); AppendSection(stringBuilder, "30 - Encounter Pacing", ("SightingIntervalMinSeconds", GetValue(values, new ConfigDefinition("30 - Encounter Pacing", "SightingIntervalMinSeconds"), new ConfigDefinition("Sightings", "SightingIntervalMinSeconds"), "45")), ("SightingIntervalMaxSeconds", GetValue(values, new ConfigDefinition("30 - Encounter Pacing", "SightingIntervalMaxSeconds"), new ConfigDefinition("Sightings", "SightingIntervalMaxSeconds"), "65")), ("AttackDelayMinSeconds", GetValue(values, new ConfigDefinition("30 - Encounter Pacing", "AttackDelayMinSeconds"), new ConfigDefinition("Attack", "AttackDelayMinSeconds"), "15")), ("AttackDelayMaxSeconds", GetValue(values, new ConfigDefinition("30 - Encounter Pacing", "AttackDelayMaxSeconds"), new ConfigDefinition("Attack", "AttackDelayMaxSeconds"), "30"))); AppendSection(stringBuilder, "40 - Movement", ("StalkMoveSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "StalkMoveSpeed"), new ConfigDefinition("Movement", "StalkMoveSpeed"), "1.5")), ("CrawlSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "CrawlSpeed"), new ConfigDefinition("Movement", "CrawlSpeed"), "2.1")), ("AttackSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "AttackSpeed"), new ConfigDefinition("Movement", "AttackSpeed"), "5.15"))); AppendSection(stringBuilder, "50 - Combat", ("AttackDamage", GetValue(values, new ConfigDefinition("50 - Combat", "AttackDamage"), new ConfigDefinition("Attack", "AttackDamage"), "40")), ("AttackCooldown", GetValue(values, new ConfigDefinition("50 - Combat", "AttackCooldown"), new ConfigDefinition("Attack", "AttackCooldown"), "1.8"))); AppendSection(stringBuilder, "60 - Presentation", ("CreatureSpotlightEnabled", GetValue(values, new ConfigDefinition("60 - Presentation", "CreatureSpotlightEnabled"), new ConfigDefinition("Visuals", "CreatureSpotlightEnabled"), "true")), ("FlashlightHarassEnabled", GetValue(values, new ConfigDefinition("60 - Presentation", "FlashlightHarassEnabled"), new ConfigDefinition("Visuals", "FlashlightHarassEnabled"), "true"))); AppendSection(stringBuilder, "99 - Diagnostics", ("DebugLogs", GetValue(values, new ConfigDefinition("99 - Diagnostics", "DebugLogs"), new ConfigDefinition("Debug", "DebugLogs"), "false"))); return stringBuilder.ToString(); } private static void AppendSection(StringBuilder output, string section, params (string Key, string Value)[] entries) { output.Append('[').Append(section).AppendLine("]"); for (int i = 0; i < entries.Length; i++) { output.Append(entries[i].Key).Append(" = ").AppendLine(entries[i].Value); } output.AppendLine(); } private static string GetValue(Dictionary<ConfigDefinition, string> values, ConfigDefinition preferred, ConfigDefinition legacy, string fallback) { if (preferred != (ConfigDefinition)null && values.TryGetValue(preferred, out var value)) { return value; } if (legacy != (ConfigDefinition)null && values.TryGetValue(legacy, out value)) { return value; } return fallback; } private static Dictionary<ConfigDefinition, string> ReadValues(string path) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(); string text = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string value = text2.Substring(num + 1).Trim(); dictionary[new ConfigDefinition(text, text3)] = value; } } return dictionary; } private static List<string> FindCustomizedDroppedKeys(Dictionary<ConfigDefinition, string> values) { List<string> list = new List<string>(); foreach (KeyValuePair<ConfigDefinition, string> removedDefault in RemovedDefaults) { if (values.TryGetValue(removedDefault.Key, out var value) && !ValuesEquivalent(value, removedDefault.Value)) { list.Add(removedDefault.Key.Section + "." + removedDefault.Key.Key); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private static bool ValuesEquivalent(string left, string right) { if (string.Equals(left.Trim(), right.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } if (float.TryParse(left, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(right, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) < 0.0001f; } return false; } private static string GetBackupPath(string configPath) { string text = configPath + ".pre-dawn.bak"; if (!File.Exists(text)) { return text; } for (int i = 2; i < 1000; i++) { string text2 = configPath + $".pre-dawn.{i}.bak"; if (!File.Exists(text2)) { return text2; } } throw new IOException("Could not allocate a Dreadweaver config backup filename."); } } internal sealed class DreadweaverSpawnWeights : IWeighted, IContextualWeighted<SpawnWeightContext> { internal const int DefaultWeight = 3; internal const int MaximumWeight = 100; private readonly Func<float> _multiplier; internal DreadweaverSpawnWeights(Func<float> multiplier) { _multiplier = multiplier ?? throw new ArgumentNullException("multiplier"); } public int GetWeight() { return Scale(3, 1f); } public int GetWeight(SpawnWeightContext context) { int moonWeight = GetMoonWeight(((SpawnWeightContext)(ref context)).Moon); if (moonWeight <= 0) { return 0; } return Scale(moonWeight, GetDungeonMultiplier(((SpawnWeightContext)(ref context)).Dungeon)); } internal static int GetMoonWeight(DawnMoonInfo moon) { if (moon == null) { return 3; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Company) || ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Unimplemented) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Test)) { return 0; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Experimentation)) { return 1; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Assurance) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Vow)) { return 3; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Offense) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.March) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Embrion)) { return 5; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Adamance)) { return 7; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Rend) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Dine)) { return 9; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Titan) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Artifice) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Liquidation)) { return 11; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Paid)) { return 8; } ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Free); return 3; } internal static float GetDungeonMultiplier(DawnDungeonInfo dungeon) { if (dungeon == null) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MansionFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Gothic) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Grand) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Ornate) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Lavish) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Eerie)) { return 1.25f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlow) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowThreeExits) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowExtraLarge) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Industrial) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Mechanical) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Factory) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Bunker)) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MineshaftFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Cavern) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Quarry) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Flooded)) { return 0.5f; } return 0.75f; } private int Scale(int moonWeight, float dungeonMultiplier) { float num = Mathf.Clamp(_multiplier(), 0f, 5f); return Mathf.Clamp(Mathf.RoundToInt((float)moonWeight * dungeonMultiplier * num), 0, 100); } private static bool KeyEquals<T>(NamespacedKey<T> left, NamespacedKey<T> right) where T : INamespaced { if (left != null && right != null) { return ((object)left).Equals((object?)right); } return false; } } internal static class DreadweaverTuning { internal const float ModelScale = 1.75f; internal const float TurnSpeed = 420f; internal const float Acceleration = 18f; internal const float AgentRadius = 0.86f; internal const float AgentHeight = 2.45f; internal const float LongSightingMinDistance = 30f; internal const float LongSightingMaxDistance = 50f; internal const float LongSightingHoldSeconds = 1.35f; internal const float MediumSightingMinDistance = 15f; internal const float MediumSightingMaxDistance = 30f; internal const float MediumSightingHoldSeconds = 1.15f; internal const float ShortSightingMinDistance = 4f; internal const float ShortSightingMaxDistance = 8f; internal const float ShortSightingHoldSeconds = 1f; internal const float SightingRetryMinSeconds = 15f; internal const float SightingRetryMaxSeconds = 30f; internal const float SightingTimeoutSeconds = 12f; internal const float PlayerSpotAngle = 25f; internal const float CreatureSightRange = 60f; internal const float StalkLightFlickerRadius = 18f; internal const float StalkLightFlickerIntervalMinSeconds = 40f; internal const float StalkLightFlickerIntervalMaxSeconds = 70f; internal const float StalkDoorSlamRadius = 14f; internal const float StalkDoorSlamIntervalMinSeconds = 35f; internal const float StalkDoorSlamIntervalMaxSeconds = 70f; internal const float AttackRevealMinDistance = 8f; internal const float AttackRevealMaxDistance = 16f; internal const float CrawlAdvanceSeconds = 3f; internal const float AttackRange = 2.35f; internal const float AttackDamageDelay = 0.48f; internal const float AttackHitArcDegrees = 120f; internal const float AttackLoseDistance = 48f; internal const float AttackLostSightGraceSeconds = 12f; internal const float PursuitRepositionCooldownMinSeconds = 2f; internal const float PursuitRepositionCooldownMaxSeconds = 5f; internal const float PursuitRepositionMinDistance = 10f; internal const float ChainAttackRadius = 13f; internal const float VanishFlickerSeconds = 0.65f; internal const float DecloakFlickerSeconds = 0.55f; internal const bool MatchAnimationToMovement = true; internal const float AuthoredWalkSpeed = 1.9f; internal const float AuthoredCrawlSpeed = 1.9f; internal const float AuthoredRunSpeed = 3.6f; internal const float CreatureSpotlightIntensity = 18f; internal const float CreatureSpotlightRange = 14f; internal const float CreatureSpotlightAngle = 42f; internal const float CreatureSpotlightHeight = 5f; } [BepInPlugin("y4ngz.lethalcompany.dreadweaver", "Y4NGZ Dreadweaver", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal const string BundleFilename = "dreadweaver.bundle"; internal const string PrefabName = "SK_Dreadweaver"; internal const string AlternatePrefabName = "Dreadweaver"; internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "dreadweaver"; internal const string ScanNodeSubtitle = ""; internal const string BestiaryText = "Dreadweaver\n\nDanger level: high\n\nA facility stalker that fixates on a single worker. It stages a sequence of sightings, each closer than the last, vanishing the moment it is approached or watched too long. A third, very close sighting means the hunt is nearly over.\n\n"; internal static ManualLogSource Log; internal static DreadweaverConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType DreadweaverEnemyType; private static bool _netcodeInitialized; private static bool _loggedScanNodeLayer; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new DreadweaverConfig(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Dreadweaver is disabled by config."); } else { if (!LoadBundle()) { return; } GameObject val = LoadBundlePrefab(); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Prefab 'SK_Dreadweaver' not found in dreadweaver.bundle."); DumpBundleAssets(); return; } PreparePrefab(val); DreadweaverEnemyType = CreateEnemyType(val); DreadweaverAI component = val.GetComponent<DreadweaverAI>(); if ((Object)(object)component != (Object)null) { ((EnemyAI)component).enemyType = DreadweaverEnemyType; } RegisterWithDawn(val); Log.LogInfo((object)"Y4NGZ Dreadweaver v0.1.0 loaded. Registered as 'dreadweaver'."); } } catch (Exception arg) { Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Dreadweaver", arg)); } } private static void RegisterWithDawn(GameObject prefab) { DreadweaverSpawnWeights spawnWeights = new DreadweaverSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(prefab); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "dreadweaver"), DreadweaverEnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Dreadweaver\n\nDanger level: high\n\nA facility stalker that fixates on a single worker. It stages a sequence of sightings, each closer than the last, vanishing the moment it is approached or watched too long. A third, very close sighting means the hunt is nearly over.\n\n").CreateNameKeyword("dreadweaver")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[5] { Tags.Hostile, Tags.Organic, Tags.Killable, Tags.Biped, Tags.Medium }); }); } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0) { continue; } try { methodInfo.Invoke(null, null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message)); } } } } } private static bool LoadBundle() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrEmpty(directoryName)) { Log.LogError((object)"Could not resolve plugin assembly directory."); return false; } string text = Path.Combine(directoryName, "dreadweaver.bundle"); if (!File.Exists(text)) { Log.LogError((object)("Missing asset bundle: " + text)); return false; } ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + ".")); return false; } return true; } private static GameObject LoadBundlePrefab() { GameObject val = ModAssets.LoadAsset<GameObject>("SK_Dreadweaver") ?? ModAssets.LoadAsset<GameObject>("Dreadweaver"); if ((Object)(object)val != (Object)null) { return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { string text2 = text.Replace('\\', '/'); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (text2.EndsWith("/sk_dreadweaver.prefab", StringComparison.OrdinalIgnoreCase) || text2.EndsWith("/dreadweaver.prefab", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "SK_Dreadweaver", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "Dreadweaver", StringComparison.OrdinalIgnoreCase)) { val = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val != (Object)null) { return val; } } } return null; } private static void PreparePrefab(GameObject prefab) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) AssignUniqueNetworkHash(prefab); prefab.SetActive(true); TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); prefab.transform.localScale = Vector3.one * 1.75f; DreadweaverAI dreadweaverAI = prefab.GetComponent<DreadweaverAI>(); if ((Object)(object)dreadweaverAI == (Object)null) { dreadweaverAI = prefab.AddComponent<DreadweaverAI>(); } if ((Object)(object)prefab.GetComponent<NetworkObject>() == (Object)null) { prefab.AddComponent<NetworkObject>(); } Animator val = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true); if ((Object)(object)val != (Object)null) { val.applyRootMotion = false; val.cullingMode = (AnimatorCullingMode)0; dreadweaverAI.visualAnimator = val; } else { Log.LogWarning((object)"[Dreadweaver] Prefab has no Animator."); } NavMeshAgent val2 = prefab.GetComponent<NavMeshAgent>(); if ((Object)(object)val2 == (Object)null) { val2 = prefab.AddComponent<NavMeshAgent>(); } ConfigureAgent(val2); ((EnemyAI)dreadweaverAI).agent = val2; ((EnemyAI)dreadweaverAI).creatureSFX = FindOrCreateAudioSource(prefab.transform, "CreatureSFX", 42f); ((EnemyAI)dreadweaverAI).creatureVoice = FindOrCreateAudioSource(prefab.transform, "CreatureVoice", 46f); ((EnemyAI)dreadweaverAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 1.85f, 0.55f)); dreadweaverAI.attackOrigin = FindOrCreateChild(prefab.transform, "AttackOrigin", new Vector3(0f, 1.2f, 0.95f)); AssignDreadweaverAudio(dreadweaverAI); EnsureDreadweaverRendering(prefab, (EnemyAI)(object)dreadweaverAI); EnsureBehaviourStates(dreadweaverAI); EnsureScanNode(prefab); EnsureCollision(prefab, dreadweaverAI); } private static void ConfigureAgent(NavMeshAgent agent) { agent.speed = ModConfig.StalkMoveSpeed.Value; agent.angularSpeed = 420f; agent.acceleration = 18f; agent.stoppingDistance = Mathf.Max(0.5f, 1.5274999f); agent.radius = 0.86f; agent.height = 2.45f; agent.baseOffset = 0f; agent.autoBraking = true; agent.autoRepath = true; agent.updateRotation = false; agent.areaMask = -1; agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; agent.avoidancePriority = 31; } private static void EnsureDreadweaverRendering(GameObject prefab, EnemyAI ai) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true); MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true); ai.skinnedMeshRenderers = componentsInChildren; ai.meshRenderers = componentsInChildren2; Bounds localBounds = default(Bounds); ((Bounds)(ref localBounds))..ctor(Vector3.up * 1.25f, new Vector3(7.5f, 5.5f, 7.5f)); foreach (SkinnedMeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val)) { ActivateRendererHierarchy(prefab.transform, ((Component)val).transform); ((Component)val).gameObject.SetActive(true); ((Renderer)val).enabled = true; ((Renderer)val).forceRenderingOff = false; val.updateWhenOffscreen = true; ((Renderer)val).localBounds = localBounds; ((Renderer)val).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val).receiveShadows = true; EnsureRendererHasOpaqueMaterial((Renderer)(object)val); } } foreach (MeshRenderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val2)) { ActivateRendererHierarchy(prefab.transform, ((Component)val2).transform); ((Component)val2).gameObject.SetActive(true); ((Renderer)val2).enabled = true; ((Renderer)val2).forceRenderingOff = false; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val2).receiveShadows = true; EnsureRendererHasOpaqueMaterial((Renderer)(object)val2); } } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"[DreadweaverRenderer] Prepared {componentsInChildren.Length} skinned renderer(s), {componentsInChildren2.Length} mesh renderer(s)."); } } private static void ActivateRendererHierarchy(Transform prefabRoot, Transform rendererTransform) { Transform val = rendererTransform; while ((Object)(object)val != (Object)null) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } if (!((Object)(object)val == (Object)(object)prefabRoot)) { val = val.parent; continue; } break; } } private static bool IsRuntimeHelperRenderer(Renderer renderer) { Transform val = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).transform : null); while ((Object)(object)val != (Object)null) { string text = ((Object)val).name ?? string.Empty; if (text.IndexOf("ScanNode", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Collision", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("MapDot", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static void EnsureRendererHasOpaqueMaterial(Renderer renderer) { Material[] array = renderer.sharedMaterials; if (array == null || array.Length == 0) { array = (Material[])(object)new Material[1]; } bool flag = false; for (int i = 0; i < array.Length; i++) { Material val = array[i]; if ((Object)(object)val == (Object)null || (Object)(object)val.shader == (Object)null || ShouldReplaceDreadweaverMaterial(val)) { array[i] = CreateOpaqueDreadweaverMaterial(val); flag = true; } else { ForceOpaqueMaterial(val); } } if (flag) { renderer.sharedMaterials = array; } } private static bool ShouldReplaceDreadweaverMaterial(Material material) { string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name : string.Empty); if (text.IndexOf("InternalError", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.IndexOf("Standard", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (material.IsKeywordEnabled("_ALPHATEST_ON") || material.renderQueue == 2450 || material.renderQueue >= 3000) { return true; } return false; } private static Material CreateOpaqueDreadweaverMaterial(Material source) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_0144: Expected O, but got Unknown Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Diffuse"); Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(source)); ((Object)val2).name = "M_DreadweaverRuntimeVisible"; Texture texture = (((Object)(object)source != (Object)null) ? source.mainTexture : null); Texture texture2 = (((Object)(object)source != (Object)null && source.HasProperty("_BumpMap")) ? source.GetTexture("_BumpMap") : null); Texture texture3 = (((Object)(object)source != (Object)null && source.HasProperty("_MetallicGlossMap")) ? source.GetTexture("_MetallicGlossMap") : null); Texture texture4 = (((Object)(object)source != (Object)null && source.HasProperty("_OcclusionMap")) ? source.GetTexture("_OcclusionMap") : null); SetMaterialTexture(val2, "_BaseColorMap", texture); SetMaterialTexture(val2, "_MainTex", texture); SetMaterialTexture(val2, "_NormalMap", texture2); SetMaterialTexture(val2, "_BumpMap", texture2); SetMaterialTexture(val2, "_MaskMap", texture3); SetMaterialTexture(val2, "_MetallicGlossMap", texture3); SetMaterialTexture(val2, "_OcclusionMap", texture4); ForceOpaqueMaterial(val2); return val2; } private static void ForceOpaqueMaterial(Material material) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)material == (Object)null)) { SetMaterialColor(material, "_BaseColor", Color.white); SetMaterialColor(material, "_Color", Color.white); SetMaterialFloat(material, "_SurfaceType", 0f); SetMaterialFloat(material, "_BlendMode", 0f); SetMaterialFloat(material, "_AlphaCutoffEnable", 0f); SetMaterialFloat(material, "_AlphaClip", 0f); SetMaterialFloat(material, "_Cutoff", 0f); SetMaterialFloat(material, "_ZWrite", 1f); SetMaterialFloat(material, "_SrcBlend", 1f); SetMaterialFloat(material, "_DstBlend", 0f); SetMaterialFloat(material, "_AlphaSrcBlend", 1f); SetMaterialFloat(material, "_AlphaDstBlend", 0f); SetMaterialFloat(material, "_Mode", 0f); SetMaterialFloat(material, "_DoubleSidedEnable", 1f); SetMaterialFloat(material, "_CullMode", 0f); SetMaterialFloat(material, "_Cull", 0f); material.SetOverrideTag("RenderType", "Opaque"); material.renderQueue = -1; material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHATESTENABLE_ON"); material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.DisableKeyword("_ALPHABLEND_ON"); } } private static void SetMaterialTexture(Material material, string propertyName, Texture texture) { if ((Object)(object)material != (Object)null && (Object)(object)texture != (Object)null && material.HasProperty(propertyName)) { material.SetTexture(propertyName, texture); } } private static void SetMaterialColor(Material material, string propertyName, Color color) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material != (Object)null && material.HasProperty(propertyName)) { material.SetColor(propertyName, color); } } private static void SetMaterialFloat(Material material, string propertyName, float value) { if ((Object)(object)material != (Object)null && material.HasProperty(propertyName)) { material.SetFloat(propertyName, value); } } private static void EnsureBehaviourStates(DreadweaverAI ai) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_007c: 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_008d: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown ((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[11] { new EnemyBehaviourState { name = "HiddenAcquireTarget" }, new EnemyBehaviourState { name = "HiddenFindWatch" }, new EnemyBehaviourState { name = "SightingVisible" }, new EnemyBehaviourState { name = "HiddenBetweenSightings" }, new EnemyBehaviourState { name = "HiddenPreAttackDelay" }, new EnemyBehaviourState { name = "AttackSetup" }, new EnemyBehaviourState { name = "CrawlAdvance" }, new EnemyBehaviourState { name = "Pursuit" }, new EnemyBehaviourState { name = "AttackVanishReposition" }, new EnemyBehaviourState { name = "Hit" }, new EnemyBehaviourState { name = "Dead" } }; ((EnemyAI)ai).currentBehaviourStateIndex = 0; ((EnemyAI)ai).previousBehaviourStateIndex = 0; ((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0]; } internal static void EnsureScanNode(GameObject prefab) { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { bool flag = val2.creatureScanID >= 0; bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0; bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal); bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal); if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4)) { val = val2; } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Dreadweaver] Found {componentsInChildren.Length} scan nodes; retiring every duplicate."); } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)(object)val) { RetireExtraScanNode(componentsInChildren[j], val, prefab); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.45f, 0f))); ((Object)((Component)val3).gameObject).name = "ScanNode"; TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)($"[Dreadweaver] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } } BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>(); } ((Collider)val4).enabled = true; ((Collider)val4).isTrigger = true; val4.center = Vector3.zero; val4.size = new Vector3(1.75f, 2.35f, 1.35f); if ((Object)(object)val == (Object)null) { val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); } val.headerText = "Dreadweaver"; val.subText = ""; val.maxRange = 25; val.minRange = 1; val.requiresLineOfSight = true; val.nodeType = 1; } private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)extra == (Object)null) { return; } Scene scene; if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject)) { scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)extra); } else { Object.DestroyImmediate((Object)(object)extra, true); } return; } GameObject gameObject = ((Component)extra).gameObject; gameObject.SetActive(false); Collider[] components = gameObject.GetComponents<Collider>(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)gameObject); } else { Object.DestroyImmediate((Object)(object)gameObject, true); } } private static void EnsureCollision(GameObject prefab, DreadweaverAI ai) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) CapsuleCollider obj = prefab.GetComponent<CapsuleCollider>() ?? prefab.AddComponent<CapsuleCollider>(); ((Collider)obj).isTrigger = false; obj.direction = 1; obj.center = new Vector3(0f, 1.18f, 0f); obj.radius = 0.86f; obj.height = 2.45f; Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1.1f, 0f)); TrySetTag(((Component)val).gameObject, "Enemy"); TrySetLayer(((Component)val).gameObject, "Enemies"); BoxCollider obj2 = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>(); ((Collider)obj2).isTrigger = true; obj2.center = Vector3.zero; obj2.size = new Vector3(2.05f, 2.25f, 1.9f); Rigidbody obj3 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>(); obj3.isKinematic = true; obj3.useGravity = false; obj3.detectCollisions = true; EnemyAICollisionDetect obj4 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>(); obj4.mainScript = (EnemyAI)(object)ai; obj4.alwaysAllowHitting = true; obj4.canCollideWithEnemies = true; obj4.onlyCollideWhenGrounded = false; } private static EnemyType CreateEnemyType(GameObject prefab) { EnemyType obj = ScriptableObject.CreateInstance<EnemyType>(); obj.enemyName = "Dreadweaver"; obj.enemyPrefab = prefab; obj.PowerLevel = ModConfig.PowerLevel.Value; obj.DiversityPowerLevel = 1; obj.MaxCount = ModConfig.MaxCount.Value; obj.canDie = true; obj.canBeStunned = true; obj.canBeDestroyed = true; obj.stunTimeMultiplier = 1f; obj.stunGameDifficultyMultiplier = 1f; obj.destroyOnDeath = false; obj.doorSpeedMultiplier = 1.1f; obj.isOutsideEnemy = false; obj.isDaytimeEnemy = false; obj.normalizedTimeInDayToLeave = 1f; obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f); obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.35f); obj.useNumberSpawnedFalloff = true; obj.disableAnimatorWhenFar = false; return obj; } private static AudioSource FindOrCreateAudioSource(Transform parent, string childName, float maxDistance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(parent, childName, Vector3.zero); AudioSource obj = ((Component)val).GetComponent<AudioSource>() ?? ((Component)val).gameObject.AddComponent<AudioSource>(); obj.playOnAwake = false; obj.spatialBlend = 1f; obj.rolloffMode = (AudioRolloffMode)1; obj.minDistance = 3f; obj.maxDistance = maxDistance; return obj; } private static void AssignDreadweaverAudio(DreadweaverAI ai) { if ((Object)(object)ai == (Object)null || (Object)(object)ModAssets == (Object)null) { return; } string[] allAssetNames = ModAssets.GetAllAssetNames(); ai.spotClips = LoadAudioClipSet(allAssetNames, "Spot_01", "Spot_02", "Spot_03"); ai.footstepClips = LoadAudioClipSet(allAssetNames, "Footstep Metal Running 1_01", "Footstep Metal Running 1_02", "Footstep Metal Running 1_03", "Footstep Metal Running 1_04", "Footstep Metal Running 1_05", "Footstep Metal Running 1_06", "Footstep Metal Running 1_07", "Footstep Metal Running 1_08"); ai.initialAttackClip = LoadAudioClip(allAssetNames, "Jumpscare_InitialAttack_01"); ai.spottedClip = ((ai.spotClips.Length != 0) ? ai.spotClips[0] : null); ai.attackClip = ai.initialAttackClip; if (ai.spotClips.Length != 3 || ai.footstepClips.Length != 8 || (Object)(object)ai.initialAttackClip == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)($"[DreadweaverAudio] Incomplete bundle audio: spots={ai.spotClips.Length}/3, " + $"footsteps={ai.footstepClips.Length}/8, initialAttack={(((Object)(object)ai.initialAttackClip != (Object)null) ? 1 : 0)}/1.")); } } else { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[DreadweaverAudio] Loaded 3 stalking stingers, 8 footsteps, and 1 initial-attack jumpscare."); } } } private static AudioClip[] LoadAudioClipSet(string[] bundleAssets, params string[] clipNames) { List<AudioClip> list = new List<AudioClip>(clipNames.Length); for (int i = 0; i < clipNames.Length; i++) { AudioClip val = LoadAudioClip(bundleAssets, clipNames[i]); if ((Object)(object)val != (Object)null) { list.Add(val); } } return list.ToArray(); } private static AudioClip LoadAudioClip(string[] bundleAssets, string clipName) { foreach (string text in bundleAssets) { if (string.Equals(Path.GetFileNameWithoutExtension(text), clipName, StringComparison.OrdinalIgnoreCase)) { AudioClip val = ModAssets.LoadAsset<AudioClip>(text); if ((Object)(object)val != (Object)null) { return val; } } } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[DreadweaverAudio] Missing AudioClip '" + clipName + "' in dreadweaver.bundle.")); } return null; } private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { val.localPosition = localPosition; return val; } val = new GameObject(name).transform; val.SetParent(parent, false); val.localPosition = localPosition; return val; } private static void AssignUniqueNetworkHash(GameObject prefab) { try { NetworkObject val = prefab.GetComponent<NetworkObject>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NetworkObject>(); } uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.dreadweaver.SK_Dreadweaver")), 0); PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(val, num); return; } FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (fieldInfo != null) { fieldInfo.SetValue(val, num); } } catch (Exception ex) { Log.LogWarning((object)("Could not assign NetworkObject hash for Dreadweaver: " + ex.Message)); } } private static void DumpBundleAssets() { if (!((Object)(object)ModAssets == (Object)null)) { string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { Log.LogError((object)(" - " + text)); } } } private static void TrySetTag(GameObject gameObject, string tag) { try { gameObject.tag = tag; } catch { } } private static void TrySetLayer(GameObject gameObject, string layerName) { if ((Object)(object)gameObject == (Object)null) { return; } int num = LayerMask.NameToLayer(layerName); if (num < 0) { num = ResolveLayerFallback(layerName); } if (num >= 0 && num <= 31) { gameObject.layer = num; return; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Dreadweaver] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}."); } } private static int ResolveLayerFallback(string layerName) { if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase)) { return 22; } if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase)) { return 19; } return -1; } private static void EnsureHierarchyActive(Transform child, Transform stopAt) { Transform val = child; while ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); if (!((Object)(object)val == (Object)(object)stopAt)) { val = val.parent; continue; } break; } } } internal static class PluginInfo { public const string PLUGIN_GUID = "y4ngz.lethalcompany.dreadweaver"; public const string PLUGIN_NAME = "Y4NGZ Dreadweaver"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace Y4NGZDreadweaver.AI { public sealed class DreadweaverAI : EnemyAI { private struct AttackProfile { public readonly int AnimationCode; public readonly float StrikeTimeSeconds; public readonly float RecoverySeconds; public readonly float RangeMultiplier; public readonly float ArcMultiplier; public readonly float SelectionWeight; public AttackProfile(int animationCode, float strikeTimeSeconds, float recoverySeconds, float rangeMultiplier, float arcMultiplier, float selectionWeight) { AnimationCode = animationCode; StrikeTimeSeconds = strikeTimeSeconds; RecoverySeconds = recoverySeconds; RangeMultiplier = rangeMultiplier; ArcMultiplier = arcMultiplier; SelectionWeight = selectionWeight; } } private struct FlickerLight { public Light Light; public bool Enabled; public float Intensity; } private enum SightingStage { Long, Medium, Short } private enum SightingPresentation { HallwayEnd, CornerReveal, DeadEndBehind } private enum AttackEngageMode { WalkThenRun, RunImmediately, CrawlThenRun } private sealed class CamoShellRenderer { public Renderer Renderer; public Material[] Materials; } private sealed class LightFlickerState { public Light Light; public bool Enabled; public float Intensity; } public const int StateHiddenAcquireTarget = 0; public const int StateHiddenFindWatch = 1; public const int StateSightingVisible = 2; public const int StateHiddenBetweenSightings = 3; public const int StateHiddenPreAttackDelay = 4; public const int StateAttackSetup = 5; public const int StateCrawlAdvance = 6; public const int StatePursuit = 7; public const int StateAttackVanishReposition = 8; public const int StateHit = 9; public const int StateDead = 10; private const ulong NoTargetClientId = ulong.MaxValue; private const float EyeHeight = 1.65f; private const float RevealUnseenHalfAngle = 35f; private const float DirectRevealHalfAngle = 12f; private const float AttackRevealUnseenHalfAngle = 45f; private const float ShortCornerMaxPathDistance = 16f; private const float ShortApproachVanishDistance = 2.4f; private const float DirectRevealDelaySeconds = 0.75f; private const float ReengageCamoPreviewSeconds = 0.72f; private const int MaxRapidReengagements = 3; private const float WatchSearchRelaxSeconds = 5f; private const float LongSearchRelaxSeconds = 8f; private const float RevealSearchTimeoutSeconds = 12f; private const float SightingSeenCloseThreshold = 1.1f; private const float WatchLosGraceSeconds = 2.5f; private const float MinDistanceFromLastVanish = 8f; private const float VisibilityResyncInterval = 6f; private const float PresentationSyncInterval = 0.08f; private const float PresentationYawThreshold = 1.25f; private const float RevealFacingLockSeconds = 0.8f; private const float RevealReadableFraction = 0.72f; private const float VanishColliderDisableFraction = 0.6f; private const float ReplicatedFacingTurnSpeed = 540f; private const float AnimationCrossFadeSeconds = 0.18f; private const float SightingMinimumStareSeconds = 0.85f; private const float UnseenPresentationTimeoutSeconds = 6f; private const float CornerPresentationMaxPathDistance = 23f; private const float DeadEndBehindMaxPathDistance = 26f; private const float RequiredSightingIntervalMinSeconds = 45f; private const float RequiredSightingIntervalFallbackMaxSeconds = 65f; private const float RetrySightingIntervalMinSeconds = 15f; private const float RetrySightingIntervalFallbackMaxSeconds = 30f; private const float AttackReadyDelayMinSeconds = 15f; private const float AttackReadyDelayMaxSeconds = 30f; private const float ExitDodgeSeconds = 0.42f; private const float ExitDodgeVisibleSeconds = 0.16f; private const float ExitDodgeCamoSeconds = 0.24f; private const float LongSightingDodgeChance = 0.12f; private const float MediumSightingDodgeChance = 0.06f; private const float ExitWalkBackSeconds = 0.82f; private const float ExitWalkBackDistance = 4.75f; private const float ExitDodgeDistance = 6.5f; private const float PlacementClearanceRadius = 0.82f; private const float PlacementClearanceHeight = 2.45f; private const float DefaultAttackDamageDelay = 0.48f; private const float AttackStuckRecoverySeconds = 7f; private const float AttackSoftPathRepairSeconds = 1.6f; private const float AttackPathRepairCooldownSeconds = 1.4f; private const float AttackProgressCheckIntervalSeconds = 0.35f; private const float AttackProgressMinDistance = 0.18f; private const float AttackWalkIntroSeconds = 3f; private const float StalkLightFlickerInitialMinSeconds = 12f; private const float StalkLightFlickerInitialMaxSeconds = 24f; private const float StalkLightFlickerDurationSeconds = 1.15f; private const int StalkLightFlickerBudgetMin = 2; private const int StalkLightFlickerBudgetMax = 3; private const int MaxStalkFlickerLights = 10; private const int MaxStalkFlickerAnimators = 8; private const int MaxPoweredLightSightingCandidates = 16; private const float PoweredLightCandidateSearchPadding = 8f; private const float PoweredLightCandidateSampleRadius = 4.5f; private const float PoweredLightAffinityRadius = 9f; private const float PoweredLightAffinityMaxScore = 4.75f; private const float StalkDoorSlamInitialMinSeconds = 24f; private const float StalkDoorSlamInitialMaxSeconds = 40f; private const float DoorSlamOpenSeconds = 0.2f; private const float DoorSlamClosedSeconds = 0.16f; private const int DoorSlamCycles = 3; private const float DamageStunFreezeSeconds = 1f; private const float FootstepPhaseOffset = 0.08f; private const int FootstepsPerLocomotionCycle = 2; private const string CamoShellName = "_DreadweaverCamoShell"; private const int AnimIdle1 = 0; private const int AnimIdle2 = 1; private const int AnimIdle3 = 2; private const int AnimIdle4 = 3; private const int AnimWalk1 = 4; private const int AnimWalk2 = 5; private const int AnimWalkBack = 6; private const int AnimWalkLeft = 7; private const int AnimWalkLeft2 = 8; private const int AnimWalkRight = 9; private const int AnimRun = 10; private const int AnimCrawl = 11; private const int AnimDodgeLeft = 12; private const int AnimDodgeRight = 13; private const int AnimDodgeForward = 14; private const int AnimDodgeBackward = 15; private const int AnimTurnLeft = 16; private const int AnimTurnRight = 17; private const int AnimWeaveFear = 18; private const int AnimAttackBase = 20; private const int AnimTakingDamage1 = 40; private const int AnimTakingDamage2 = 41; private const int AnimDeath1 = 50; private const int AnimDeath2 = 51; private static readonly AttackProfile[] AttackProfiles = new AttackProfile[9] { new AttackProfile(21, 0.37f, 0.83f, 0.92f, 0.92f, 1.15f), new AttackProfile(22, 0.48f, 1.5f, 1f, 1f, 1f), new AttackProfile(23, 0.43f, 1.2f, 0.96f, 1.06f, 1.1f), new AttackProfile(24, 0.53f, 1.83f, 1f, 1f, 1f), new AttackProfile(25, 0.53f, 1.83f, 1f, 1f, 1f), new AttackProfile(26, 0.65f, 2.67f, 1.08f, 0.9f, 0.7f), new AttackProfile(27, 0.6f, 2.43f, 1.05f, 0.95f, 0.8f), new AttackProfile(28, 0.58f, 2.43f, 1.05f, 1f, 0.8f), new AttackProfile(29, 0.55f, 2.13f, 1f, 1.08f, 0.9f) }; [Header("Dreadweaver anchors")] public Transform attackOrigin; public Animator visualAnimator; [Header("Dreadweaver search")] public AISearchRoutine attackRecoverySearch = new AISearchRoutine(); [Header("Dreadweaver audio")] public AudioClip[] spotClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip[] footstepClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip initialAttackClip; public AudioClip spottedClip; public AudioClip vanishClip; public AudioClip decloakClip; public AudioClip attackClip; public AudioClip hitClip; public AudioClip deathClip; private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[48]; private readonly Collider[] _placementColliders = (Collider[])(object)new Collider[24]; private readonly List<CamoShellRenderer> _camoShells = new List<CamoShellRenderer>(); private readonly List<LightFlickerState> _activeLightFlickerStates = new List<LightFlickerState>(); private readonly NetworkVariable<int> _networkState = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<ulong> _networkTargetClientId = new NetworkVariable<ulong>(ulong.MaxValue, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> _networkStage = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> _networkPresentation = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> _networkAnimationCode = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkAnimationNormalizedTime = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<bool> _networkVisible = new NetworkVariable<bool>(true, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> _networkVisibilitySequence = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkFacingYaw = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> _networkRevealSequence = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<Vector3> _networkRevealPosition = new NetworkVariable<Vector3>(Vector3.zero, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkFacingLockDuration = new NetworkVariable<float>(0.8f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkPresentationReadyDelay = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<Vector3> _networkModelScale = new NetworkVariable<Vector3>(Vector3.one, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkMovementSpeed = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkLocomotionPlayback = new NetworkVariable<float>(1f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<bool> _networkSpotlightActive = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkSpotlightIntensity = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkSpotlightAngle = new NetworkVariable<float>(42f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkSpotlightRange = new NetworkVariable<float>(14f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkSpotlightHeight = new NetworkVariable<float>(5f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<Vector3> _networkSpotlightColor = new NetworkVariable<Vector3>(Vector3.one, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private Renderer[] _bodyRenderers = (Renderer[])(object)new Renderer[0]; private bool[] _bodyRendererDefaults = new bool[0]; private Collider[] _bodyColliders = (Collider[])(object)new Collider[0]; private bool[] _bodyColliderDefaults = new bool[0]; private bool _visualsCaptured; private bool _camoShellsCreated; private bool _usingBundledCamoMaterial; private bool _loggedCamoFallback; private bool _logicalVisible = true; private bool _renderersShown = true; private int _visSeq; private int _appliedVisSeq = -1; private Coroutine _flickerRoutine; private Coroutine _camoPreviewRoutine; private Coroutine _localLightFlickerRoutine; private float _nextVisibilityResyncTime; private float _presentationReadyAt; private float _nextPresentationSyncTime; private float _lastPublishedFacingYaw; private float _lastPublishedMovementSpeed = -1f; private float _lastPublishedLocomotionPlayback = -1f; private int _clientAppliedRevealSequence; private float _clientFacingLockUntil; private SightingStage _stage; private SightingPresentation _pendingPresentation; private ulong _targetClientId = ulong.MaxValue; private ulong _lastKilledTargetClientId = ulong.MaxValue; private ulong _lastHitByClientId = ulong.MaxValue; private float _phaseEnteredAt; private float _nextActionTime; private bool _hasPendingWatchPosition; private float _watchRevealDeadline; private float _sightingFirstSeenAt = -1f; private float _sightingSeenDistance; private float _losLostSince = -1f; private Vector3 _lastVanishPosition; private bool _hasLastVanishPosition; private Coroutine _sightingExitRoutine; private bool _isEndingSighting; private Coroutine _stalkDoorSlamRoutine; private DoorLock _stalkDoorSlamDoor; private float _nextStalkLightFlickerTime; private float _nextStalkDoorSlamTime; private int _remainingStalkLightFlickers; private Vector3 _lastAttackRevealPosition; private bool _hasLastAttackRevealPosition; private AttackEngageMode _attackEngageMode = AttackEngageMode.CrawlThenRun; private int _attackAdvanceAnimation = 11; private float _attackAdvanceEndTime; private float _nextAttackTime; private float _lostSightTimer; private float _repositionRelaxAt; private Vector3 _lastKnownAttackTargetPosition; private Vector3 _lastAttackProgressPosition; private float _lastAttackProgressDistance; private float _attackStuckTimer; private float _nextAttackProgressCheckTime; private float _nextAttackPathRepairTime; private Coroutine _attackRoutine; private Coroutine _reengageCueRoutine; private bool _isAttackAnimating; private bool _isHitStaggering; private AttackProfile _activeAttackProfile; private bool _resolvePostTargetDownAfterSwing; private float _attackMovementReadyAt; private bool _pursuitSpotlightProfileApplied; private int _rapidReengagementCount; private float _nextLocalFearTime; private float _lastLocalMovementAnimTime; private float _animationLockUntil; private float _damageStunUntil; private float _preDamageStunAnimatorSpeed = 1f; private string _currentAnimationName; private int _currentAnimationCode = int.MinValue; private float _currentAnimationNormalizedTime; private bool _damageStunFrozen; private bool _locomotionMoving; private int _footstepAnimatorStateHash; private int _footstepTick = int.MinValue; private float _lastFootstepNormalizedTime; private int _lastFootstepClipIndex = -1; private bool _hasPlayedInitialAttackJumpscare; private static AudioClip _directionalCamoCue; private DreadweaverSpotlight _spotlight; private bool _spotlightActive; private float _spotlightIntensity; private float _spotlightAngle = 42f; private float _spotlightRange = 14f; private float _spotlightHeight = 5f; private Vector3 _spotlightColor = Vector3.one; private Coroutine _flashlightHarassRoutine; private readonly List<FlickerLight> _flashlightHarassLights = new List<FlickerLight>(); private float _nextFlashlightHarassTime; private float StalkMoveSpeed => Mathf.Clamp(Plugin.ModConfig?.StalkMoveSpeed.Value ?? 1.5f, 0.5f, 4f); private float CrawlSpeed => Mathf.Clamp(Plugin.ModConfig?.CrawlSpeed.Value ?? 2.1f, 0.8f, 4f); private float AttackWalkSpeed => Mathf.Clamp(Mathf.Max(StalkMoveSpeed, CrawlSpeed * 0.85f), 1.25f, 3.2f); private float AttackSpeed => Mathf.Clamp(Plugin.ModConfig?.AttackSpeed.Value ?? 5.15f, 2f, 9f); private float TurnSpeed => 420f; private float Acceleration => 18f; private float SpotHalfAngle => 25f; private float CreatureSightRange => 60f; private float SightingIntervalMin => Mathf.Clamp(Plugin.ModConfig?.SightingIntervalMinSeconds.Value ?? 45f, 8f, 120f); private float SightingIntervalMax => ResolveIntervalMax(Plugin.ModConfig?.SightingIntervalMaxSeconds.Value ?? 65f, SightingIntervalMin, 65f, 150f); private float SightingRetryMin => 15f; private float SightingRetryMax => 30f; private float SightingTimeoutSeconds => 12f; private float StalkLightFlickerRadius => 18f; private float StalkLightFlickerIntervalMin => 40f; private float StalkLightFlickerIntervalMax => 70f; private float StalkDoorSlamRadius => 14f; private float StalkDoorSlamIntervalMin => 35f; private float StalkDoorSlamIntervalMax => 70f; private float AttackDelayMin => Mathf.Clamp(Plugin.ModConfig?.AttackDelayMinSeconds.Value ?? 15f, 5f, 60f); private float AttackDelayMax => Mathf.Max(AttackDelayMin, Mathf.Clamp(Plugin.ModConfig?.AttackDelayMaxSeconds.Value ?? 30f, AttackDelayMin, 90f)); private float AttackRevealMin => 8f; private float AttackRevealMax => 16f; private float CrawlAdvanceSeconds => 3f; private float AttackRange => 2.35f; private float AttackCooldown => Mathf.Clamp(Plugin.ModConfig?.AttackCooldown.Value ?? 1.8f, 0.5f, 6f); private float AttackDamageDelay => 0.48f; private float AttackHitHalfAngle => 60f; private int AttackDamage => Mathf.Clamp(Plugin.ModConfig?.AttackDamage.Value ?? 40, 1, 100); private float AttackLoseDistance => 48f; private float AttackLostSightGraceSeconds => 12f; private float PursuitRepositionCooldownMin => 2f; private float PursuitRepositionCooldownMax => 5f; private float PursuitRepositionMinDistance => 10f; private float ChainAttackRadius => 13f; private float VanishFlickerSeconds => 0.65f; private float DecloakFlickerSeconds => 0.55f; private bool DebugLogs => Plugin.ModConfig?.DebugLogs.Value ?? false; private bool MatchAnimationToMovement => true; private float AuthoredWalkSpeed => 1.9f; private float AuthoredCrawlSpeed => 1.9f; private float AuthoredRunSpeed => 3.6f; private bool CreatureSpotlightEnabled => Plugin.ModConfig?.CreatureSpotlightEnabled.Value ?? true; private bool FlashlightHarassEnabled => Plugin.ModConfig?.FlashlightHarassEnabled.Value ?? true; private bool CanSendRpc { get { if ((Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null) { return ((NetworkBehaviour)this).NetworkObject.IsSpawned; } return false; } } private static float ResolveIntervalMax(float configuredValue, float min, float fallbackMax, float hardMax) { if (configuredValue < min + 0.1f) { return Mathf.Max(min + 1f, fallbackMax); } return Mathf.Max(min, Mathf.Clamp(configuredValue, min, hardMax)); } public override void Awake() { try { ((EnemyAI)this).Awake(); ResolveReferences(); ConfigureAttackSearchDefaults(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[DreadweaverAI] Awake failed: {arg}"); } } } public override void OnNetworkSpawn() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) ((NetworkBehaviour)this).OnNetworkSpawn(); _clientAppliedRevealSequence = -1; if (((NetworkBehaviour)this).IsServer) { _networkModelScale.Value = ((Component)this).transform.localScale; } else { ApplyNetworkSnapshotLocal(force: true); } } public override void Start() { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Start(); Plugin.EnsureScanNode(((Component)this).gameObject); ResolveReferences(); ConfigureAttackSearchDefaults(); CaptureVisuals(); base.enemyHP = Plugin.ModConfig?.Health.Value ?? 5; ConfigureAgent(StalkMoveSpeed); StopAgent(); SetStateLocal(0); PlayAnimationLocal(0, 0.18f, 0f); _hasPlayedInitialAttackJumpscare = false; ResetFootstepTracking(); if (((NetworkBehaviour)this).IsServer) { RepairFacilityAINodes(); PublishAuthoritativePresentationServer(force: true); VanishServer(playCue: false); _nextActionTime = Time.time + Random.Range(2f, 4f); } else if (((NetworkBehaviour)this).IsSpawned) { ApplyNetworkSnapshotLocal(force: true); } if (DebugLogs) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[DreadweaverAI] Spawned #{base.thisEnemyIndex} at {((Component)this).transform.position}."); } } } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"[DreadweaverAI] Start failed: {arg}"); } } } public override void Update() { try { ((EnemyAI)this).Update(); if (base.isEnemyDead) { return; } ResolveReferences(); ApplyNetworkSnapshotLocal(); ApplyReplicatedFacingLocal(); if (ApplyDamageStunFreeze()) { return; } TickLocalFear(); TickAnimatorPlaybackSpeed(); TickLocalFootsteps(); if (!((NetworkBehaviour)this).IsServer || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead) { return; } if (Time.time >= _nextVisibilityResyncTime) { _nextVisibilityResyncTime = Time.time + 6f; if (CanSendRpc) { ResyncVisibilityClientRpc(_logicalVisible, _visSeq); } } if (!_isHitStaggering) { TickStalkingEnvironmentScares(); switch (base.currentBehaviourStateIndex) { case 0: TickHiddenAcquireTarget(); break; case 1: TickHiddenFindWatch(); break; case 2: TickSightingVisible(Time.deltaTime); break; case 3: TickHiddenWait(1); break; case 4: TickHiddenWait(5); break; case 5: TickAttackSetup(); break; case 6: TickCrawlAdvance(Time.deltaTime); break; case 7: TickPursuit(Time.deltaTime); break; case 8: TickAttackVanishReposition(); break; } TickAuthoritativeLocomotionAnimation(); PublishAuthoritativePresentationServer(); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[DreadweaverAI] Update failed: {arg}"); } } } public override void DoAIInterval() { try { ((EnemyAI)this).DoAIInterval(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[DreadweaverAI] DoAIInterval failed: {arg}"); } } } public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { try { ((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID); if (base.isEnemyDead) { return; } BeginDamageStunFreeze(); if (!((NetworkBehaviour)this).IsServer) { return; } base.enemyHP -= Mathf.Max(1, force); if (base.enemyHP <= 0) { DieFromDamage(); return; } _lastHitByClientId = (((Object)(object)playerWhoHit != (Object)null) ? playerWhoHit.actualClientId : ulong.MaxValue); if (!_isHitStaggering) { ((MonoBehaviour)this).StartCoroutine(HitStaggerRoutine()); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[DreadweaverAI] HitEnemy failed: {arg}"); } } } public override void KillEnemy(bool destroy = false) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) try { StopManagedRoutines(); if (_flickerRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_flickerRoutine); _flickerRoutine = null; } if (_camoPreviewRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_camoPreviewRoutine); _camoPreviewRoutine = null; } StopLocalLightFlicker(); StopFlashlightHarass(); _spotlightActive = false; ApplyCreatureSpotlight(active: false, 0f, 0f, 0f, 0f, Vector3.zero); _logicalVisible = true; _isEndingSighting = false; SetCollidersEnabled(enabled: true); SetCamoShellsShown(shown: false); SetRenderersShown(shown: true); ClearDamageStunFreeze(); StopAgent(); ((EnemyAI)this).KillEnemy(destroy); base.isEnemyDead = true; SetStateLocal(10); PlayAnimationLocal((Random.value < 0.5f) ? 50 : 51, 0.08f, 0f); if ((Object)(object)deathClip != (Object)null && (Object)(object)base.creatureVoice != (Object)null) { base.creatureVoice.PlayOneShot(deathClip, 1f); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[DreadweaverAI] KillEnemy failed: {arg}"); } } } private void TickHiddenAcquireTarget() { if (!(Time.time < _nextActionTime)) { _nextActionTime = Time.time + 1.5f; PlayerControllerB val = ChooseFixationTarget(); if (!((Object)(object)val == (Object)null)) { SetFixationTarget(val, "new stalking target"); _stage = SightingStage.Long; EnterPhase(1); } } } private void TickHiddenWait(int nextState) { if ((Object)(object)RequireStalkTarget() == (Object)null) { RestartStalkCycle("target lost while hidden"); } else if (!(Time.time < _nextActionTime)) { EnterPhase(nextState); } } private void TickHiddenFindWatch() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = RequireStalkTarget(); if ((Object)(object)val == (Object)null) { RestartStalkCycle("target lost while finding watch position"); } else if (!_hasPendingWatchPosition) { if (Time.time < _nextActionTime) { return; } _nextActionTime = Time.time + 0.65f; if (!TryFindSightingPosition(val, _stage, out var position)) { if (Time.time - _phaseEnteredAt > 12f) { RestartStalkCycle("no stalking presentation found"); } } else { TeleportFacing(position, GetPlayerFocusPoint(val)); _hasPendingWatchPosition = true; _watchRevealDeadline = Time.time + 0.75f; } } else if (!ValidateWatchPosition(val, _stage)) { _hasPendingWatchPosition = false; } else { if (AnyPlayerWouldSeePosition(GetCreatureFocusPoint(), 12f) && Time.time < _watchRevealDeadline) { return; } TeleportFacing(((Component)this).transform.position, GetPlayerFocusPoint(val)); RevealServer(Mathf.Max(0.08f, DecloakFlickerSeconds * 0.75f)); PlayStalkingRevealSoundServer(val); PlayAnimationServer(ChooseSightingIntroAnimation(), 0.2f, GetSightingIntroNormalizedTime()); EnterPhase(2); if (DebugLogs) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[DreadweaverAI] {_stage}/{_pendingPresentation} sighting revealed at {((Component)this).transform.position}."); } } } } private bool ValidateWatchPosition(PlayerControllerB target, SightingStage stage) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) GetStageParameters(stage, out var min, out var max, out var _, out var panic); float num = Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position); float radius = ((_pendingPresentation == SightingPresentation.HallwayEnd && stage != SightingStage.Short) ? panic : Mathf.Max(2.6f, 2.4f)); if (TooCloseToAnyPlayer(((Component)this).transform.position, radius)) { return false; } if (_pendingPresentation == SightingPresentation.CornerReveal) { if (num <= Mathf.Max(max + 10f, 13f)) { return HasShortCompletePath(((Component)this).transform.position, ((Component)target).transform.position, 23f); } return false; } if (_pendingPresentation == SightingPresentation.DeadEndBehind) { if (num >= 3.5f && num <= Mathf.Max(max + 12f, 18f)) { return HasShortCompletePath(((Component)this).transform.position, ((Component)target).transform.position, 26f); } return false; } if (num < min * 0.6f || num > max * 1.35f) { return false; } return HasClearLineOfSight(GetCreatureFocusPoint(), GetPlayerFocusPoint(target), ((Component)target).transform); } private void TickSightingVisible(float deltaTime) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0197: 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) PlayerControllerB val = RequireStalkTarget(); if ((Object)(object)val == (Object)null) { RestartStalkCycle("target lost while visible"); return; } StopAgent(); FaceTargetForStalking(val); if (_isEndingSighting) { return; } GetStageParameters(_stage, out var min, out var max, out var hold, out var panic); hold = Mathf.Max(0.85f, hold); float num
Y4NGZFlyingTV.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.IO.Compression; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using Unity.Netcode; using Unity.Netcode.Components; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.Video; using Y4NGZFlyingTV.NetcodePatcher; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZFlyingTV")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZFlyingTV")] [assembly: AssemblyTitle("Y4NGZFlyingTV")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZFlyingTV { public sealed class FlyingTVAi : EnemyAI { private struct ScreenMaterialTarget { public Renderer Renderer; public int MaterialIndex; public ScreenMaterialTarget(Renderer renderer, int materialIndex) { Renderer = renderer; MaterialIndex = materialIndex; } } private struct PlayerMovementSample { public float Timestamp; public Vector3 Position; public PlayerMovementSample(float timestamp, Vector3 position) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Timestamp = timestamp; Position = position; } } private const int StateRoaming = 0; private const int StateApproach = 1; private const int StateChecking = 2; private const int StateVideo = 3; private const int StateAttack = 4; private const int StateLeave = 5; private const int StateDead = 6; private const float StopSampleIntervalSeconds = 0.1f; private const float FacingAngleThreshold = 60f; private const float AttackDamage = 25f; private const float AttackCooldown = 1.4f; private const float AttackRange = 2.2f; private const int FlyingTVHealth = 6; private const float VoiceToVideoGapSeconds = 0.15f; private const float PlaybackStartLeadSeconds = 0.35f; private const float VideoNoncomplianceGraceSeconds = 5f; private const float YoutubeResolutionTimeoutSeconds = 90f; private const float VideoPrepareTimeoutSeconds = 20f; private const int StaticTextureWidth = 256; private const int StaticTextureHeight = 144; private const float StaticFrameIntervalSeconds = 1f / 12f; private const float RoamSearchWidth = 70f; private const float RoamSearchPrecision = 4f; private const float RoamSearchRetargetMinSeconds = 3.5f; private const float RoamSearchRetargetMaxSeconds = 7.5f; private const float HoverBobSpeed = 1.2f; private const float HoverBobAmplitude = 0.16f; private const float CeilingClearance = 0.6f; private const float NavMeshRepairIntervalSeconds = 1f; private const float DamageSlowPerHit = 0.09f; private const float MinDamageSpeedMultiplier = 0.55f; private const float DamageWobblePerHit = 0.2f; private const float MaxDamageWobble = 1.1f; private const float DeathExplosionKnockbackRadius = 10f; private const float DeathExplosionMaxKnockback = 34f; private const float DeathExplosionMinKnockback = 12f; private const float DeathDespawnDelaySeconds = 0.35f; private const float DamageStunFreezeSeconds = 1f; private const string EmbeddedScreenSurfaceName = "FlyingTVEmbeddedScreenSurface"; internal const float BodyColliderRadius = 0.65f; internal const float BodyColliderHeight = 1.35f; private static readonly int MovingHash = Animator.StringToHash("Moving"); private static readonly string[] VideoExtensions = new string[6] { ".mp4", ".webm", ".mov", ".m4v", ".ogv", ".avi" }; public Transform visualRoot; public Renderer screenRenderer; public AudioSource videoAudioSource; public AudioClip greetingsClip; public AudioClip noncomplianceClip; public AudioClip complianceClip; public AudioClip propellerLoopClip; public AISearchRoutine facilitySearch = new AISearchRoutine(); private AudioSource _voiceSource; private AudioSource _propellerSource; private Coroutine _checkRoutine; private Coroutine _videoRoutine; private Vector3 _leaveDestination; private Vector3 _lastKnownTargetPosition; private Vector3 _videoHoldPosition; private Quaternion _videoHoldRotation; private float _leaveDeadline; private float _leaveMovementStartTime; private float _nextAttackTime; private float _serverVideoEndTime; private float _serverNoncomplianceEnableTime = float.PositiveInfinity; private float _lastVoiceStartTime; private float _nextRoamSearchRetargetTime; private float _roamAngle; private int _damageHitCount; private bool _checkActive; private bool _videoActive; private bool _selectedVideoPlaying; private bool _destroying; private bool _leaveMovementStarted; private bool _deathExplosionTriggered; private Coroutine _deathDespawnRoutine; private string _videoName = string.Empty; private float _forcedDurationSeconds; private Vector3 _lastPosition; private Vector3 _visualBaseLocalPosition; private bool _hasVisualBaseLocalPosition; private float _hoverHeight; private float _nextNavMeshRepairTime; private float _attackLostAggroSince = -1f; private float _videoNoncomplianceSince = -1f; private float _ignoreDetectionUntil; private float _damageStunUntil; private float _preDamageStunAnimatorSpeed = 1f; private bool _hasMovingParameter; private bool _damageStunFrozen; private AudioClip _lastVoiceClip; private CapsuleCollider _bodyCollider; private Rigidbody _bodyRigidbody; private readonly List<PlayerMovementSample> _playerMovementSamples = new List<PlayerMovementSample>(); private readonly RaycastHit[] _movementHits = (RaycastHit[])(object)new RaycastHit[8]; private Material _screenMaterial; private Material _screenBlankMaterial; private int _screenMaterialIndex = -1; private GameObject _screenOverlayObject; private Renderer _screenOverlayRenderer; private readonly List<ScreenMaterialTarget> _screenMaterialTargets = new List<ScreenMaterialTarget>(); private bool _screenTargetsLogged; private bool _missingScreenTargetLogged; private VideoPlayer _videoPlayer; private Coroutine _playbackRoutine; private RenderTexture _renderTexture; private Texture2D _fallbackTexture; private Texture2D _staticTexture; private Color32[] _staticPixels; private bool _staticPlaying; private float _nextStaticFrameTime; private uint _staticNoiseState; private int _staticFrameIndex; private float FollowDistance => Mathf.Max(1f, FlyingTVConfig.FollowDistance.Value); private float FollowHeight => 2.4f; private float PlayerStopWindowSeconds => Mathf.Max(0.1f, 1f); private float PlayerStopThreshold => 0.35f; private float VideoNoncomplianceDistance => Mathf.Max(FollowDistance, FlyingTVConfig.VideoNoncomplianceDistance.Value); private float TurnAwayAngleThreshold => Mathf.Clamp(FlyingTVConfig.TurnAwayAngleThreshold.Value, 10f, 89f); private float VideoNoncomplianceSustainSeconds => Mathf.Max(0f, FlyingTVConfig.VideoNoncomplianceSustainSeconds.Value); private float ApproachSpeed => Mathf.Max(1f, FlyingTVConfig.ApproachSpeed.Value); private float LeaveSpeed => 7f; private float ChaseLoseAggroDistance => 28f; private float ChaseLoseAggroSeconds => 4f; private float ApproachLoseAggroDistance => Mathf.Max(FlyingTVConfig.DetectionRange.Value + 5f, 45f); private float ApproachLoseAggroSeconds => 8f; private float ConfiguredHoverHeight => 1.9f; private float RoamSpeed => Mathf.Max(0.1f, FlyingTVConfig.RoamSpeed.Value); private float ChaseSpeed => Mathf.Max(0.1f, FlyingTVConfig.ChaseSpeed.Value); private float DamageSpeedMultiplier => Mathf.Max(0.55f, 1f - (float)_damageHitCount * 0.09f); private float DamageWobbleAmount => Mathf.Min(1.1f, (float)_damageHitCount * 0.2f); private bool AgentReady { get { if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled) { return base.agent.isOnNavMesh; } return false; } } public override void OnNetworkSpawn() { //IL_0102: Unknown result type (might be due to invalid IL or missing references) ((NetworkBehaviour)this).OnNetworkSpawn(); EnsureNavigationAgent(); ResolveReferences(); EnsureBehaviourStates(); ConfigureSearchDefaults(); _voiceSource = EnsureAudioSource(base.creatureVoice, "FlyingTVVoice", 34f); base.creatureVoice = _voiceSource; _propellerSource = EnsureAudioSource(_propellerSource, "FlyingTVPropellerLoop", 38f); EnsurePropellerLoopPlaying(); StartStaticPlayback(); _roamAngle = Random.Range(0f, 360f); _hoverHeight = ConfiguredHoverHeight; if (((NetworkBehaviour)this).IsServer) { _videoName = FlyingTVConfig.ResolveVideoSource(); _forcedDurationSeconds = ((FlyingTVConfig.PlaybackDurationSeconds != null) ? Mathf.Max(0f, FlyingTVConfig.PlaybackDurationSeconds.Value) : 0f); PrefetchYoutubePlaybackClientRpc(_videoName); SnapToNavMesh(logAlways: true); base.currentBehaviourStateIndex = 0; ((EnemyAI)this).SwitchToBehaviourState(0); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = true; StartFacilitySearch(((Component)this).transform.position, 70f); } } public override void Start() { //IL_0037: 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) ((EnemyAI)this).Start(); EnsureNavigationAgent(); Plugin.EnsureScanNode(((Component)this).gameObject); EnsureEyeTransform(); EnsureCollisionBody(); ConfigureSearchDefaults(); base.enemyHP = 6; _lastPosition = ((Component)this).transform.position; } public override void FinishedCurrentSearchRoutine() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).FinishedCurrentSearchRoutine(); if (base.currentSearch == facilitySearch && base.currentBehaviourStateIndex == 0) { StartFacilitySearch(((Component)this).transform.position, 70f); } } private void EnsureNavigationAgent() { if ((Object)(object)base.agent == (Object)null) { base.agent = ((Component)this).GetComponentInChildren<NavMeshAgent>(true); } if ((Object)(object)base.agent == (Object)null) { base.agent = ((Component)this).gameObject.AddComponent<NavMeshAgent>(); } base.agent.updatePosition = true; base.agent.updateRotation = false; base.agent.updateUpAxis = false; ((Behaviour)base.agent).enabled = true; ConfigureAgent(); } private void ConfigureAgent() { if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled) { base.agent.speed = RoamSpeed; base.agent.acceleration = 10f; base.agent.angularSpeed = 360f; base.agent.stoppingDistance = 0.6f; base.agent.radius = 0.65f; base.agent.height = 1.35f; base.agent.autoBraking = true; base.agent.autoRepath = true; base.agent.autoTraverseOffMeshLink = true; base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; base.agent.avoidancePriority = 45; if (base.agent.areaMask == 0) { base.agent.areaMask = -1; } if (base.openDoorSpeedMultiplier <= 0f) { base.openDoorSpeedMultiplier = 1f; } ApplyHoverHeight(); } } private void ApplyHoverHeight() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled) { float num = ConfiguredHoverHeight; Vector3 val = ((Component)this).transform.position - Vector3.up * base.agent.baseOffset; float num2 = num + 0.675f + 0.6f; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val + Vector3.up * 0.1f, Vector3.up, ref val2, num2, GetWorldCollisionMask(), (QueryTriggerInteraction)1)) { num = Mathf.Clamp(((RaycastHit)(ref val2)).distance + 0.1f - 0.675f - 0.6f, 0f, num); } _hoverHeight = Mathf.MoveTowards(_hoverHeight, num, Mathf.Max(0.5f, num) * 2f * Time.deltaTime); base.agent.baseOffset = _hoverHeight; } } private void RepairOffNavMeshIfNeeded() { if (((NetworkBehaviour)this).IsServer && !((Object)(object)base.agent == (Object)null) && !(Time.time < _nextNavMeshRepairTime) && (!((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh)) { _nextNavMeshRepairTime = Time.time + 1f; SnapToNavMesh(logAlways: false); } } private bool SnapToNavMesh(bool logAlways) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer || (Object)(object)base.agent == (Object)null) { return false; } if (((Behaviour)base.agent).enabled && base.agent.isOnNavMesh) { return true; } Vector3 position = ((Component)this).transform.position; int areaMask = ((base.agent.areaMask == 0) ? (-1) : base.agent.areaMask); if (TrySampleNavMesh(position, 14f, areaMask, out var position2) || TrySampleNearestAINode(position, areaMask, out position2) || TrySampleNavMesh(position, 80f, -1, out position2)) { ((Behaviour)base.agent).enabled = false; ((Component)this).transform.position = position2; ((Behaviour)base.agent).enabled = true; ConfigureAgent(); bool flag = base.agent.Warp(position2); if (logAlways) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[FlyingTV] Placed on the NavMesh at {position2} (from {position}, warp={flag})."); } } if (!flag) { return base.agent.isOnNavMesh; } return true; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)$"[FlyingTV] No NavMesh point found near spawn at {position}; the TV cannot path."); } return false; } private static bool TrySampleNavMesh(Vector3 candidate, float radius, int areaMask, out Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(candidate, ref val, Mathf.Max(0.25f, radius), areaMask)) { position = ((NavMeshHit)(ref val)).position; return true; } position = Vector3.zero; return false; } private bool TrySampleNearestAINode(Vector3 from, int areaMask, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; GameObject[] allAINodes = base.allAINodes; if (allAINodes == null || allAINodes.Length == 0) { return false; } GameObject val = null; float num = float.PositiveInfinity; foreach (GameObject val2 in allAINodes) { if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = val2.transform.position - from; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = val2; } } } if ((Object)(object)val != (Object)null) { return TrySampleNavMesh(val.transform.position, 12f, areaMask, out position); } return false; } private void EnsureEyeTransform() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.eye == (Object)null) { Transform val = ((Component)this).transform.Find("FlyingTVEye"); if ((Object)(object)val == (Object)null) { val = new GameObject("FlyingTVEye").transform; val.SetParent(((Component)this).transform, false); } base.eye = val; } base.eye.localPosition = Vector3.zero; base.eye.localRotation = Quaternion.LookRotation(FlyingTVManager.GetScreenLocalFacingDirection(), Vector3.up); } private void EnsureCollisionBody() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) _bodyCollider = ((Component)this).GetComponent<CapsuleCollider>() ?? ((Component)this).gameObject.AddComponent<CapsuleCollider>(); ((Collider)_bodyCollider).enabled = true; ((Collider)_bodyCollider).isTrigger = false; _bodyCollider.direction = 1; _bodyCollider.center = Vector3.zero; _bodyCollider.radius = 0.65f; _bodyCollider.height = 1.35f; _bodyRigidbody = ((Component)this).GetComponent<Rigidbody>() ?? ((Component)this).gameObject.AddComponent<Rigidbody>(); _bodyRigidbody.isKinematic = true; _bodyRigidbody.useGravity = false; _bodyRigidbody.detectCollisions = true; _bodyRigidbody.collisionDetectionMode = (CollisionDetectionMode)3; } public override void Update() { ((EnemyAI)this).Update(); UpdateStaticPlayback(); if (!base.isEnemyDead) { EnsurePropellerLoopPlaying(); } if (!base.isEnemyDead && !ApplyDamageStunFreeze()) { UpdateAnimation(); TickVisualHover(); if (((NetworkBehaviour)this).IsServer) { UpdateServerMovement(); } } } public override void DoAIInterval() { ((EnemyAI)this).DoAIInterval(); if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead) { return; } int currentBehaviourStateIndex = base.currentBehaviourStateIndex; if (currentBehaviourStateIndex != 6 && currentBehaviourStateIndex != 5 && currentBehaviourStateIndex != 1 && currentBehaviourStateIndex != 2 && currentBehaviourStateIndex != 3 && currentBehaviourStateIndex != 4 && currentBehaviourStateIndex == 0 && !(Time.time < _ignoreDetectionUntil)) { PlayerControllerB val = FindDetectedPlayer(); if ((Object)(object)val != (Object)null) { base.targetPlayer = val; StartApproach(); } } } public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { ((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID); if (base.isEnemyDead) { return; } base.enemyHP -= Mathf.Max(1, force); RegisterDamageHit(); BeginDamageStunFreeze(); if (base.enemyHP <= 0) { DieFromDamage(); } else if ((Object)(object)playerWhoHit != (Object)null) { if (((NetworkBehaviour)this).IsServer) { TriggerNonComplianceFromAttack(playerWhoHit); } else if (((NetworkBehaviour)this).IsSpawned) { ReportAttackHitServerRpc(playerWhoHit.playerClientId); } } } public override void KillEnemy(bool destroy = false) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!base.isEnemyDead) { _destroying = true; StopAllServerRoutines(); if (((NetworkBehaviour)this).IsServer) { StopPlaybackClientRpc(); } else { StopLocalPlayback(resumeStatic: false); } CleanupVideoResources(); StopPropellerLoop(); ClearDamageStunFreeze(); if ((Object)(object)_voiceSource != (Object)null) { _voiceSource.Stop(); } TriggerDeathExplosionPresentation(((Component)this).transform.position); ((EnemyAI)this).SwitchToBehaviourState(6); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; ((EnemyAI)this).KillEnemy(destroy); base.isEnemyDead = true; if (((NetworkBehaviour)this).IsServer && _deathDespawnRoutine == null && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned) { _deathDespawnRoutine = ((MonoBehaviour)this).StartCoroutine(DeathDespawnRoutine()); } } } public override void OnDestroy() { _destroying = true; CleanupVideoResources(); ((EnemyAI)this).OnDestroy(); } internal void InitializeServer(int targetPlayerIndex, string videoName, float durationSeconds) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer) { ResolveReferences(); _videoName = videoName ?? string.Empty; _forcedDurationSeconds = Mathf.Max(0f, durationSeconds); PrefetchYoutubePlaybackClientRpc(_videoName); PlayerControllerB player = FlyingTVManager.GetPlayer(targetPlayerIndex); if (FlyingTVManager.IsValidLivingPlayer(player)) { _lastKnownTargetPosition = ((Component)player).transform.position; StartFacilitySearch(((Component)player).transform.position, 70f); } } } private void StartApproach() { if (base.currentBehaviourStateIndex == 0) { StopSearchIfNeeded(clear: false); base.movingTowardsTargetPlayer = true; base.moveTowardsDestination = true; if ((Object)(object)base.targetPlayer != (Object)null) { ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); } SetAgentSpeed(ApproachSpeed); ((EnemyAI)this).SwitchToBehaviourState(1); PlayVoiceClip(greetingsClip); } } private void StartCheckPhase() { if (!_checkActive) { _checkActive = true; _playerMovementSamples.Clear(); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; StopAgentForHold(); ((EnemyAI)this).SwitchToBehaviourState(2); _checkRoutine = ((MonoBehaviour)this).StartCoroutine(CheckRoutine()); } } private IEnumerator CheckRoutine() { while (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && _checkActive && base.currentBehaviourStateIndex == 2 && FlyingTVManager.IsValidLivingPlayer(base.targetPlayer)) { PlayerControllerB targetPlayer = base.targetPlayer; float time = Time.time; float playerStopWindowSeconds = PlayerStopWindowSeconds; Vector3 position = ((Component)targetPlayer).transform.position; _playerMovementSamples.Add(new PlayerMovementSample(time, position)); float num = time - playerStopWindowSeconds; while (_playerMovementSamples.Count > 1 && _playerMovementSamples[1].Timestamp <= num) { _playerMovementSamples.RemoveAt(0); } bool flag = _playerMovementSamples[0].Timestamp <= num; if (flag) { for (int i = 0; i < _playerMovementSamples.Count; i++) { if (Vector3.Distance(position, _playerMovementSamples[i].Position) > PlayerStopThreshold) { flag = false; break; } } } if (flag && IsWithinFollowRange(targetPlayer)) { bool num2 = IsPlayerFacingTV(targetPlayer, 60f); _checkActive = false; _checkRoutine = null; _playerMovementSamples.Clear(); if (num2) { StartVideoPhase(); } else { StartAttack(); } yield break; } yield return (object)new WaitForSeconds(0.1f); } _checkActive = false; _checkRoutine = null; _playerMovementSamples.Clear(); } private void StartVideoPhase() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!_videoActive) { _videoActive = true; _videoNoncomplianceSince = -1f; _serverNoncomplianceEnableTime = float.PositiveInfinity; _videoHoldPosition = ((Component)this).transform.position; _videoHoldRotation = ((Component)this).transform.rotation; base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; StopAgentForHold(); ((EnemyAI)this).SwitchToBehaviourState(3); float num = ResolveVideoDuration(); float currentVoiceRemainingSeconds = GetCurrentVoiceRemainingSeconds(); _serverVideoEndTime = Time.time + currentVoiceRemainingSeconds + num; if (_videoRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_videoRoutine); } _videoRoutine = ((MonoBehaviour)this).StartCoroutine(VideoStartAndMonitorRoutine(currentVoiceRemainingSeconds, num)); } } private float ResolveVideoDuration() { if (_forcedDurationSeconds > 0f) { return _forcedDurationSeconds; } return 300f; } private IEnumerator VideoStartAndMonitorRoutine(float videoStartDelay, float videoDuration) { if (videoStartDelay > 0f) { float startTime = Time.time + videoStartDelay; while (_videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null && Time.time < startTime) { yield return null; } } if (!_videoActive || base.isEnemyDead || (Object)(object)base.targetPlayer == (Object)null) { _videoRoutine = null; yield break; } if (YoutubeVideoResolver.IsYoutubeUrl(_videoName)) { Task<YoutubeVideoStreams> localPrefetchTask = YoutubeVideoResolver.ResolveAsync(_videoName); float startTime = Time.realtimeSinceStartup + 90f; while (!localPrefetchTask.IsCompleted && _videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null && Time.realtimeSinceStartup < startTime) { yield return null; } if (!_videoActive || base.isEnemyDead || (Object)(object)base.targetPlayer == (Object)null) { _videoRoutine = null; yield break; } if (!localPrefetchTask.IsCompleted) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[FlyingTV] YouTube prefetch did not finish before the presentation deadline."); } } } double playbackStartServerTime = GetSynchronizedServerTime() + 0.3499999940395355; _serverVideoEndTime = Time.time + 0.35f + videoDuration; _serverNoncomplianceEnableTime = Time.time + 0.35f + 5f; StartPlaybackClientRpc(_videoName, _forcedDurationSeconds, playbackStartServerTime); while (_videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null) { if (ShouldTriggerVideoNonCompliance(base.targetPlayer)) { StopPlaybackClientRpc(); _videoActive = false; _videoRoutine = null; StartAttack(); yield break; } if (Time.time >= _serverVideoEndTime) { CompleteVideoAndLeave(); _videoRoutine = null; yield break; } yield return (object)new WaitForSeconds(0.25f); } CompleteVideoAndLeave(); _videoRoutine = null; } private void StartAttack() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (base.currentBehaviourStateIndex != 4) { StopAllServerRoutines(); StopPlaybackClientRpc(); StopSearchIfNeeded(clear: false); base.movingTowardsTargetPlayer = true; base.moveTowardsDestination = true; if ((Object)(object)base.targetPlayer != (Object)null) { _lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position; ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); } SetAgentSpeed(ChaseSpeed); ((EnemyAI)this).SwitchToBehaviourState(4); _attackLostAggroSince = -1f; PlayVoiceClip(noncomplianceClip); } } private void StartLeave(float movementDelaySeconds = 0f) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (base.currentBehaviourStateIndex != 5) { StopAllServerRoutines(); StopSearchIfNeeded(clear: false); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; ((EnemyAI)this).SwitchToBehaviourState(5); Vector3 val = (((Object)(object)base.targetPlayer != (Object)null) ? FlyingTVManager.FlatDirection(((Component)this).transform.position - ((Component)base.targetPlayer).transform.position, -((Component)base.targetPlayer).transform.forward) : ((Component)this).transform.forward); _leaveDestination = ((Component)this).transform.position + val * 16f; if (TrySampleNavMesh(_leaveDestination, 16f, ((Object)(object)base.agent != (Object)null && base.agent.areaMask != 0) ? base.agent.areaMask : (-1), out var position)) { _leaveDestination = position; } _leaveMovementStartTime = Time.time + Mathf.Max(0f, movementDelaySeconds); _leaveDeadline = _leaveMovementStartTime + 3f; _leaveMovementStarted = false; StopAgentForHold(); if (movementDelaySeconds <= 0f) { BeginLeaveMovement(); } } } private void BeginLeaveMovement() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!_leaveMovementStarted) { _leaveMovementStarted = true; base.moveTowardsDestination = true; SetAgentSpeed(LeaveSpeed); if (AgentReady) { base.agent.isStopped = false; ((EnemyAI)this).SetDestinationToPosition(_leaveDestination, true); } } } private void DieFromDamage() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!base.isEnemyDead) { StopAllServerRoutines(); if (((NetworkBehaviour)this).IsServer) { StopPlaybackClientRpc(); DeathExplosionClientRpc(((Component)this).transform.position); } else { StopLocalPlayback(resumeStatic: false); TriggerDeathExplosionPresentation(((Component)this).transform.position); } ((EnemyAI)this).SwitchToBehaviourState(6); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; if (((NetworkBehaviour)this).IsOwner || ((NetworkBehaviour)this).IsServer) { ((EnemyAI)this).KillEnemyOnOwnerClient(false); } } } [ClientRpc] private void DeathExplosionClientRpc(Vector3 position) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(393840246u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe(ref position); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 393840246u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; TriggerDeathExplosionPresentation(position); } } } private void TriggerDeathExplosionPresentation(Vector3 position) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!_deathExplosionTriggered) { _deathExplosionTriggered = true; StopLocalPlayback(resumeStatic: false); StopPropellerLoop(); if ((Object)(object)_voiceSource != (Object)null) { _voiceSource.Stop(); } SpawnVanillaDeathExplosions(position); ApplyLocalDeathExplosionKnockback(position); HideDeathBody(); } } private void SpawnVanillaDeathExplosions(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Vector3 val = position + Vector3.up * 0.7f; SpawnVanillaExplosionVisual(val); SpawnVanillaExplosionVisual(val + Vector3.up * 0.9f); SpawnVanillaExplosionVisual(val - Vector3.up * 0.45f); } private static void SpawnVanillaExplosionVisual(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Landmine.SpawnExplosion(position, true, 0f, 0f, 0, 0f, (GameObject)null, false); } private void ApplyLocalDeathExplosionKnockback(Vector3 position) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if (!FlyingTVManager.IsValidLivingPlayer(val)) { return; } Vector3 val2 = ((Component)val).transform.position - position; float magnitude = ((Vector3)(ref val2)).magnitude; if (!(magnitude > 10f)) { val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = ((Component)val).transform.forward; } float num = Mathf.Clamp01(1f - magnitude / 10f); Vector3 val3 = ((Vector3)(ref val2)).normalized * Mathf.Lerp(12f, 34f, num) + Vector3.up * Mathf.Lerp(4f, 9f, num); val.externalForces += val3; if ((Object)(object)val.playerBodyAnimator != (Object)null) { val.playerBodyAnimator.SetTrigger("Damage"); } } } private void HideDeathBody() { Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.enabled = false; val.forceRenderingOff = true; } } Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { val2.enabled = false; } } if ((Object)(object)_bodyRigidbody != (Object)null) { _bodyRigidbody.detectCollisions = false; } } private IEnumerator DeathDespawnRoutine() { yield return (object)new WaitForSeconds(0.35f); if ((Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned) { ((NetworkBehaviour)this).NetworkObject.Despawn(true); } _deathDespawnRoutine = null; } private void LoseAttackAggro() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) StopAllServerRoutines(); StopPlaybackClientRpc(); _attackLostAggroSince = -1f; _ignoreDetectionUntil = Time.time + ChaseLoseAggroSeconds; Vector3 start = ((_lastKnownTargetPosition == Vector3.zero) ? ((Component)this).transform.position : _lastKnownTargetPosition); base.targetPlayer = null; base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = true; SetAgentSpeed(RoamSpeed); ((EnemyAI)this).SwitchToBehaviourState(0); StartFacilitySearch(start, 52.5f); } private void StopAllServerRoutines() { if (_checkRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_checkRoutine); _checkRoutine = null; } if (_videoRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_videoRoutine); _videoRoutine = null; } _checkActive = false; _videoActive = false; _playerMovementSamples.Clear(); _videoNoncomplianceSince = -1f; } [ServerRpc(RequireOwnership = false)] private void ReportAttackHitServerRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2863110160u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 2863110160u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayerControllerB val3 = ResolvePlayerByClientId(playerClientId); if ((Object)(object)val3 != (Object)null && !base.isEnemyDead) { TriggerNonComplianceFromAttack(val3); } } } private void TriggerNonComplianceFromAttack(PlayerControllerB attacker) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && FlyingTVManager.IsValidLivingPlayer(attacker)) { base.targetPlayer = attacker; _lastKnownTargetPosition = ((Component)attacker).transform.position; if (base.currentBehaviourStateIndex != 4 && base.currentBehaviourStateIndex != 6 && base.currentBehaviourStateIndex != 5) { StartAttack(); } } } private void RegisterDamageHit() { _damageHitCount = Mathf.Clamp(_damageHitCount + 1, 0, 10); _roamAngle += Random.Range(12f, 38f); } private void BeginDamageStunFreeze() { _damageStunUntil = Mathf.Max(_damageStunUntil, Time.time + 1f); ApplyDamageStunFreeze(); } private bool ApplyDamageStunFreeze() { if (!(base.stunNormalizedTimer >= 0f) && !(Time.time < _damageStunUntil)) { ClearDamageStunFreeze(); return false; } PauseAgent(); if (!_damageStunFrozen) { _preDamageStunAnimatorSpeed = (((Object)(object)base.creatureAnimator != (Object)null) ? Mathf.Max(0.01f, base.creatureAnimator.speed) : 1f); _damageStunFrozen = true; } if ((Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.speed = 0f; } return true; } private void ClearDamageStunFreeze() { if (_damageStunFrozen) { if ((Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.speed = _preDamageStunAnimatorSpeed; } _damageStunFrozen = false; } } private void ConfigureSearchDefaults() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown if (facilitySearch == null) { facilitySearch = new AISearchRoutine(); } facilitySearch.loopSearch = true; facilitySearch.randomized = true; facilitySearch.onlySearchNodesInLOS = false; facilitySearch.searchPrecision = 4f; if (facilitySearch.searchWidth <= 0f) { facilitySearch.searchWidth = 70f; } } private void EnsureRoamingSearch() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && base.currentBehaviourStateIndex == 0 && (facilitySearch == null || base.currentSearch != facilitySearch || !facilitySearch.inProgress) && !(Time.time < _nextRoamSearchRetargetTime)) { StartFacilitySearch(((Component)this).transform.position, 70f); } } private void StartFacilitySearch(Vector3 start, float width) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead) { ConfigureSearchDefaults(); facilitySearch.searchWidth = Mathf.Clamp(width, 8f, 160f); facilitySearch.searchPrecision = 4f; if (!CanUseVanillaSearch()) { _nextRoamSearchRetargetTime = Time.time + 0.5f; return; } StopSearchIfNeeded(clear: false); ((EnemyAI)this).StartSearch(start, facilitySearch); _nextRoamSearchRetargetTime = Time.time + Random.Range(3.5f, 7.5f); } } private bool CanUseVanillaSearch() { if (((NetworkBehaviour)this).IsOwner && AgentReady && base.allAINodes != null) { return base.allAINodes.Length != 0; } return false; } private void StopSearchIfNeeded(bool clear) { if (base.currentSearch != null && base.currentSearch.inProgress && ((NetworkBehaviour)this).IsOwner) { ((EnemyAI)this).StopSearch(base.currentSearch, clear); } } private void UpdateRoamingSearch() { SetAgentSpeed(RoamSpeed); EnsureRoamingSearch(); float damageWobbleAmount = DamageWobbleAmount; _roamAngle += Time.deltaTime * (0.6f + damageWobbleAmount * 0.45f); FaceTravelDirection(); } private void FaceTravelDirection() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled) ? base.agent.velocity : Vector3.zero); val.y = 0f; Quaternion val2 = ((!(((Vector3)(ref val)).sqrMagnitude > 0.04f)) ? FlyingTVManager.BuildScreenFacingRotation(new Vector3(Mathf.Cos(_roamAngle * 0.5f), 0f, Mathf.Sin(_roamAngle * 0.5f))) : FlyingTVManager.BuildScreenFacingRotation(((Vector3)(ref val)).normalized)); ((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val2, Mathf.Clamp01(Time.deltaTime * 2.5f)); } private PlayerControllerB FindDetectedPlayer() { float num = Mathf.Max(1f, FlyingTVConfig.DetectionRange.Value); float num2 = Mathf.Clamp(FlyingTVConfig.DetectionConeDegrees.Value, 1f, 360f); int num3 = Mathf.RoundToInt(3f); PlayerControllerB val = ((EnemyAI)this).CheckLineOfSightForPlayer(num2, Mathf.RoundToInt(num), num3); if (!FlyingTVManager.IsValidLivingPlayer(val)) { return null; } return val; } private static PlayerControllerB ResolvePlayerByClientId(ulong clientId) { PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null); if (array == null) { return null; } foreach (PlayerControllerB val in array) { if ((Object)(object)val != (Object)null && val.playerClientId == clientId) { return val; } } return null; } private void UpdateServerMovement() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) int currentBehaviourStateIndex = base.currentBehaviourStateIndex; if (currentBehaviourStateIndex == 6) { return; } RepairOffNavMeshIfNeeded(); ApplyHoverHeight(); switch (currentBehaviourStateIndex) { case 0: UpdateRoamingSearch(); return; case 5: UpdateLeave(); return; } PlayerControllerB targetPlayer = base.targetPlayer; if (!FlyingTVManager.IsValidLivingPlayer(targetPlayer)) { LoseAttackAggro(); return; } _lastKnownTargetPosition = ((Component)targetPlayer).transform.position; switch (currentBehaviourStateIndex) { case 1: if (ShouldLoseAggro(targetPlayer, ApproachLoseAggroDistance, ApproachLoseAggroSeconds)) { LoseAttackAggro(); break; } SetAgentSpeed(ApproachSpeed); FaceTarget(targetPlayer); if (!_checkActive && IsWithinFollowRange(targetPlayer)) { StartCheckPhase(); } break; case 2: if (ShouldLoseAggro(targetPlayer, ApproachLoseAggroDistance, ApproachLoseAggroSeconds)) { LoseAttackAggro(); } else { FollowTargetDuringCheck(targetPlayer); } break; case 3: ((Component)this).transform.rotation = _videoHoldRotation; break; case 4: ChaseAndAttackTarget(targetPlayer); break; } } private void SetAgentSpeed(float speed) { if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled) { base.agent.speed = Mathf.Max(0.1f, speed * DamageSpeedMultiplier); if (base.agent.isOnNavMesh) { base.agent.isStopped = false; } } } private void PauseAgent() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (AgentReady) { base.agent.isStopped = true; base.agent.velocity = Vector3.zero; } } private void StopAgentForHold() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) StopSearchIfNeeded(clear: false); if (AgentReady) { base.agent.isStopped = true; base.agent.ResetPath(); base.agent.velocity = Vector3.zero; } } private void FollowTargetDuringCheck(PlayerControllerB target) { FaceTarget(target); if (IsWithinFollowRange(target)) { if (base.movingTowardsTargetPlayer || base.moveTowardsDestination || (AgentReady && !base.agent.isStopped)) { base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; StopAgentForHold(); } return; } if (!base.movingTowardsTargetPlayer || !base.moveTowardsDestination) { base.movingTowardsTargetPlayer = true; base.moveTowardsDestination = true; ((EnemyAI)this).SetMovingTowardsTargetPlayer(target); } SetAgentSpeed(ApproachSpeed); } private bool IsWithinFollowRange(PlayerControllerB target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= FollowDistance * FollowDistance) { return HasLineOfSightToTarget(target); } return false; } private void UpdateLeave() { if (FlyingTVManager.IsValidLivingPlayer(base.targetPlayer)) { FaceTarget(base.targetPlayer); } if (!(Time.time < _leaveMovementStartTime)) { BeginLeaveMovement(); SetAgentSpeed(LeaveSpeed); if (Time.time >= _leaveDeadline && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned) { ((NetworkBehaviour)this).NetworkObject.Despawn(true); } } } private void ChaseAndAttackTarget(PlayerControllerB target) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (ShouldLoseAggro(target, ChaseLoseAggroDistance, ChaseLoseAggroSeconds)) { LoseAttackAggro(); return; } SetAgentSpeed(ChaseSpeed); FaceTarget(target); if (!(Time.time < _nextAttackTime) && Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position) <= 3.2f) { _nextAttackTime = Time.time + 1.4f; ApplyAttackDamageClientRpc(target.actualClientId, 25); } } [ClientRpc] private void ApplyAttackDamageClientRpc(ulong targetClientId, int damage) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3566271186u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, targetClientId); BytePacker.WriteValueBitPacked(val, damage); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3566271186u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayerControllerB val3 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if (!((Object)(object)val3 == (Object)null) && !val3.isPlayerDead && (val3.actualClientId == targetClientId || val3.playerClientId == targetClientId)) { val3.DamagePlayer(damage, true, true, (CauseOfDeath)1, 0, false, default(Vector3)); } } } private bool ShouldLoseAggro(PlayerControllerB target, float loseDistance, float loseSeconds) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) float num = Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position); bool flag = num >= loseDistance; bool flag2 = num > 3.2f && !HasLineOfSightToTarget(target); if (!flag && !flag2) { _attackLostAggroSince = -1f; return false; } if (_attackLostAggroSince < 0f) { _attackLostAggroSince = Time.time; return false; } return Time.time - _attackLostAggroSince >= loseSeconds; } private bool HasLineOfSightToTarget(PlayerControllerB target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; Vector3 val = ((Component)target).transform.position + Vector3.up * 1.4f - position; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.1f) { return true; } int worldCollisionMask = GetWorldCollisionMask(); int num = Physics.RaycastNonAlloc(position, val / magnitude, _movementHits, magnitude, worldCollisionMask, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref _movementHits[i])).collider; if (!IsIgnoredMovementCollider(collider)) { return false; } } return true; } private void TickVisualHover() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)visualRoot == (Object)null)) { if (!_hasVisualBaseLocalPosition) { _visualBaseLocalPosition = visualRoot.localPosition; _hasVisualBaseLocalPosition = true; } if (base.isEnemyDead) { visualRoot.localPosition = _visualBaseLocalPosition; return; } float damageWobbleAmount = DamageWobbleAmount; float num = Time.time * 1.2f; float num2 = Mathf.Sin(num * 1.3f) * (0.16f + damageWobbleAmount * 0.09f); float num3 = Mathf.Sin(num * 1.7f + _roamAngle) * damageWobbleAmount * 0.11f; visualRoot.localPosition = _visualBaseLocalPosition + new Vector3(num3, num2, 0f); } } private bool IsIgnoredMovementCollider(Collider hitCollider) { if ((Object)(object)hitCollider == (Object)null) { return true; } Transform transform = ((Component)hitCollider).transform; if ((Object)(object)transform != (Object)null && transform.IsChildOf(((Component)this).transform)) { return true; } if ((Object)(object)((Component)hitCollider).GetComponentInParent<PlayerControllerB>() != (Object)null) { return true; } return (Object)(object)((Component)hitCollider).GetComponentInParent<EnemyAI>() != (Object)null; } private static int GetWorldCollisionMask() { if ((Object)(object)StartOfRound.Instance != (Object)null) { return StartOfRound.Instance.collidersAndRoomMaskAndDefault; } int mask = 1; AddLayerToMask(ref mask, "Room"); AddLayerToMask(ref mask, "MapProps"); AddLayerToMask(ref mask, "Colliders"); return mask; } private static void AddLayerToMask(ref int mask, string layerName) { int num = LayerMask.NameToLayer(layerName); if (num >= 0) { mask |= 1 << num; } } private void FaceTarget(PlayerControllerB target) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null)) { Vector3 val = ((Component)target).transform.position + Vector3.up * 1.4f - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = ((Component)this).transform.forward; } val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = ((Component)this).transform.forward; } Vector3 val2 = GetCurrentScreenSideDirection(); if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = ((Component)this).transform.forward; } Quaternion val3 = Quaternion.FromToRotation(((Vector3)(ref val2)).normalized, ((Vector3)(ref val)).normalized) * ((Component)this).transform.rotation; ((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val3, Mathf.Clamp01(Time.deltaTime * 8f)); } } private Vector3 GetCurrentScreenSideDirection() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Vector3 screenFacingDirection = FlyingTVManager.GetScreenFacingDirection(((Component)this).transform); screenFacingDirection.y = 0f; if (((Vector3)(ref screenFacingDirection)).sqrMagnitude > 0.0025f) { return ((Vector3)(ref screenFacingDirection)).normalized; } return ((Component)this).transform.forward; } private bool IsPlayerFacingTV(PlayerControllerB player, float angleThreshold) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } Vector3 forward = ((Component)player).transform.forward; forward.y = 0f; ((Vector3)(ref forward)).Normalize(); Vector3 val = ((Component)this).transform.position - ((Component)player).transform.position; val.y = 0f; ((Vector3)(ref val)).Normalize(); if (((Vector3)(ref forward)).sqrMagnitude < 0.001f || ((Vector3)(ref val)).sqrMagnitude < 0.001f) { return true; } return Vector3.Angle(forward, val) <= angleThreshold; } private bool IsPlayerLookingAwayFromTV(PlayerControllerB player, float angleThreshold) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } Transform val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)player).transform); Vector3 val2; if (!((Object)(object)screenRenderer != (Object)null)) { val2 = ((Component)this).transform.position + Vector3.up * 0.5f; } else { Bounds bounds = screenRenderer.bounds; val2 = ((Bounds)(ref bounds)).center; } Vector3 val3 = val2 - val.position; Vector3 forward = val.forward; if (((Vector3)(ref forward)).sqrMagnitude < 0.001f || ((Vector3)(ref val3)).sqrMagnitude < 0.001f) { return false; } float num = Mathf.Cos(angleThreshold * (MathF.PI / 180f)); forward = val.forward; return Vector3.Dot(((Vector3)(ref forward)).normalized, ((Vector3)(ref val3)).normalized) < num; } private bool ShouldTriggerVideoNonCompliance(PlayerControllerB player) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!FlyingTVManager.IsValidLivingPlayer(player)) { _videoNoncomplianceSince = -1f; return false; } if (Time.time < _serverNoncomplianceEnableTime) { _videoNoncomplianceSince = -1f; return false; } float num = Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position); bool num2 = num > VideoNoncomplianceDistance; bool flag = IsPlayerLookingAwayFromTV(player, TurnAwayAngleThreshold); if (!(num2 || flag)) { _videoNoncomplianceSince = -1f; return false; } if (_videoNoncomplianceSince < 0f) { _videoNoncomplianceSince = Time.time; } if (Time.time - _videoNoncomplianceSince < VideoNoncomplianceSustainSeconds) { return false; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[FlyingTV] Video noncompliance detected: distance={num:0.0}m " + $"(limit {VideoNoncomplianceDistance:0.0}m), outsideViewCone={flag}.")); } return true; } private void CompleteVideoAndLeave() { if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && base.currentBehaviourStateIndex == 3) { _videoActive = false; StopPlaybackClientRpc(); PlayVoiceClip(complianceClip); float currentVoiceRemainingSeconds = GetCurrentVoiceRemainingSeconds(); StartLeave(currentVoiceRemainingSeconds); } } private void UpdateAnimation() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.creatureAnimator == (Object)null) && _hasMovingParameter) { Vector3 val = ((Component)this).transform.position - _lastPosition; float num = ((Vector3)(ref val)).magnitude / Mathf.Max(Time.deltaTime, 0.001f); bool flag = base.currentBehaviourStateIndex == 1 || base.currentBehaviourStateIndex == 4 || base.currentBehaviourStateIndex == 5 || num > 0.2f; base.creatureAnimator.SetBool(MovingHash, flag); _lastPosition = ((Component)this).transform.position; } } private void PlayVoiceClip(AudioClip clip) { if (!((Object)(object)_voiceSource == (Object)null) && !((Object)(object)clip == (Object)null)) { _voiceSource.Stop(); _voiceSource.clip = clip; _lastVoiceClip = clip; _lastVoiceStartTime = Time.time; _voiceSource.Play(); } } private float GetCurrentVoiceRemainingSeconds() { AudioClip val = (((Object)(object)_voiceSource != (Object)null && (Object)(object)_voiceSource.clip != (Object)null) ? _voiceSource.clip : _lastVoiceClip); if ((Object)(object)val == (Object)null) { return 0f; } if ((Object)(object)_voiceSource != (Object)null && _voiceSource.isPlaying && (Object)(object)_voiceSource.clip == (Object)(object)val) { float num = Mathf.Max(0.01f, Mathf.Abs(_voiceSource.pitch)); float num2 = (val.length - _voiceSource.time) / num; if (!(num2 > 0f)) { return 0f; } return num2 + 0.15f; } float num3 = Time.time - _lastVoiceStartTime; float num4 = val.length - Mathf.Max(0f, num3); if (!(num4 > 0f)) { return 0f; } return num4 + 0.15f; } private void EnsurePropellerLoopPlaying() { if ((Object)(object)_propellerSource == (Object)null) { return; } if ((Object)(object)propellerLoopClip == (Object)null) { propellerLoopClip = Plugin.PropellerClip; } if (!((Object)(object)propellerLoopClip == (Object)null)) { _propellerSource.loop = true; _propellerSource.volume = ((FlyingTVConfig.PropellerVolume != null) ? Mathf.Clamp01(FlyingTVConfig.PropellerVolume.Value) : 0.65f); if ((Object)(object)_propellerSource.clip != (Object)(object)propellerLoopClip) { _propellerSource.clip = propellerLoopClip; } if (!_propellerSource.isPlaying) { _propellerSource.Play(); } } } private void StopPropellerLoop() { if ((Object)(object)_propellerSource != (Object)null) { _propellerSource.Stop(); } } [ClientRpc] private void PrefetchYoutubePlaybackClientRpc(string youtubeUrl) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2130784982u, val2, (RpcDelivery)0); bool flag = youtubeUrl != null; ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(youtubeUrl, false); } ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2130784982u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (YoutubeVideoResolver.IsYoutubeUrl(youtubeUrl)) { YoutubeVideoResolver.ResolveAsync(youtubeUrl); } } } [ClientRpc] private void StartPlaybackClientRpc(string videoName, float durationSeconds, double playbackStartServerTime) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3395646845u, val2, (RpcDelivery)0); bool flag = videoName != null; ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(videoName, false); } ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref durationSeconds, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref playbackStartServerTime, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3395646845u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; _videoName = videoName ?? string.Empty; _forcedDurationSeconds = Mathf.Max(0f, durationSeconds); if (!_selectedVideoPlaying) { ResolveReferences(); _selectedVideoPlaying = true; if (YoutubeVideoResolver.IsYoutubeUrl(videoName)) { StartYoutubeVideoPlayback(videoName, _forcedDurationSeconds, playbackStartServerTime); return; } string videoLocation = ResolveVideoLocation(videoName); StartVideoPlayback(videoLocation, loop: false, playAudio: true, selectedVideo: true, _forcedDurationSeconds, playbackStartServerTime); } } private void StartYoutubeVideoPlayback(string youtubeUrl, float durationSeconds, double playbackStartServerTime) { if (_playbackRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_playbackRoutine); _playbackRoutine = null; } StopVideoPlayer(); _playbackRoutine = ((MonoBehaviour)this).StartCoroutine(ResolveAndStartYoutubePlayback(youtubeUrl, durationSeconds, playbackStartServerTime)); } private IEnumerator ResolveAndStartYoutubePlayback(string youtubeUrl, float durationSeconds, double playbackStartServerTime) { Task<YoutubeVideoStreams> resolutionTask = YoutubeVideoResolver.ResolveAsync(youtubeUrl); float resolutionDeadline = Time.realtimeSinceStartup + 90f; while (!resolutionTask.IsCompleted && _selectedVideoPlaying && !_destroying && !base.isEnemyDead && Time.realtimeSinceStartup < resolutionDeadline) { yield return null; } if (!_selectedVideoPlaying || _destroying || base.isEnemyDead) { _playbackRoutine = null; yield break; } YoutubeVideoStreams youtubeVideoStreams = null; if (!resolutionTask.IsCompleted) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[FlyingTV] Local YouTube resolution timed out; showing the fallback screen."); } } else if (!resolutionTask.IsCanceled && !resolutionTask.IsFaulted) { youtubeVideoStreams = resolutionTask.Result; } _playbackRoutine = null; StartVideoPlayback(youtubeVideoStreams?.VideoUrl, loop: false, playAudio: true, selectedVideo: true, durationSeconds, playbackStartServerTime); } [ClientRpc] private void StopPlaybackClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2066075155u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2066075155u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; StopLocalPlayback(resumeStatic: true); } } } [ServerRpc(RequireOwnership = false)] private void SelectedPlaybackFinishedServerRpc(ServerRpcParams rpcParams = default(ServerRpcParams)) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2905851093u, rpcParams, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 2905851093u, rpcParams, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; CompleteVideoAndLeave(); } } } private void StartStaticPlayback() { if (_destroying || base.isEnemyDead || _selectedVideoPlaying) { return; } ResolveReferences(); StopVideoPlayer(); EnsureScreenMaterial(); EnsureStaticTexture(); if ((Object)(object)_staticTexture == (Object)null) { ShowFallbackTexture(); return; } _staticPlaying = true; _nextStaticFrameTime = 0f; UpdateStaticPlayback(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[FlyingTV] Started procedural animated static playback."); } } private void StartVideoPlayback(string videoLocation, bool loop, bool playAudio, bool selectedVideo, float durationSeconds, double playbackStartServerTime) { if (!_destroying && !base.isEnemyDead) { if (_playbackRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_playbackRoutine); _playbackRoutine = null; } StopVideoPlayer(); _playbackRoutine = ((MonoBehaviour)this).StartCoroutine(PrepareAndPlayVideo(videoLocation, loop, playAudio, selectedVideo, durationSeconds, playbackStartServerTime)); } } private IEnumerator PrepareAndPlayVideo(string videoLocation, bool loop, bool playAudio, bool selectedVideo, float durationSeconds, double playbackStartServerTime) { EnsureScreenMaterial(); EnsureRenderTexture(); bool flag = IsVideoUrl(videoLocation); if (string.IsNullOrEmpty(videoLocation) || (!flag && !File.Exists(videoLocation))) { if (selectedVideo) { _playbackRoutine = null; HandleSelectedVideoFailed(); } else { ShowFallbackTexture(); _playbackRoutine = null; } yield break; } _videoPlayer = ((Component)this).gameObject.GetComponent<VideoPlayer>(); if ((Object)(object)_videoPlayer == (Object)null) { _videoPlayer = ((Component)this).gameObject.AddComponent<VideoPlayer>(); } _videoPlayer.playOnAwake = false; _videoPlayer.waitForFirstFrame = true; _videoPlayer.skipOnDrop = true; _videoPlayer.aspectRatio = (VideoAspectRatio)5; _videoPlayer.isLooping = loop; _videoPlayer.source = (VideoSource)1; _videoPlayer.url = (flag ? videoLocation : new Uri(videoLocation).AbsoluteUri); _videoPlayer.renderMode = (VideoRenderMode)2; _videoPlayer.targetTexture = _renderTexture; _videoPlayer.audioOutputMode = (VideoAudioOutputMode)(playAudio ? 1 : 0); _videoPlayer.controlledAudioTrackCount = (playAudio ? ((ushort)1) : ((ushort)0)); if (playAudio) { _videoPlayer.SetTargetAudioSource((ushort)0, videoAudioSource); } _videoPlayer.loopPointReached -= new EventHandler(OnVideoLoopPointReached); _videoPlayer.loopPointReached += new EventHandler(OnVideoLoopPointReached); _videoPlayer.errorReceived -= new ErrorEventHandler(OnVideoErrorReceived); _videoPlayer.errorReceived += new ErrorEventHandler(OnVideoErrorReceived); _videoPlayer.Prepare(); float prepareDeadline = Time.realtimeSinceStartup + 20f; while (!_videoPlayer.isPrepared && Time.realtimeSinceStartup < prepareDeadline) { yield return null; } if (!_videoPlayer.isPrepared) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[FlyingTV] Video failed to prepare within {20f:0} seconds: " + GetSafeVideoLocationLabel(videoLocation))); } if (selectedVideo) { _playbackRoutine = null; HandleSelectedVideoFailed(); } else { ShowFallbackTexture(); _playbackRoutine = null; } yield break; } int requestedWidth = (int)((_videoPlayer.width != 0) ? Math.Min(_videoPlayer.width, 2048u) : 1024); int requestedHeight = (int)((_videoPlayer.height != 0) ? Math.Min(_videoPlayer.height, 2048u) : 576); EnsureRenderTexture(requestedWidth, requestedHeight); _videoPlayer.targetTexture = _renderTexture; double num = 0.0; if (selectedVideo && playbackStartServerTime > 0.0) { while (_selectedVideoPlaying && GetSynchronizedServerTime() < playbackStartServerTime) { yield return null; } if (!_selectedVideoPlaying) { yield break; } num = Math.Max(0.0, GetSynchronizedServerTime() - playbackStartServerTime); if (durationSeconds > 0f && num >= (double)durationSeconds) { _playbackRoutine = null; HandleSelectedVideoFinished(); yield break; } SeekPreparedPlayer(_videoPlayer, num); } StopStaticPlayback(); ApplyTextureToScreen((Texture)(object)_renderTexture); _videoPlayer.Play(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[FlyingTV] Video render target resized to {((Texture)_renderTexture).width}x{((Texture)_renderTexture).height}."); } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)(selectedVideo ? "[FlyingTV] Started selected video playback with picture and audio." : "[FlyingTV] Started local video playback.")); } if (selectedVideo && durationSeconds > 0f) { float num2 = Mathf.Max(0f, durationSeconds - (float)num); if (num2 > 0f) { yield return (object)new WaitForSeconds(num2); } _playbackRoutine = null; HandleSelectedVideoFinished(); } else { _playbackRoutine = null; } } private static void SeekPreparedPlayer(VideoPlayer player, double playbackOffsetSeconds) { if (!((Object)(object)player == (Object)null) && player.isPrepared && !(playbackOffsetSeconds <= 0.05) && player.canSetTime) { double num = playbackOffsetSeconds; if (player.length > 0.0) { num = Math.Min(num, Math.Max(0.0, player.length - 0.05)); } player.time = num; } } private static string GetSafeVideoLocationLabel(string videoLocation) { if (string.IsNullOrWhiteSpace(videoLocation)) { return "no media source"; } if (Uri.TryCreate(videoLocation, UriKind.Absolute, out Uri result) && (result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps)) { return result.Scheme + "://" + result.IdnHost + "/..."; } string fileName = Path.GetFileName(videoLocation); if (!string.IsNullOrEmpty(fileName)) { return fileName; } return "local media file"; } private static string GetSafeVideoError(string message) { if (string.IsNullOrWhiteSpace(message)) { return "no decoder diagnostic was returned"; } string text = message.Replace('\r', ' ').Replace('\n', ' ').Trim(); if (text.IndexOf("http", StringComparison.OrdinalIgnoreCase) >= 0) { return "the decoder reported an HTTP media failure (signed URL omitted)"; } if (text.Length > 300) { return text.Substring(0, 300) + "..."; } return text; } private static double GetSynchronizedServerTime() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton != (Object)null)) { return Time.realtimeSinceStartup; } NetworkTime serverTime = singleton.ServerTime; return ((NetworkTime)(ref serverTime)).Time; } private void OnVideoLoopPointReached(VideoPlayer source) { if (_selectedVideoPlaying) { HandleSelectedVideoFinished(); } } private void OnVideoErrorReceived(VideoPlayer source, string message) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[FlyingTV] Video error: " + GetSafeVideoError(message))); } if (_selectedVideoPlaying) { HandleSelectedVideoFailed(); return; } StopVideoPlayer(); ShowFallbackTexture(); } private void HandleSelectedVideoFinished() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_selectedVideoPlaying) { _selectedVideoPlaying = false; StopVideoPlayer(); StartStaticPlayback(); if (((NetworkBehaviour)this).IsServer) { CompleteVideoAndLeave(); } else if (((NetworkBehaviour)this).IsSpawned && !YoutubeVideoResolver.IsYoutubeUrl(_videoName)) { SelectedPlaybackFinishedServerRpc(); } } } private void HandleSelectedVideoFailed() { if (!_selectedVideoPlaying) { return; } _selectedVideoPlaying = false; StopVideoPlayer(); StartStaticPlayback(); if (((NetworkBehaviour)this).IsServer && _videoActive && base.currentBehaviourStateIndex == 3) { float num = Time.time + 10f; if (_serverVideoEndTime <= Time.time || _serverVideoEndTime > num) { _serverVideoEndTime = num; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[FlyingTV] Selected video failed; showing animated static for {10f:0} seconds before leaving."); } } } private void StopLocalPlayback(bool resumeStatic) { _selectedVideoPlaying = false; StopVideoPlayer(); StopStaticPlayback(); if (resumeStatic) { StartStaticPlayback(); } } private void StopVideoPlayer() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (_playbackRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_playbackRoutine); _playbackRoutine = null; } if ((Object)(object)_videoPlayer != (Object)null) { _videoPlayer.loopPointReached -= new EventHandler(OnVideoLoopPointReached); _videoPlayer.errorReceived -= new ErrorEventHandler(OnVideoErrorReceived); _videoPlayer.Stop(); } if ((Object)(object)videoAudioSource != (Object)null) { videoAudioSource.Stop(); } } private void CleanupVideoResources() { StopLocalPlayback(resumeStatic: false); if ((Object)(object)_renderTexture != (Object)null) { _renderTexture.Release(); Object.Destroy((Object)(object)_renderTexture); _renderTexture = null; } if ((Object)(object)_staticTexture != (Object)null) { Object.Destroy((Object)(object)_staticTexture); _staticTexture = null; _staticPixels = null; } if ((Object)(object)_screenMaterial != (Object)null) { Object.Destroy((Object)(object)_screenMaterial); _screenMaterial = null; _screenMaterialIndex = -1; } if ((Object)(object)_screenBlankMaterial != (Object)null) { Object.Destroy((Object)(object)_screenBlankMaterial); _screenBlankMaterial = null; } if ((Object)(object)_screenOverlayObject != (Object)null) { Object.Destroy((Object)(object)_screenOverlayObject); _screenOverlayObject = null; _screenOverlayRenderer = null; } if ((Object)(object)_fallbackTexture != (Object)null) { Object.Destroy((Object)(object)_fallbackTexture); _fallbackTexture = null; } } private void EnsureScreenMaterial() { CollectScreenMaterialTargets(); if ((Object)(object)_screenMaterial != (Object)null) { ApplyScreenMaterialToTargets(); NeutralizeOriginalScreenSurfaces(); EnsureVideoDisplaySurface(); return; } Material source = null; if (_screenMaterialTargets.Count > 0) { ScreenMaterialTarget screenMaterialTarget = _screenMaterialTargets[0]; Material[] array = (((Object)(object)screenMaterialTarget.Renderer != (Object)null) ? screenMaterialTarget.Renderer.materials : null); if (array != null && screenMaterialTarget.MaterialIndex >= 0 && screenMaterialTarget.MaterialIndex < array.Length) { source = array[screenMaterialTarget.MaterialIndex]; } } else if ((Object)(object)screenRenderer != (Object)null) { Material[] materials = screenRenderer.materials; if (materials != null && materials.Length != 0) { _screenMaterialIndex = ResolveScreenMaterialIndex(materials, _screenMaterialIndex); source = (((Object)(object)materials[_screenMaterialIndex] != (Object)null) ? materials[_screenMaterialIndex] : screenRenderer.sharedMaterial); } } _screenMaterial = CreateRuntimeScreenMaterial(source); ((Object)_screenMaterial).name = "FlyingTV_RuntimeScreen"; ApplyScreenMaterialToTargets(); NeutralizeOriginalScreenSurfaces(); EnsureVideoDisplaySurface(); } private void EnsureRenderTexture(int requestedWidth = 0, int requestedHeight = 0) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown int num = ((requestedWidth > 0) ? Mathf.Clamp(requestedWidth, 64, 2048) : 1024); int num2 = ((requestedHeight > 0) ? Mathf.Clamp(requestedHeight, 64, 2048) : 576); if ((Object)(object)_renderTexture != (Object)null && ((Texture)_renderTexture).width == num && ((Texture)_renderTexture).height == num2 && _renderTexture.IsCreated()) { return; } if ((Object)(object)_renderTexture != (Object)null) { if ((Object)(object)_videoPlayer != (Object)null && (Object)(object)_videoPlayer.targetTexture == (Object)(object)_renderTexture) { _videoPlayer.targetTexture = null; } _renderTexture.Release(); Object.Destroy((Object)(object)_renderTexture); _renderTexture = null; } _renderTexture = new RenderTexture(num, num2, 0, (RenderTextureFormat)0) { name = "FlyingTVVideoRT", useMipMap = false, autoGenerateMips = false }; _renderTexture.Create(); } private void ShowFallbackTexture() { StopStaticPlayback(); EnsureScreenMaterial(); if ((Object)(object)_fallbackTexture == (Object)null) { _fallbackTexture = BuildFallbackTexture(); } ApplyTextureToScreen((Texture)(object)_fallbackTexture); } private void EnsureStaticTexture() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if (!((Object)(object)_staticTexture != (Object)null) || _staticPixels == null) { _staticTexture = new Texture2D(256, 144, (TextureFormat)4, false) { name = "FlyingTVProceduralStatic", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)0 }; _staticPixels = (Color32[])(object)new Color32[36864]; _staticNoiseState = (uint)(((Object)this).GetInstanceID() ^ -1640531527); if (_staticNoiseState == 0) { _staticNoiseState = 2738958700u; } ApplyTextureToScreen((Texture)(object)_staticTexture); } } private void UpdateStaticPlayback() { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (!_staticPlaying || (Object)(object)_sta
Y4NGZHarmonic.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using Unity.Netcode; using Unity.Netcode.Components; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using Y4NGZHarmonic.AI; using Y4NGZHarmonic.NetcodePatcher; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZHarmonic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZHarmonic")] [assembly: AssemblyTitle("Y4NGZHarmonic")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZHarmonic { internal static class HarmonicBloodFxBridge { internal const string PluginGuid = "com.y4ngz.bloodfx"; private const string CreatureBloodTypeName = "Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood"; private static bool? _pluginPresent; private static bool _bridgeResolved; private static PropertyInfo _isAvailable; private static MethodInfo _playCreatureBleed; internal static void PlayCreatureBleed(int creatureKey, Vector3 point, Vector3 direction, Color tint, int contacts, float scale) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!BloodFxPluginPresent() || !ResolveBridge()) { return; } try { if (_isAvailable != null) { object value = _isAvailable.GetValue(null); if (value is bool && !(bool)value) { return; } } _playCreatureBleed.Invoke(null, new object[6] { creatureKey, point, direction, tint, contacts, scale }); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Harmonic] Optional BloodFX bridge failed: " + ex.GetBaseException().Message)); } } } private static bool BloodFxPluginPresent() { if (!_pluginPresent.HasValue) { _pluginPresent = Chainloader.PluginInfos.ContainsKey("com.y4ngz.bloodfx"); } return _pluginPresent.Value; } private static bool ResolveBridge() { if (_bridgeResolved) { return _playCreatureBleed != null; } _bridgeResolved = true; if (!Chainloader.PluginInfos.TryGetValue("com.y4ngz.bloodfx", out var value) || (Object)(object)value.Instance == (Object)null) { return false; } Type type = ((object)value.Instance).GetType().Assembly.GetType("Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood", throwOnError: false); if (type == null) { return false; } _isAvailable = type.GetProperty("IsAvailable", BindingFlags.Static | BindingFlags.Public); _playCreatureBleed = type.GetMethod("PlayCreatureBleed", BindingFlags.Static | BindingFlags.Public, null, new Type[6] { typeof(int), typeof(Vector3), typeof(Vector3), typeof(Color), typeof(int), typeof(float) }, null); return _playCreatureBleed != null; } } internal sealed class HarmonicConfig { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<float> SpawnWeightMultiplier { get; } public ConfigEntry<int> MaxCount { get; } public ConfigEntry<float> PowerLevel { get; } public ConfigEntry<int> Health { get; } public ConfigEntry<float> MoveSpeed { get; } public ConfigEntry<float> AlarmChance { get; } public ConfigEntry<float> AlarmAttractionRadius { get; } public ConfigEntry<float> MusicVolume { get; } public ConfigEntry<float> SfxVolume { get; } public ConfigEntry<float> MusicMaxDistance { get; } public ConfigEntry<float> SfxMaxDistance { get; } public ConfigEntry<bool> DebugLogs { get; } public HarmonicConfig(ConfigFile config) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Expected O, but got Unknown bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { HarmonicConfigMigration.TryMigrate(config, Plugin.Log); ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Harmonic"); Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Harmonic encounter."); SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Harmonic's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Harmonics at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 1.1f, new ConfigDescription("Indoor enemy power budget cost for each Harmonic.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>())); Health = config.Bind<int>("Core Stats", "Health", 4, new ConfigDescription("Hits the Harmonic can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); MoveSpeed = config.Bind<float>("Movement", "MoveSpeed", 1.15f, new ConfigDescription("Passive roaming speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>())); AlarmChance = config.Bind<float>("Abilities", "AlarmChance", 0.2f, new ConfigDescription("Chance that the next selected track will be the alarm.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); AlarmAttractionRadius = config.Bind<float>("Abilities", "AlarmAttractionRadius", 30f, new ConfigDescription("Maximum distance in metres at which an alarm attracts other indoor enemies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>())); MusicVolume = config.Bind<float>("Audio and Presentation", "MusicVolume", 0.95f, new ConfigDescription("Volume for idle music.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); SfxVolume = config.Bind<float>("Audio and Presentation", "SfxVolume", 1f, new ConfigDescription("Shared volume for the alarm, hit, and death sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); MusicMaxDistance = config.Bind<float>("Audio and Presentation", "MusicMaxDistance", 65f, new ConfigDescription("Maximum audible distance for Harmonic music.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 65f), Array.Empty<object>())); SfxMaxDistance = config.Bind<float>("Audio and Presentation", "SfxMaxDistance", 42f, new ConfigDescription("Maximum audible distance for alarm, hit, and death sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 42f), Array.Empty<object>())); DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose Harmonic diagnostics to the BepInEx log."); } finally { config.SaveOnConfigSet = saveOnConfigSet; if (saveOnConfigSet) { config.Save(); } } } } internal static class HarmonicConfigMigration { private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight"); private static readonly Dictionary<ConfigDefinition, string> RemovedDefaults = new Dictionary<ConfigDefinition, string> { { new ConfigDefinition("Spawning", "LevelMask"), "-1" }, { new ConfigDefinition("Spawning", "SpawnType"), "Default" }, { new ConfigDefinition("Stats", "ModelScale"), "0.72" }, { new ConfigDefinition("Movement", "Acceleration"), "4.5" }, { new ConfigDefinition("Movement", "AngularSpeed"), "70" }, { new ConfigDefinition("Movement", "HoverHeight"), "0.55" }, { new ConfigDefinition("Movement", "RoamSearchWidth"), "120" }, { new ConfigDefinition("Movement", "RoamSearchPrecision"), "8" }, { new ConfigDefinition("Movement", "RoamStuckRecoverySeconds"), "3.5" }, { new ConfigDefinition("Movement", "MovementBobAmount"), "0.06" }, { new ConfigDefinition("Movement", "MovementTiltDegrees"), "4" }, { new ConfigDefinition("Collision", "BodyColliderRadius"), "0.32" }, { new ConfigDefinition("Collision", "BodyColliderHeight"), "1.25" }, { new ConfigDefinition("Alarm", "RefreshSeconds"), "0.35" }, { new ConfigDefinition("Audio", "AlarmVolume"), "1" }, { new ConfigDefinition("Audio", "DeathVolume"), "1" }, { new ConfigDefinition("Death", "HitInflateAmount"), "0.13" }, { new ConfigDefinition("Death", "DeathEffectScale"), "0.75" }, { new ConfigDefinition("Pulse", "IdlePulseRate"), "0.42" }, { new ConfigDefinition("Pulse", "WarningPulseRate"), "1.55" }, { new ConfigDefinition("Pulse", "PitchPulseAmount"), "0.025" }, { new ConfigDefinition("Pulse", "VolumePulseAmount"), "0.08" }, { new ConfigDefinition("Pulse", "WarningPitchMultiplier"), "1.18" }, { new ConfigDefinition("Pulse", "AnimationPulseAmount"), "0" }, { new ConfigDefinition("Pulse", "HornPulseScale"), "0.06" }, { new ConfigDefinition("Light", "BaseIntensity"), "45" }, { new ConfigDefinition("Light", "PulseIntensity"), "35" }, { new ConfigDefinition("Light", "Range"), "8.5" }, { new ConfigDefinition("Light", "EmissionIntensity"), "0.22" } }; internal static bool TryMigrate(ConfigFile config, ManualLogSource log) { string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return false; } Dictionary<ConfigDefinition, string> dictionary = null; string text = null; try { dictionary = ReadValues(configFilePath); if (!ContainsLegacyConfig(dictionary)) { return false; } text = GetBackupPath(configFilePath); File.Copy(configFilePath, text, overwrite: false); File.WriteAllText(configFilePath, BuildMigratedConfig(dictionary), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } catch (Exception ex) { string text2 = "The original config was not modified."; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Copy(text, configFilePath, overwrite: true); config.Reload(); text2 = "The original config was restored from its backup."; } catch (Exception ex2) { text2 = "Automatic restore also failed: " + ex2.GetBaseException().Message + ". Recover manually from " + text + "."; } } if (log != null) { log.LogWarning((object)("[Harmonic] Could not migrate legacy config: " + ex.GetBaseException().Message + " " + text2)); } return false; } List<string> list = FindCustomizedDroppedKeys(dictionary); if (log != null) { log.LogInfo((object)("[Harmonic] Migrated legacy config to the compact DawnLib layout. Backup: " + text)); } if (list.Count > 0 && log != null) { log.LogWarning((object)("[Harmonic] These customized legacy settings are now authored source tuning and were not carried forward: " + string.Join(", ", list))); } return true; } private static bool ContainsLegacyConfig(Dictionary<ConfigDefinition, string> values) { if (values.ContainsKey(LegacySpawnWeight)) { return true; } foreach (ConfigDefinition key in RemovedDefaults.Keys) { if (values.ContainsKey(key)) { return true; } } return false; } private static string BuildMigratedConfig(Dictionary<ConfigDefinition, string> values) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00a8: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_0105: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_013f: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_018a: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_01d5: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_0220: Expected O, but got Unknown //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Expected O, but got Unknown //IL_025a: Expected O, but got Unknown //IL_0287: 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) //IL_02a5: Expected O, but got Unknown //IL_02a5: Expected O, but got Unknown //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Expected O, but got Unknown //IL_02df: Expected O, but got Unknown //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Expected O, but got Unknown //IL_0319: Expected O, but got Unknown //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Expected O, but got Unknown //IL_0353: Expected O, but got Unknown //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Expected O, but got Unknown //IL_039e: Expected O, but got Unknown string text = GetValue(values, new ConfigDefinition("10 - Spawning", "SpawnWeightMultiplier"), null, null); if (string.IsNullOrWhiteSpace(text)) { text = ((!float.TryParse(GetValue(values, LegacySpawnWeight, null, "18"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) ? "1" : (result / 18f).ToString("0.###", CultureInfo.InvariantCulture)); } StringBuilder stringBuilder = new StringBuilder(); AppendSection(stringBuilder, "00 - General", ("Enabled", GetValue(values, new ConfigDefinition("00 - General", "Enabled"), new ConfigDefinition("General", "Enabled"), "true"))); AppendSection(stringBuilder, "10 - Spawning", ("SpawnWeightMultiplier", text), ("MaxCount", GetValue(values, new ConfigDefinition("10 - Spawning", "MaxCount"), new ConfigDefinition("Spawning", "MaxCount"), "1")), ("PowerLevel", GetValue(values, new ConfigDefinition("10 - Spawning", "PowerLevel"), new ConfigDefinition("Spawning", "PowerLevel"), "1.1"))); AppendSection(stringBuilder, "20 - Core Stats", ("Health", GetValue(values, new ConfigDefinition("20 - Core Stats", "Health"), new ConfigDefinition("Stats", "Health"), "4"))); AppendSection(stringBuilder, "40 - Movement", ("MoveSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "MoveSpeed"), new ConfigDefinition("Movement", "MoveSpeed"), "1.15"))); AppendSection(stringBuilder, "60 - Abilities", ("AlarmChance", GetValue(values, new ConfigDefinition("60 - Abilities", "AlarmChance"), new ConfigDefinition("Audio", "AlarmChance"), "0.2")), ("AlarmAttractionRadius", GetValue(values, new ConfigDefinition("60 - Abilities", "AlarmAttractionRadius"), new ConfigDefinition("Alarm", "AttractionRadius"), "30"))); AppendSection(stringBuilder, "70 - Audio and Presentation", ("MusicVolume", GetValue(values, new ConfigDefinition("70 - Audio and Presentation", "MusicVolume"), new ConfigDefinition("Audio", "IdleMusicVolume"), "0.95")), ("SfxVolume", GetValue(values, new ConfigDefinition("70 - Audio and Presentation", "SfxVolume"), new ConfigDefinition("Audio", "HitVolume"), "1")), ("MusicMaxDistance", GetValue(values, new ConfigDefinition("70 - Audio and Presentation", "MusicMaxDistance"), new ConfigDefinition("Audio", "MusicMaxDistance"), "65")), ("SfxMaxDistance", GetValue(values, new ConfigDefinition("70 - Audio and Presentation", "SfxMaxDistance"), new ConfigDefinition("Audio", "SfxMaxDistance"), "42"))); AppendSection(stringBuilder, "99 - Diagnostics", ("DebugLogs", GetValue(values, new ConfigDefinition("99 - Diagnostics", "DebugLogs"), new ConfigDefinition("Debug", "DebugLogs"), "false"))); return stringBuilder.ToString(); } private static void AppendSection(StringBuilder output, string section, params (string Key, string Value)[] entries) { output.Append('[').Append(section).AppendLine("]"); for (int i = 0; i < entries.Length; i++) { output.Append(entries[i].Key).Append(" = ").AppendLine(entries[i].Value); } output.AppendLine(); } private static string GetValue(Dictionary<ConfigDefinition, string> values, ConfigDefinition preferred, ConfigDefinition legacy, string fallback) { if (preferred != (ConfigDefinition)null && values.TryGetValue(preferred, out var value)) { return value; } if (legacy != (ConfigDefinition)null && values.TryGetValue(legacy, out value)) { return value; } return fallback; } private static Dictionary<ConfigDefinition, string> ReadValues(string path) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(); string text = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string value = text2.Substring(num + 1).Trim(); dictionary[new ConfigDefinition(text, text3)] = value; } } return dictionary; } private static List<string> FindCustomizedDroppedKeys(Dictionary<ConfigDefinition, string> values) { List<string> list = new List<string>(); foreach (KeyValuePair<ConfigDefinition, string> removedDefault in RemovedDefaults) { if (values.TryGetValue(removedDefault.Key, out var value) && !ValuesEquivalent(value, removedDefault.Value)) { list.Add(removedDefault.Key.Section + "." + removedDefault.Key.Key); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private static bool ValuesEquivalent(string left, string right) { if (string.Equals(left.Trim(), right.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } if (float.TryParse(left, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(right, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) < 0.0001f; } return false; } private static string GetBackupPath(string configPath) { string text = configPath + ".pre-dawn.bak"; if (!File.Exists(text)) { return text; } for (int i = 2; i < 1000; i++) { string text2 = configPath + $".pre-dawn.{i}.bak"; if (!File.Exists(text2)) { return text2; } } throw new IOException("Could not allocate a Harmonic config backup filename."); } } internal sealed class HarmonicSpawnWeights : IWeighted, IContextualWeighted<SpawnWeightContext> { internal const int DefaultWeight = 6; internal const int MaximumWeight = 100; private readonly Func<float> _multiplier; internal HarmonicSpawnWeights(Func<float> multiplier) { _multiplier = multiplier ?? throw new ArgumentNullException("multiplier"); } public int GetWeight() { return Scale(6, 1f); } public int GetWeight(SpawnWeightContext context) { int moonWeight = GetMoonWeight(((SpawnWeightContext)(ref context)).Moon); if (moonWeight <= 0) { return 0; } return Scale(moonWeight, GetDungeonMultiplier(((SpawnWeightContext)(ref context)).Dungeon)); } internal static int GetMoonWeight(DawnMoonInfo moon) { if (moon == null) { return 6; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Company) || ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Unimplemented) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Test)) { return 0; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Experimentation)) { return 4; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Assurance) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Vow)) { return 6; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Offense) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.March) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Embrion)) { return 8; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Adamance)) { return 10; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Rend) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Dine)) { return 12; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Titan) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Artifice) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Liquidation)) { return 14; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Paid)) { return 10; } ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Free); return 6; } internal static float GetDungeonMultiplier(DawnDungeonInfo dungeon) { if (dungeon == null) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlow) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowThreeExits) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowExtraLarge) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Industrial) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Mechanical) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Factory)) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MansionFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Gothic) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Grand) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Ornate)) { return 0.75f; } if (!KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MineshaftFlow) && !((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Cavern) && !((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Quarry)) { ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Flooded); } return 0.5f; } private int Scale(int moonWeight, float dungeonMultiplier) { float num = Mathf.Clamp(_multiplier(), 0f, 5f); return Mathf.Clamp(Mathf.RoundToInt((float)moonWeight * dungeonMultiplier * num), 0, 100); } private static bool KeyEquals<T>(NamespacedKey<T> left, NamespacedKey<T> right) where T : INamespaced { if (left != null && right != null) { return ((object)left).Equals((object?)right); } return false; } } internal static class HarmonicTuning { internal const float ModelScale = 0.72f; internal const float Acceleration = 4.5f; internal const float AngularSpeed = 70f; internal const float HoverHeight = 0.55f; internal const float RoamSearchWidth = 120f; internal const float RoamSearchPrecision = 8f; internal const float RoamStuckRecoverySeconds = 3.5f; internal const float MovementBobAmount = 0.06f; internal const float MovementTiltDegrees = 4f; internal const float BodyColliderRadius = 0.32f; internal const float BodyColliderHeight = 1.25f; internal const float AlarmRefreshSeconds = 0.35f; internal const float HitInflateAmount = 0.13f; internal const float DeathEffectScale = 0.75f; internal const float IdlePulseRate = 0.42f; internal const float WarningPulseRate = 1.55f; internal const float PitchPulseAmount = 0.025f; internal const float VolumePulseAmount = 0.08f; internal const float WarningPitchMultiplier = 1.18f; internal const float AnimationPulseAmount = 0f; internal const float HornPulseScale = 0.06f; internal const float LightBaseIntensity = 45f; internal const float LightPulseIntensity = 35f; internal const float LightRange = 8.5f; internal const float EmissionIntensity = 0.22f; } [BepInPlugin("y4ngz.lethalcompany.harmonic", "Y4NGZ Harmonic", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal const string BundleFilename = "harmonic.bundle"; internal const string PrefabName = "Harmonic"; internal const string DeathEffectName = "DustExplosion"; internal const string AudioFolderName = "Harmonic"; internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "harmonic"; internal const string BestiaryText = "Harmonic\n\nDanger level: ambient\n\nA passive floating organism that wanders facilities while playing warped music. Its alarm call can briefly draw other creatures toward its location.\n\n"; internal static ManualLogSource Log; private static bool _loggedScanNodeLayer; internal static HarmonicConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType EnemyType; internal static string AssemblyDirectory; internal static AudioClip[] IdleMusicClips = Array.Empty<AudioClip>(); internal static AudioClip AlarmClip; internal static AudioClip DeathClip; internal static AudioClip DeathPopClip; internal static AudioClip[] HitClips = Array.Empty<AudioClip>(); internal static GameObject DeathEffectPrefab; private const float MusicMaxAudibleDistance = 65f; private const float SfxMaxAudibleDistance = 42f; private static bool _netcodeInitialized; private static Material _fallbackVisibleMaterial; private static Material _fallbackParticleMaterial; private static Texture2D _runtimeParticleTexture; private static readonly Color RuntimeParticleDustColor = new Color(0.52f, 0.5f, 0.46f, 0.72f); private static readonly Dictionary<Texture, Material> RuntimeVisualMaterials = new Dictionary<Texture, Material>(); private static readonly Dictionary<Material, Material> RuntimeParticleMaterials = new Dictionary<Material, Material>(); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new HarmonicConfig(((BaseUnityPlugin)this).Config); AssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Harmonic is disabled by config."); } else { if (!LoadBundle()) { return; } DeathEffectPrefab = LoadDeathEffectPrefab(); GameObject val = LoadBundlePrefab(); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Prefab 'Harmonic' not found in harmonic.bundle. Refusing to load fallback/legacy visuals."); DumpBundleAssets(); return; } PreparePrefab(val); EnemyType = CreateEnemyType(val); HarmonicAI component = val.GetComponent<HarmonicAI>(); if ((Object)(object)component != (Object)null) { ((EnemyAI)component).enemyType = EnemyType; } RegisterWithDawn(val); ((MonoBehaviour)this).StartCoroutine(LoadLooseAudioAsync(val)); Log.LogInfo((object)"Y4NGZ Harmonic v0.1.0 loaded. Registered as 'Harmonic'."); } } catch (Exception arg) { Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Harmonic", arg)); } } private static void RegisterWithDawn(GameObject prefab) { HarmonicSpawnWeights spawnWeights = new HarmonicSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(prefab); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "harmonic"), EnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Harmonic\n\nDanger level: ambient\n\nA passive floating organism that wanders facilities while playing warped music. Its alarm call can briefly draw other creatures toward its location.\n\n").CreateNameKeyword("harmonic")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[3] { Tags.Passive, Tags.Organic, Tags.Killable }); }); } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0) { continue; } try { methodInfo.Invoke(null, null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message)); } } } } } private static bool LoadBundle() { if (string.IsNullOrEmpty(AssemblyDirectory)) { Log.LogError((object)"Could not resolve plugin assembly directory."); return false; } string text = Path.Combine(AssemblyDirectory, "harmonic.bundle"); if (!File.Exists(text)) { Log.LogError((object)("Missing asset bundle: " + text)); return false; } ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + ".")); return false; } return true; } private static GameObject LoadBundlePrefab() { string[] array = new string[4] { "Harmonic", "Y4NGZHarmonic", "AF_45", "Alien flora 45" }; for (int i = 0; i < array.Length; i++) { GameObject val = ModAssets.LoadAsset<GameObject>(array[i]); if ((Object)(object)val != (Object)null) { return val; } } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { string text2 = text.Replace('\\', '/'); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (text2.EndsWith("/harmonic.prefab", StringComparison.OrdinalIgnoreCase) || text2.EndsWith("/y4ngzharmonic.prefab", StringComparison.OrdinalIgnoreCase) || text2.EndsWith("/af_45.prefab", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "Harmonic", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "AF_45", StringComparison.OrdinalIgnoreCase)) { GameObject val2 = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } private static GameObject LoadDeathEffectPrefab() { string[] array = new string[2] { "DustExplosion", "DustExplosion.prefab" }; for (int i = 0; i < array.Length; i++) { GameObject val = ModAssets.LoadAsset<GameObject>(array[i]); if ((Object)(object)val != (Object)null) { return val; } } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { string text2 = text.Replace('\\', '/'); if (text2.EndsWith("/dustexplosion.prefab", StringComparison.OrdinalIgnoreCase) || string.Equals(Path.GetFileNameWithoutExtension(text2), "DustExplosion", StringComparison.OrdinalIgnoreCase)) { GameObject val2 = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val2 != (Object)null) { return val2; } } } Log.LogWarning((object)"[Harmonic] Death effect 'DustExplosion' not found in harmonic.bundle; death pop will hide the creature without particles."); return null; } private IEnumerator LoadLooseAudioAsync(GameObject prefab) { string audioDir = Path.Combine(AssemblyDirectory ?? string.Empty, "assets", "Harmonic"); if (!Directory.Exists(audioDir)) { Log.LogWarning((object)("[Harmonic] Audio directory not found: " + audioDir)); yield break; } List<AudioClip> idle = new List<AudioClip>(); string path = Path.Combine(audioDir, "idle music"); if (Directory.Exists(path)) { string[] idleFiles = Directory.GetFiles(path, "*.mp3", SearchOption.TopDirectoryOnly); Array.Sort(idleFiles, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); for (int i = 0; i < idleFiles.Length; i++) { AudioClip loaded = null; yield return LoadAudioClipCoroutine(idleFiles[i], delegate(AudioClip clip) { loaded = clip; }); if ((Object)(object)loaded != (Object)null) { idle.Add(loaded); } } } IdleMusicClips = idle.ToArray(); yield return LoadAudioClipCoroutine(Path.Combine(audioDir, "alarm.mp3"), delegate(AudioClip clip) { AlarmClip = clip; }); yield return LoadAudioClipCoroutine(Path.Combine(audioDir, "death.wav"), delegate(AudioClip clip) { DeathClip = clip; }); yield return LoadAudioClipCoroutine(Path.Combine(audioDir, "pop.mp3"), delegate(AudioClip clip) { DeathPopClip = clip; }); List<AudioClip> hits = new List<AudioClip>(); string[] hitNames = new string[3] { "hit01.wav", "hit02.wav", "hit03.wav" }; for (int i = 0; i < hitNames.Length; i++) { AudioClip loaded2 = null; yield return LoadAudioClipCoroutine(Path.Combine(audioDir, hitNames[i]), delegate(AudioClip clip) { loaded2 = clip; }); if ((Object)(object)loaded2 != (Object)null) { hits.Add(loaded2); } } HitClips = hits.ToArray(); ApplyAudioToPrefab(prefab); RefreshSpawnedHarmonics(); Log.LogInfo((object)$"[Harmonic] Audio loaded. idle={IdleMusicClips.Length}, alarm={(Object)(object)AlarmClip != (Object)null}, death={(Object)(object)DeathClip != (Object)null}, pop={(Object)(object)DeathPopClip != (Object)null}, hits={HitClips.Length}."); } private IEnumerator LoadAudioClipCoroutine(string path, Action<AudioClip> onLoaded) { if (!File.Exists(path)) { Log.LogWarning((object)("[Harmonic] Audio file not found: " + path)); yield break; } AudioType val = ResolveAudioType(path); string text = "file:///" + path.Replace('\\', '/'); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, val); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Log.LogWarning((object)("[Harmonic] Failed to load audio " + path + ": " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content != (Object)null) { ((Object)content).name = Path.GetFileNameWithoutExtension(path); } onLoaded?.Invoke(content); } finally { ((IDisposable)request)?.Dispose(); } } private static AudioType ResolveAudioType(string path) { string extension = Path.GetExtension(path); if (!string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase)) { if (!string.Equals(extension, ".wav", StringComparison.OrdinalIgnoreCase)) { return (AudioType)0; } return (AudioType)20; } return (AudioType)13; } private static void ApplyAudioToPrefab(GameObject prefab) { HarmonicAI harmonicAI = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<HarmonicAI>() : null); if (!((Object)(object)harmonicAI == (Object)null)) { harmonicAI.idleMusicClips = IdleMusicClips; harmonicAI.alarmClip = AlarmClip; harmonicAI.deathClip = DeathClip; harmonicAI.deathPopClip = DeathPopClip; harmonicAI.hitClips = HitClips; harmonicAI.deathEffectPrefab = DeathEffectPrefab; } } private static void RefreshSpawnedHarmonics() { HarmonicAI[] array = Object.FindObjectsOfType<HarmonicAI>(); for (int i = 0; i < array.Length; i++) { array[i].RefreshClipsFromPlugin(); } } private static void PreparePrefab(GameObject prefab) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) AssignUniqueNetworkHash(prefab, "Harmonic"); TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); prefab.transform.localScale = Vector3.one * 0.72f; NetworkObject val = prefab.GetComponent<NetworkObject>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NetworkObject>(); } val.SynchronizeTransform = true; if ((Object)(object)prefab.GetComponent<NetworkTransform>() == (Object)null) { prefab.AddComponent<NetworkTransform>(); } HarmonicAI harmonicAI = prefab.GetComponent<HarmonicAI>(); if ((Object)(object)harmonicAI == (Object)null) { harmonicAI = prefab.AddComponent<HarmonicAI>(); } Animator val2 = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true); if ((Object)(object)val2 != (Object)null) { val2.applyRootMotion = false; val2.cullingMode = (AnimatorCullingMode)0; ((EnemyAI)harmonicAI).creatureAnimator = val2; } NavMeshAgent val3 = prefab.GetComponent<NavMeshAgent>() ?? prefab.GetComponentInChildren<NavMeshAgent>(true); if ((Object)(object)val3 == (Object)null) { val3 = prefab.AddComponent<NavMeshAgent>(); } ((EnemyAI)harmonicAI).agent = val3; ConfigureAgent(val3); harmonicAI.visualRoot = FindBestVisualRoot(prefab.transform); ((EnemyAI)harmonicAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 0.35f, 0.2f)); harmonicAI.musicSource = FindOrCreateAudioSource(prefab.transform, "HarmonicMusic", ModConfig.MusicMaxDistance.Value); harmonicAI.sfxSource = FindOrCreateAudioSource(prefab.transform, "HarmonicSFX", ModConfig.SfxMaxDistance.Value); harmonicAI.glowLight = FindOrCreateLight(prefab.transform); harmonicAI.deathEffectPrefab = DeathEffectPrefab; EnsureScanNode(prefab); EnsureCollision(prefab, harmonicAI); EnsureBehaviourStates(harmonicAI); RepairRuntimePresentation(prefab, "prefab", logDiagnostics: true); } internal static void ConfigureAgent(NavMeshAgent agent) { if (!((Object)(object)agent == (Object)null)) { agent.speed = Mathf.Max(0.1f, ModConfig.MoveSpeed.Value); agent.acceleration = 4.5f; agent.angularSpeed = 70f; agent.stoppingDistance = 0.55f; agent.radius = 0.32f; agent.height = 1.25f; agent.baseOffset = 0f; agent.autoBraking = true; agent.autoRepath = true; agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; agent.avoidancePriority = 55; } } private static void EnsureBehaviourStates(HarmonicAI ai) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown ((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[3] { new EnemyBehaviourState { name = "Roaming", IsAnimTrigger = false, parameterString = "Moving", boolValue = true }, new EnemyBehaviourState { name = "Alarm", IsAnimTrigger = false, parameterString = "Moving", boolValue = true }, new EnemyBehaviourState { name = "Dead", IsAnimTrigger = true, parameterString = "Death" } }; ((EnemyAI)ai).currentBehaviourStateIndex = 0; ((EnemyAI)ai).previousBehaviourStateIndex = 0; ((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0]; } internal static int RepairRuntimePresentation(GameObject root, string context, bool logDiagnostics) { if ((Object)(object)root == (Object)null) { return 0; } TrySetTag(root, "Enemy"); TrySetLayer(root, "Enemies"); int num = PrepareRenderers(root); EnsureScanNode(root); EnsureCollision(root, root.GetComponent<HarmonicAI>()); Animator val = root.GetComponent<Animator>() ?? root.GetComponentInChildren<Animator>(true); if ((Object)(object)val != (Object)null) { val.cullingMode = (AnimatorCullingMode)0; } if (logDiagnostics) { LogPresentationDiagnostics(root, context, num); } return num; } internal static void EnsureScanNode(GameObject prefab) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { if ((Object)(object)val == (Object)null || (val2.creatureScanID >= 0 && val.creatureScanID < 0) || (val2.creatureScanID == val.creatureScanID && ((Object)((Component)val2).gameObject).name == "ScanNode" && ((Object)((Component)val).gameObject).name != "ScanNode")) { val = val2; } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Harmonic] Found {componentsInChildren.Length} scan nodes; repairing the preferred existing node without creating another."); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", ResolveScanNodeLocalPosition(prefab))); TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)($"[Harmonic] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } } BoxCollider obj = ((Component)val3).GetComponent<BoxCollider>() ?? ((Component)val3).gameObject.AddComponent<BoxCollider>(); ((Collider)obj).enabled = true; ((Collider)obj).isTrigger = true; obj.center = Vector3.zero; obj.size = new Vector3(2.4f, 2.4f, 2.4f); Rigidbody obj2 = ((Component)val3).GetComponent<Rigidbody>() ?? ((Component)val3).gameObject.AddComponent<Rigidbody>(); obj2.isKinematic = true; obj2.useGravity = false; obj2.detectCollisions = true; val = val ?? ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); val.headerText = "Harmonic"; val.subText = "Creature"; val.maxRange = 18; val.minRange = 1; val.requiresLineOfSight = true; val.nodeType = 1; } private static Vector3 ResolveScanNodeLocalPosition(GameObject prefab) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab != (Object)null && TryGetRendererBounds(prefab, out var bounds)) { Vector3 val = ((Bounds)(ref bounds)).center + Vector3.up * Mathf.Clamp(((Bounds)(ref bounds)).extents.y * 0.2f, 0.25f, 0.85f); return prefab.transform.InverseTransformPoint(val); } return new Vector3(0f, 1.15f, 0f); } internal static void EnsureCollision(GameObject prefab, HarmonicAI ai) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) ResolveCollisionShape(prefab, out var center, out var radius, out var height); CapsuleCollider obj = prefab.GetComponent<CapsuleCollider>() ?? prefab.AddComponent<CapsuleCollider>(); ((Collider)obj).enabled = true; ((Collider)obj).isTrigger = false; obj.direction = 1; obj.center = center; obj.radius = radius; obj.height = height; Rigidbody obj2 = prefab.GetComponent<Rigidbody>() ?? prefab.AddComponent<Rigidbody>(); obj2.isKinematic = true; obj2.useGravity = false; obj2.detectCollisions = true; Transform val = FindOrCreateChild(prefab.transform, "Collision", Vector3.zero); ((Component)val).gameObject.SetActive(true); TrySetTag(((Component)val).gameObject, "Enemy"); TrySetLayer(((Component)val).gameObject, "Enemies"); CapsuleCollider obj3 = ((Component)val).GetComponent<CapsuleCollider>() ?? ((Component)val).gameObject.AddComponent<CapsuleCollider>(); ((Collider)obj3).enabled = true; ((Collider)obj3).isTrigger = true; obj3.direction = 1; obj3.center = center; obj3.radius = radius * 1.15f; obj3.height = height * 1.12f; Rigidbody obj4 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>(); obj4.isKinematic = true; obj4.useGravity = false; obj4.detectCollisions = true; if ((Object)(object)ai != (Object)null) { EnemyAICollisionDetect obj5 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>(); obj5.mainScript = (EnemyAI)(object)ai; obj5.alwaysAllowHitting = true; obj5.canCollideWithEnemies = true; obj5.onlyCollideWhenGrounded = false; } DisableRenderers(val); } private static void ResolveCollisionShape(GameObject root, out Vector3 center, out float radius, out float height) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) radius = 0.32f; height = 1.25f; center = new Vector3(0f, Mathf.Max(0.45f, height * 0.5f), 0f); if (TryGetRendererBounds(root, out var bounds)) { Vector3 val = root.transform.InverseTransformPoint(((Bounds)(ref bounds)).center); float num = Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); radius = Mathf.Clamp(Mathf.Max(radius, num * 0.22f), 0.1f, 0.75f); height = Mathf.Clamp(Mathf.Max(height, ((Bounds)(ref bounds)).size.y * 0.55f), 0.65f, 2.4f); center = new Vector3(0f, Mathf.Clamp(val.y, height * 0.45f, height * 1.1f), 0f); } } private static int PrepareRenderers(GameObject prefab) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); int num = 0; foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !IsHelperRenderer(val)) { EnsureHierarchyActive(((Component)val).transform, prefab.transform); ((Component)val).gameObject.layer = 0; val.enabled = true; val.forceRenderingOff = false; val.allowOcclusionWhenDynamic = false; val.shadowCastingMode = (ShadowCastingMode)1; val.receiveShadows = true; EnsureVisibleMaterials(val); SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); if ((Object)(object)val2 != (Object)null) { val2.updateWhenOffscreen = true; ((Renderer)val2).localBounds = new Bounds(new Vector3(0f, 1f, 0f), Vector3.one * 12f); } num++; } } return num; } private static EnemyType CreateEnemyType(GameObject prefab) { EnemyType obj = ScriptableObject.CreateInstance<EnemyType>(); obj.enemyName = "Harmonic"; obj.enemyPrefab = prefab; obj.PowerLevel = ModConfig.PowerLevel.Value; obj.DiversityPowerLevel = 1; obj.MaxCount = Mathf.Max(1, ModConfig.MaxCount.Value); obj.canDie = true; obj.canBeStunned = true; obj.canBeDestroyed = true; obj.stunTimeMultiplier = 1f; obj.stunGameDifficultyMultiplier = 1f; obj.destroyOnDeath = false; obj.doorSpeedMultiplier = 1f; obj.isOutsideEnemy = false; obj.isDaytimeEnemy = false; obj.pushPlayerDistance = 0f; obj.pushPlayerForce = 0f; obj.normalizedTimeInDayToLeave = 1f; obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f); obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0f); obj.useNumberSpawnedFalloff = true; obj.disableAnimatorWhenFar = false; return obj; } private static AudioSource FindOrCreateAudioSource(Transform parent, string childName, float maxDistance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(parent, childName, Vector3.zero); AudioSource val2 = ((Component)val).GetComponent<AudioSource>() ?? ((Component)val).gameObject.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.spatialBlend = 1f; val2.rolloffMode = (AudioRolloffMode)0; val2.minDistance = 4f; float num = (string.Equals(childName, "HarmonicMusic", StringComparison.OrdinalIgnoreCase) ? 65f : 42f); val2.maxDistance = Mathf.Clamp(maxDistance, 8f, num); val2.dopplerLevel = 0f; val2.spread = 55f; if ((Object)(object)((Component)val2).GetComponent<AudioLowPassFilter>() == (Object)null) { ((Component)val2).gameObject.AddComponent<AudioLowPassFilter>(); } return val2; } private static Light FindOrCreateLight(Transform parent) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(parent, "HarmonicLight", new Vector3(0f, 1.1f, 0f)); Light obj = ((Component)val).GetComponent<Light>() ?? ((Component)val).gameObject.AddComponent<Light>(); obj.type = (LightType)2; obj.color = new Color(0.34f, 0.24f, 1f, 1f); obj.intensity = 45f; obj.range = 8.5f; obj.shadows = (LightShadows)0; obj.renderMode = (LightRenderMode)1; return obj; } private static Transform FindBestVisualRoot(Transform root) { Transform val = FindChildRecursive(root, "VisualRoot") ?? FindChildRecursive(root, "Armature") ?? FindChildRecursive(root, "HarmonicModel_AF_45") ?? FindChildRecursive(root, "AF_45"); if ((Object)(object)val != (Object)null) { return val; } Renderer componentInChildren = ((Component)root).GetComponentInChildren<Renderer>(true); if ((Object)(object)componentInChildren == (Object)null) { return root; } Transform val2 = ((Component)componentInChildren).transform; while ((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)root) { val2 = val2.parent; } return val2; } internal static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); val.localPosition = localPosition; val.localRotation = Quaternion.identity; val.localScale = Vector3.one; return val; } val = new GameObject(name).transform; val.SetParent(parent, false); val.localPosition = localPosition; val.localRotation = Quaternion.identity; val.localScale = Vector3.one; return val; } internal static Transform FindChildRecursive(Transform parent, string name) { if ((Object)(object)parent == (Object)null || string.IsNullOrWhiteSpace(name)) { return null; } if (string.Equals(((Object)parent).name, name, StringComparison.OrdinalIgnoreCase)) { return parent; } for (int i = 0; i < parent.childCount; i++) { Transform val = FindChildRecursive(parent.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void DisableRenderers(Transform root) { Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } } private static bool TryGetRendererBounds(GameObject root, out Bounds bounds) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) Renderer[] array = (((Object)(object)root != (Object)null) ? root.GetComponentsInChildren<Renderer>(true) : Array.Empty<Renderer>()); bounds = new Bounds(((Object)(object)root != (Object)null) ? root.transform.position : Vector3.zero, Vector3.zero); bool flag = false; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponentInParent<ScanNodeProperties>() != (Object)null)) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } return flag; } private static void EnsureVisibleMaterials(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return; } Material[] array = renderer.sharedMaterials; if (array == null || array.Length == 0) { array = (Material[])(object)new Material[1] { GetOrCreateRuntimeVisibleMaterial(null) }; } bool flag = false; for (int i = 0; i < array.Length; i++) { Material val = array[i]; if (ShouldUseRuntimeMaterial(val)) { array[i] = GetOrCreateRuntimeVisibleMaterial(val); flag = true; } else { flag |= ForceOpaqueMaterial(val); } } if (flag) { renderer.sharedMaterials = array; } } private static bool ShouldUseRuntimeMaterial(Material material) { if ((Object)(object)material == (Object)null) { return true; } if (((Object)material).name.StartsWith("HarmonicRuntimeVisible", StringComparison.OrdinalIgnoreCase)) { return false; } ((Object)material).name.StartsWith("HarmonicVisible", StringComparison.OrdinalIgnoreCase); return ShouldReplaceShader(material.shader); } private static Material GetOrCreateRuntimeVisibleMaterial(Material source) { Texture baseTexture = GetBaseTexture(source); if ((Object)(object)baseTexture != (Object)null && RuntimeVisualMaterials.TryGetValue(baseTexture, out var value) && (Object)(object)value != (Object)null) { return value; } Material val = CreateRuntimeVisibleMaterial(source, baseTexture); if ((Object)(object)baseTexture != (Object)null) { RuntimeVisualMaterials[baseTexture] = val; } else { _fallbackVisibleMaterial = val; } return val; } private static Material CreateRuntimeVisibleMaterial(Material source, Texture texture) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00e7: Expected O, but got Unknown if ((Object)(object)texture == (Object)null && (Object)(object)_fallbackVisibleMaterial != (Object)null) { return _fallbackVisibleMaterial; } Shader val = FindVisibleShader(); Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(Shader.Find("Unlit/Color"))); ((Object)val2).name = (((Object)(object)texture != (Object)null) ? "HarmonicRuntimeVisible_Textured" : "HarmonicRuntimeVisible_Fallback"); ApplyBaseTexture(val2, texture); ApplyNormalTexture(val2, GetNormalTexture(source)); ApplyOcclusionTexture(val2, GetOcclusionTexture(source)); ApplyBaseColor(val2, (Color)(((Object)(object)source != (Object)null) ? GetBaseColor(source) : new Color(0.74f, 0.56f, 0.28f, 1f))); SetFloatIfPresent(val2, "_Metallic", 0f); SetFloatIfPresent(val2, "_Smoothness", 0.35f); SetFloatIfPresent(val2, "_Glossiness", 0.35f); ForceOpaqueMaterial(val2); return val2; } internal static void RepairParticleRenderers(GameObject root) { if ((Object)(object)root == (Object)null) { return; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if (!((Object)(object)val2 != (Object)null) || ShouldReplaceShader(val2.shader) || !((Object)(object)GetBaseTexture(val2) != (Object)null)) { sharedMaterials[j] = GetOrCreateRuntimeParticleMaterial(val2); flag = true; } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static Material GetOrCreateRuntimeParticleMaterial(Material source) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source != (Object)null && RuntimeParticleMaterials.TryGetValue(source, out var value) && (Object)(object)value != (Object)null) { return value; } if ((Object)(object)source == (Object)null && (Object)(object)_fallbackParticleMaterial != (Object)null) { return _fallbackParticleMaterial; } Shader val = FindRuntimeParticleShader(); if ((Object)(object)val == (Object)null) { return source; } Material val2 = new Material(val); ((Object)val2).name = "HarmonicRuntimeParticle"; ((Object)val2).hideFlags = (HideFlags)61; Texture texture = (Texture)(((object)GetBaseTexture(source)) ?? ((object)GetOrCreateRuntimeParticleTexture())); ApplyBaseTexture(val2, texture); ApplyParticleColor(val2, RuntimeParticleDustColor); MakeTransparentUnlit(val2); if ((Object)(object)source != (Object)null) { RuntimeParticleMaterials[source] = val2; } else { _fallbackParticleMaterial = val2; } return val2; } private static Shader FindRuntimeParticleShader() { string[] array = new string[3] { "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended", "Sprites/Default" }; for (int i = 0; i < array.Length; i++) { Shader val = Shader.Find(array[i]); if ((Object)(object)val != (Object)null && val.isSupported) { return val; } } Shader val2 = Shader.Find("HDRP/Unlit"); if ((Object)(object)val2 != (Object)null && val2.isSupported) { return val2; } return Shader.Find("Unlit/Transparent") ?? FindVisibleShader(); } private static Texture2D GetOrCreateRuntimeParticleTexture() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_runtimeParticleTexture != (Object)null) { return _runtimeParticleTexture; } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, true) { name = "HarmonicRuntimeDustSprite", hideFlags = (HideFlags)61, filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < 64; i++) { float num = ((float)i + 0.5f) / 64f * 2f - 1f; for (int j = 0; j < 64; j++) { float num2 = ((float)j + 0.5f) / 64f * 2f - 1f; float num3 = Mathf.Atan2(num, num2); float num4 = Mathf.Sqrt(num2 * num2 + num * num); float num5 = 0.94f + Mathf.Sin(num3 * 3f + 0.45f) * 0.045f + Mathf.Sin(num3 * 7f - 0.8f) * 0.025f; float num6 = Mathf.InverseLerp(0.08f, num5, num4); float num7 = Mathf.SmoothStep(1f, 0f, num6); float num8 = 0.88f + 0.08f * Mathf.Sin(num2 * 8.3f + num * 3.7f) + 0.04f * Mathf.Sin(num * 11.1f - num2 * 2.9f); byte b = (byte)Mathf.RoundToInt(Mathf.Clamp01(num7 * num8) * 255f); array[i * 64 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } val.SetPixels32(array); val.Apply(true, true); _runtimeParticleTexture = val; return val; } private static void ApplyParticleColor(Material material, Color color) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return; } string[] array = new string[4] { "_BaseColor", "_Color", "_TintColor", "_UnlitColor" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { material.SetColor(array[i], color); } } } private static void MakeTransparentUnlit(Material material) { SetFloatIfPresent(material, "_SurfaceType", 1f); SetFloatIfPresent(material, "_BlendMode", 0f); SetFloatIfPresent(material, "_AlphaCutoffEnable", 0f); SetFloatIfPresent(material, "_SrcBlend", 5f); SetFloatIfPresent(material, "_DstBlend", 10f); SetFloatIfPresent(material, "_AlphaSrcBlend", 5f); SetFloatIfPresent(material, "_AlphaDstBlend", 10f); SetFloatIfPresent(material, "_ZWrite", 0f); SetFloatIfPresent(material, "_TransparentZWrite", 0f); SetFloatIfPresent(material, "_ZTestDepthEqualForOpaque", 4f); SetFloatIfPresent(material, "_CullMode", 0f); SetFloatIfPresent(material, "_TransparentCullMode", 0f); material.SetOverrideTag("RenderType", "Transparent"); material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.EnableKeyword("_BLENDMODE_ALPHA"); material.EnableKeyword("_ALPHABLEND_ON"); material.EnableKeyword("_ENABLE_FOG_ON_TRANSPARENT"); material.DisableKeyword("_BLENDMODE_ADD"); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; if ((Object)(object)material.shader != (Object)null && ((Object)material.shader).name.StartsWith("HDRP/", StringComparison.OrdinalIgnoreCase)) { HDMaterial.ValidateMaterial(material); } } private static bool ShouldReplaceShader(Shader shader) { if (IsInvalidShader(shader)) { return true; } if (!shader.isSupported) { return true; } string text = ((Object)shader).name ?? string.Empty; if (!string.Equals(text, "Standard", StringComparison.OrdinalIgnoreCase)) { return text.IndexOf("Universal Render Pipeline", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool IsInvalidShader(Shader shader) { if ((Object)(object)shader == (Object)null) { return true; } return (((Object)shader).name ?? string.Empty).IndexOf("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase) >= 0; } private static Shader FindVisibleShader() { return Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit") ?? Shader.Find("Standard") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Unlit/Texture"); } private static Texture GetBaseTexture(Material material) { if ((Object)(object)material == (Object)null) { return null; } string[] array = new string[4] { "_BaseColorMap", "_UnlitColorMap", "_MainTex", "_BaseMap" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { Texture texture = material.GetTexture(array[i]); if (IsLikelyAlbedo(texture)) { return texture; } } } for (int j = 0; j < array.Length; j++) { if (material.HasProperty(array[j])) { Texture texture2 = material.GetTexture(array[j]); if ((Object)(object)texture2 != (Object)null && !IsLikelyUtilityMap(texture2)) { return texture2; } } } Texture val = FindTextureByName(material, "color", "albedo", "diffuse", "base"); if ((Object)(object)val != (Object)null) { return val; } return null; } private static void ApplyBaseTexture(Material material, Texture texture) { if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null) { return; } string[] array = new string[4] { "_BaseColorMap", "_UnlitColorMap", "_MainTex", "_BaseMap" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { material.SetTexture(array[i], texture); } } } private static Texture GetNormalTexture(Material material) { if ((Object)(object)material == (Object)null) { return null; } string[] array = new string[2] { "_NormalMap", "_BumpMap" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { Texture texture = material.GetTexture(array[i]); if ((Object)(object)texture != (Object)null) { return texture; } } } return FindTextureByName(material, "normal", "bump"); } private static void ApplyNormalTexture(Material material, Texture texture) { if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null) { return; } string[] array = new string[2] { "_NormalMap", "_BumpMap" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { material.SetTexture(array[i], texture); } } material.EnableKeyword("_NORMALMAP"); } private static Texture GetOcclusionTexture(Material material) { if ((Object)(object)material == (Object)null) { return null; } string[] array = new string[1] { "_OcclusionMap" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { Texture texture = material.GetTexture(array[i]); if ((Object)(object)texture != (Object)null) { return texture; } } } return FindTextureByName(material, "occlusion", "_ao", "ao"); } private static void ApplyOcclusionTexture(Material material, Texture texture) { if (!((Object)(object)material == (Object)null) && !((Object)(object)texture == (Object)null) && material.HasProperty("_OcclusionMap")) { material.SetTexture("_OcclusionMap", texture); } } private static Texture FindTextureByName(Material material, params string[] needles) { if ((Object)(object)material == (Object)null || needles == null || needles.Length == 0) { return null; } string[] array; try { array = material.GetTexturePropertyNames(); } catch { array = Array.Empty<string>(); } for (int i = 0; i < array.Length; i++) { if (!material.HasProperty(array[i])) { continue; } Texture texture = material.GetTexture(array[i]); if ((Object)(object)texture == (Object)null || string.IsNullOrEmpty(((Object)texture).name)) { continue; } string name = ((Object)texture).name; for (int j = 0; j < needles.Length; j++) { if (name.IndexOf(needles[j], StringComparison.OrdinalIgnoreCase) >= 0) { return texture; } } } return null; } private static bool IsLikelyAlbedo(Texture texture) { if ((Object)(object)texture == (Object)null || string.IsNullOrEmpty(((Object)texture).name)) { return (Object)(object)texture != (Object)null; } string name = ((Object)texture).name; if (name.IndexOf("color", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("albedo", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("diffuse", StringComparison.OrdinalIgnoreCase) < 0) { return name.IndexOf("base", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool IsLikelyUtilityMap(Texture texture) { if ((Object)(object)texture == (Object)null || string.IsNullOrEmpty(((Object)texture).name)) { return false; } string name = ((Object)texture).name; if (name.IndexOf("normal", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("bump", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("metal", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("rough", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("occlusion", StringComparison.OrdinalIgnoreCase) < 0) { return name.IndexOf("_ao", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static Color GetBaseColor(Material material) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return Color.white; } string[] array = new string[4] { "_BaseColor", "_Color", "_TintColor", "_UnlitColor" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { Color color = material.GetColor(array[i]); color.a = 1f; return color; } } return Color.white; } private static void ApplyBaseColor(Material material, Color color) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return; } color.a = 1f; string[] array = new string[4] { "_BaseColor", "_Color", "_TintColor", "_UnlitColor" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { material.SetColor(array[i], color); } } } private static bool ForceOpaqueMaterial(Material material) { int result = (int)(0u | (SetAlphaIfPresent(material, "_Color") ? 1u : 0u) | (SetAlphaIfPresent(material, "_BaseColor") ? 1u : 0u) | (SetAlphaIfPresent(material, "_TintColor") ? 1u : 0u) | (SetAlphaIfPresent(material, "_UnlitColor") ? 1u : 0u) | (SetFloatIfPresent(material, "_Mode", 0f) ? 1u : 0u) | (SetFloatIfPresent(material, "_SurfaceType", 0f) ? 1u : 0u) | (SetFloatIfPresent(material, "_SrcBlend", 1f) ? 1u : 0u) | (SetFloatIfPresent(material, "_DstBlend", 0f) ? 1u : 0u) | (SetFloatIfPresent(material, "_ZWrite", 1f) ? 1u : 0u)) | (SetFloatIfPresent(material, "_AlphaCutoffEnable", 0f) ? 1 : 0); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.renderQueue = -1; return (byte)result != 0; } private static bool SetAlphaIfPresent(Material material, string property) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || !material.HasProperty(property)) { return false; } Color color = material.GetColor(property); if (color.a >= 0.99f) { return false; } color.a = 1f; material.SetColor(property, color); return true; } private static bool SetFloatIfPresent(Material material, string property, float value) { if ((Object)(object)material == (Object)null || !material.HasProperty(property)) { return false; } if (Mathf.Approximately(material.GetFloat(property), value)) { return false; } material.SetFloat(property, value); return true; } private static void AssignUniqueNetworkHash(GameObject prefab, string key) { try { NetworkObject val = prefab.GetComponent<NetworkObject>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NetworkObject>(); } uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.harmonic." + key)), 0); PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(val, num); return; } FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (fieldInfo != null) { fieldInfo.SetValue(val, num); } } catch (Exception ex) { Log.LogWarning((object)("[Harmonic] Could not assign NetworkObject hash: " + ex.Message)); } } private static void TrySetTag(GameObject obj, string tag) { try { obj.tag = tag; } catch { } } internal static void TrySetLayer(GameObject obj, string layerName) { if ((Object)(object)obj == (Object)null) { return; } int num = LayerMask.NameToLayer(layerName); if (num < 0) { num = ResolveLayerFallback(layerName); } if (num >= 0 && num <= 31) { obj.layer = num; return; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Harmonic] Layer '{layerName}' unresolved; '{((Object)obj).name}' stays on layer {obj.layer}."); } } private static int ResolveLayerFallback(string layerName) { if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase)) { return 22; } if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase)) { return 19; } return -1; } private static void EnsureHierarchyActive(Transform child, Transform root) { Transform val = child; while ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); if (!((Object)(object)val == (Object)(object)root)) { val = val.parent; continue; } break; } } private static bool IsHelperRenderer(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return true; } if ((Object)(object)((Component)renderer).GetComponentInParent<ScanNodeProperties>() != (Object)null) { return true; } Transform val = ((Component)renderer).transform; while ((Object)(object)val != (Object)null) { if (string.Equals(((Object)val).name, "Collision", StringComparison.OrdinalIgnoreCase)) { return true; } val = val.parent; } return false; } private static void LogPresentationDiagnostics(GameObject root, string context, int repairedRenderers) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0216: 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_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null || Log == null) { return; } Renderer val = null; Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); int num = 0; int num2 = 0; int num3 = 0; foreach (Renderer val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !IsHelperRenderer(val2)) { num++; if (val2 is SkinnedMeshRenderer) { num2++; } else if (val2 is MeshRenderer) { num3++; } if ((Object)(object)val == (Object)null) { val = val2; } } } Transform val3 = root.transform.Find("ScanNode"); string text = (((Object)(object)val3 != (Object)null) ? $"scanLayer={((Component)val3).gameObject.layer}, scanActive={((Component)val3).gameObject.activeInHierarchy}, scanPos={val3.localPosition}" : "scan=missing"); string text2 = "material=<none>"; if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMaterial != (Object)null) { Material sharedMaterial = val.sharedMaterial; Texture baseTexture = GetBaseTexture(sharedMaterial); text2 = string.Format("material={0}/{1}, supported={2}, tex={3}", ((Object)sharedMaterial).name, ((Object)(object)sharedMaterial.shader != (Object)null) ? ((Object)sharedMaterial.shader).name : "<none>", (Object)(object)sharedMaterial.shader != (Object)null && sharedMaterial.shader.isSupported, ((Object)(object)baseTexture != (Object)null) ? ((Object)baseTexture).name : "<none>"); } CapsuleCollider component = root.GetComponent<CapsuleCollider>(); Transform val4 = root.transform.Find("Collision"); CapsuleCollider val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<CapsuleCollider>() : null); string text3 = (((Object)(object)component != (Object)null && (Object)(object)val5 != (Object)null) ? $"bodyCollider(center={component.center}, h={component.height:0.00}, r={component.radius:0.00}), hitbox(center={val5.center}, h={val5.height:0.00}, r={val5.radius:0.00})" : "collision=missing"); object obj; if (!((Object)(object)val != (Object)null)) { obj = "firstRenderer=<none>"; } else { object[] obj2 = new object[5] { GetHierarchyPath(root.transform, ((Component)val).transform), ((Component)val).gameObject.activeInHierarchy, val.enabled, ((Component)val).gameObject.layer, null }; Bounds bounds = val.bounds; obj2[4] = ((Bounds)(ref bounds)).size; obj = string.Format("firstRenderer='{0}', active={1}, enabled={2}, layer={3}, bounds={4}", obj2); } string text4 = (string)obj; Log.LogInfo((object)$"[Harmonic] Presentation repair ({context}): repaired={repairedRenderers}, renderers={num}, skinned={num2}, mesh={num3}, {text}, {text3}, {text4}, {text2}."); } private static string GetHierarchyPath(Transform root, Transform child) { if ((Object)(object)child == (Object)null) { return "<null>"; } List<string> list = new List<string>(); Transform val = child; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } val = val.parent; } list.Reverse(); return string.Join("/", list); } private static void DumpBundleAssets() { if (!((Object)(object)ModAssets == (Object)null)) { string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { Log.LogError((object)(" - " + text)); } } } } internal static class PluginInfo { public const string PLUGIN_GUID = "y4ngz.lethalcompany.harmonic"; public const string PLUGIN_NAME = "Y4NGZ Harmonic"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace Y4NGZHarmonic.AI { public sealed class HarmonicAI : EnemyAI { private sealed class HornPulseTarget { public readonly Transform Transform; public readonly Vector3 BaseScale; public HornPulseTarget(Transform transform) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Transform = transform; BaseScale = (((Object)(object)transform != (Object)null) ? transform.localScale : Vector3.one); } } private struct AlarmedEnemyState { public PlayerControllerB TargetPlayer; public int BehaviourStateIndex; } public const int StateRoaming = 0; public const int StateAlarm = 1; public const int StateDead = 2; private const int LocalTrackNone = 0; private const int LocalTrackIdle = 1; private const int LocalTrackAlarm = 2; private const float MusicOutputMultiplier = 1f; private const float AlarmOutputMultiplier = 1f; private const float SfxOutputMultiplier = 1f; private const float MusicMaxAudibleDistance = 65f; private const float SfxMaxAudibleDistance = 42f; private const float ClearAudioCutoff = 22000f; private const float DistantAudioCutoff = 6500f; private const float ObstructedAudioCutoff = 2400f; private const float DamageStunFreezeSeconds = 1f; private const float AlarmArrivalReleaseRadius = 4f; private const float AlarmArrivalReleaseImmunitySeconds = 1f; private static readonly int MovingHash = Animator.StringToHash("Moving"); private static readonly string[] IdleAnimationStates = new string[4] { "Idle_1", "Idle_2", "Idle_3", "Idle_4" }; private static readonly string[] HornPulseBoneNames = new string[6] { "JNT_Trumpet_a4", "JNT_Trumpet_b4", "JNT_Trumpet_c4", "JNT_Trumpet_d4", "JNT_Trumpet_e4", "JNT_Trumpet_f4" }; public AISearchRoutine facilitySearch = new AISearchRoutine(); public Transform visualRoot; public AudioSource musicSource; public AudioSource sfxSource; public Light glowLight; public AudioClip[] idleMusicClips; public AudioClip alarmClip; public AudioClip deathClip; public AudioClip deathPopClip; public AudioClip[] hitClips; public GameObject deathEffectPrefab; private readonly Dictionary<EnemyAI, AlarmedEnemyState> _alarmedEnemies = new Dictionary<EnemyAI, AlarmedEnemyState>(); private readonly Dictionary<EnemyAI, float> _alarmReleaseImmunityUntil = new Dictionary<EnemyAI, float>(); private readonly List<Material> _runtimeMaterials = new List<Material>(); private readonly List<HornPulseTarget> _hornPulseTargets = new List<HornPulseTarget>(); private readonly RaycastHit[] _audioOcclusionHits = (RaycastHit[])(object)new RaycastHit[8]; private Coroutine _serverMusicRoutine; private Coroutine _localPlaybackRoutine; private Vector3 _visualBaseLocalPosition; private Vector3 _visualBaseLocalScale = Vector3.one; private Vector3 _lastMovementCheckPosition; private Quaternion _visualBaseLocalRotation = Quaternion.identity; private float _visualLocalMinY; private float _visualLocalMaxY; private float _visualHoverVelocity; private float _hornPulseAmount; private float _hornPulseVelocity; private float _desiredHornPulseAmount; private float _targetHitInflateAmount; private float _hitInflateAmount; private float _hitInflateVelocity; private float _pulsePhase; private float _localClipStartedAt; private float _localClipDuration; private float _deathFadeStartedAt = -1f; private float _stuckTimer; private float _nextSearchRepairTime; private float _nextAlarmRefreshTime; private float _nextAudioOcclusionUpdateTime; private float _nextNavMeshRepairTime; private float _nextPresentationRepairTime; private float _damageStunUntil; private float _preDamageStunAnimatorSpeed = 1f; private int _lastIdleIndex = -1; private int _localPlaybackToken; private int _localTrackKind; private string _currentAnimationState; private AudioLowPassFilter _musicLowPass; private AudioLowPassFilter _sfxLowPass; private Coroutine _deathPresentationRoutine; private bool _hasCapturedVisualBase; private bool _hasVisualBounds; private bool _hornPulseTargetsScanned; private bool _hasMovingParameter; private bool _localWarningRamp; private bool _serverAlarmActive; private bool _deathSent; private bool _deathBodyHidden; private bool _presentationLogged; private bool _damageStunFrozen; private int Health => Plugin.ModConfig?.Health.Value ?? 4; private float AlarmChance => Mathf.Clamp01(Plugin.ModConfig?.AlarmChance.Value ?? 0.2f); private float AlarmRefreshSeconds => 0.35f; private float AlarmAttractionRadius => Mathf.Max(0f, Plugin.ModConfig?.AlarmAttractionRadius.Value ?? 30f); private float IdleVolume => Mathf.Clamp01(Plugin.ModConfig?.MusicVolume.Value ?? 0.95f); private float AlarmVolume => Mathf.Clamp01(Plugin.ModConfig?.SfxVolume.Value ?? 1f); private float HitVolume => Mathf.Clamp01(Plugin.ModConfig?.SfxVolume.Value ?? 1f); private float DeathVolume => Mathf.Clamp01(Plugin.ModConfig?.SfxVolume.Value ?? 1f); private float PulseRate => 0.42f; private float WarningPulseRate => 1.55f; private float PitchPulseAmount => 0.025f; private float VolumePulseAmount => 0.08f; private float WarningPitchMultiplier => 1.18f; private float AnimationPulseAmount => 0f; private float HoverHeight => 0.55f; private float MaxHitInflateAmount => 0.13f; private float DeathEffectScale => 0.75f; private float RoamSearchWidth => 120f; private float RoamSearchPrecision => 8f; private float RoamStuckRecoverySeconds => 3.5f; private float MovementBobAmount => 0.06f; private float MovementTiltDegrees => 4f; private float HornPulseScale => 0.06f; private float LightBaseIntensity => 45f; private float LightPulseIntensity => 35f; private float LightRange => 8.5f; private float EmissionIntensity => 0.22f; private bool DebugLogs => Plugin.ModConfig?.DebugLogs.Value ?? false; public override void Awake() { try { ((EnemyAI)this).Awake(); ResolveReferences(); ConfigureSearchDefaults(); EnsureRuntimePresentation(force: true); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] Awake failed: {arg}"); } } } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); ResolveReferences(); EnsureRuntimePresentation(force: true); CaptureRuntimeMaterials(); } public override void Start() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) try { ResolveReferences(); ConfigureSearchDefaults(); EnsureRuntimePresentation(force: true); CaptureRuntimeMaterials(); ConfigureAgent(); if (((NetworkBehaviour)this).IsServer) { SnapToInteriorNavMeshIfNeeded(logAlways: true); } ((EnemyAI)this).Start(); base.enemyHP = Health; _pulsePhase = Random.Range(0f, 1000f); _lastMovementCheckPosition = ((Component)this).transform.position; if (((NetworkBehaviour)this).IsServer) { SwitchState(0); EnsureRoamingSearch(); RestartMusicLoop(); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] Start failed: {arg}"); } } } public override void Update() { try { ((EnemyAI)this).Update(); ResolveReferences(); EnsureRuntimePresentation(force: false); if (!ApplyDamageStunFreeze()) { if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead) { ConfigureAgent(); RepairOffNavMeshIfNeeded(); TickRoamingSearch(Time.deltaTime); TickAlarmAttraction(); } TickLocalPulse(); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] Update failed: {arg}"); } } } private void LateUpdate() { try { if (!ApplyDamageStunFreeze()) { ApplyHornPulse(Time.deltaTime); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] LateUpdate failed: {arg}"); } } } public override void DoAIInterval() { try { if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead) { ConfigureAgent(); RepairOffNavMeshIfNeeded(); if ((Object)(object)base.agent == (Object)null || !((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh) { return; } } ((EnemyAI)this).DoAIInterval(); if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && (base.currentBehaviourStateIndex == 0 || base.currentBehaviourStateIndex == 1)) { ConfigureAgent(); RepairOffNavMeshIfNeeded(); EnsureRoamingSearch(); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] DoAIInterval failed: {arg}"); } } } public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { try { ((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID); if (base.isEnemyDead) { return; } BeginDamageStunFreeze(); if (((NetworkBehaviour)this).IsServer) { int num = Mathf.Max(1, force); base.enemyHP -= num; if (base.enemyHP <= 0) { DieFromDamage(); return; } PlayHitClientRpc(PickHitClipIndex(), Random.Range(0.92f, 1.08f), CalculateHitInflateAmount(base.enemyHP)); RestartMusicLoop(); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[HarmonicAI] HitEnemy failed: {arg}"); } } } public override void KillEnemy(bool destroy = false) { StopServerMusicLoop(); EndAlarmAttraction(); StopLocalMusic(); if ((Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.speed = 1f; } ClearDamageStunFreeze(); ((EnemyAI)this).KillEnemy(destroy); base.isEnemyDead = true; } public override void OnDestroy() { StopServerMusicLoop(); EndAlarmAttraction(); if (_deathPresentationRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_deathPresentationRoutine); _deathPresentationRoutine = null; } DestroyRuntimeMaterials(); ((EnemyAI)this).OnDestroy(); } public void RefreshClip
Y4NGZPoltergeist.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations; using UnityEngine.Audio; using UnityEngine.Networking; using UnityEngine.Playables; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Y4NGZMonsters.Shared; using Y4NGZPoltergeist.AI; using Y4NGZPoltergeist.NetcodePatcher; using Y4NGZPoltergeist.Patches; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZPoltergeist")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZPoltergeist")] [assembly: AssemblyTitle("Y4NGZPoltergeist")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZPoltergeist { [BepInPlugin("y4ngz.lethalcompany.poltergeist", "Y4NGZ Poltergeist", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal const string BundleFilename = "y4ngzpoltergeist.bundle"; internal const string PrefabName = "Poltergeist"; internal const string AlternatePrefabName = "thc3"; internal const string DisplayName = "Passenger"; internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "passenger"; internal const string ScanNodeSubtitle = ""; internal const string BestiaryText = "Passenger\n\nDanger level: high\n\nAn intangible facility resident that ignores walls entirely, drifting through them to reach a worker it has chosen. Its claws are survivable. What follows them is not: a sufficiently wounded worker can be worn like a coat, and will turn on their own crew for as long as the thing keeps its grip. It does not enjoy being shot at, and leaves when it is.\n\n"; internal static ManualLogSource Log; private static bool _loggedScanNodeLayer; internal static PoltergeistConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType PoltergeistEnemyType; internal static readonly string[] BreachEffectNames = new string[3] { "PoltergeistBreach_Dark", "PoltergeistBreach_Portal", "PoltergeistBreach_Authored" }; internal static GameObject[] BreachEffectPrefabs; internal static GameObject PhaseAuraPrefab; internal static AudioClip PossessedLoopClip; internal const string LooseAudioFolderName = "Poltergeist"; private static AudioMixerGroup _diegeticMaster; private static bool _netcodeInitialized; private static readonly Dictionary<Material, Material> RuntimeParticleMaterials = new Dictionary<Material, Material>(); private void Awake() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new PoltergeistConfig(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Poltergeist is disabled in config; skipping registration."); return; } new Harmony("y4ngz.lethalcompany.poltergeist").PatchAll(typeof(Plugin).Assembly); if (!LoadBundle()) { return; } ((MonoBehaviour)this).StartCoroutine(LoadLoosePossessionAudio()); GameObject val = LoadBundlePrefab(); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Prefab 'Poltergeist' not found in y4ngzpoltergeist.bundle."); DumpBundleAssets(); return; } PreparePrefab(val); PoltergeistEnemyType = CreateEnemyType(val); PoltergeistAI component = val.GetComponent<PoltergeistAI>(); if ((Object)(object)component != (Object)null) { ((EnemyAI)component).enemyType = PoltergeistEnemyType; } PoltergeistSpawnWeights spawnWeights = new PoltergeistSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(val); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "passenger"), PoltergeistEnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Passenger\n\nDanger level: high\n\nAn intangible facility resident that ignores walls entirely, drifting through them to reach a worker it has chosen. Its claws are survivable. What follows them is not: a sufficiently wounded worker can be worn like a coat, and will turn on their own crew for as long as the thing keeps its grip. It does not enjoy being shot at, and leaves when it is.\n\n").CreateNameKeyword("passenger")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[5] { Tags.Hostile, Tags.Organic, Tags.Biped, Tags.Killable, Tags.Medium }); }); Log.LogInfo((object)"Y4NGZ Poltergeist v0.1.0 loaded. Registered as 'Passenger'."); } catch (Exception arg) { Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Poltergeist", arg)); } } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0) { continue; } try { methodInfo.Invoke(null, null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message)); } } } } } private static bool LoadBundle() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrEmpty(directoryName)) { Log.LogError((object)"Could not resolve plugin assembly directory."); return false; } string text = Path.Combine(directoryName, "y4ngzpoltergeist.bundle"); if (!File.Exists(text)) { Log.LogError((object)("Missing asset bundle: " + text)); return false; } ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + ".")); return false; } return true; } private IEnumerator LoadLoosePossessionAudio() { string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "assets", "Poltergeist"); if (!Directory.Exists(text)) { Log.LogWarning((object)("[PoltergeistAudio] Loose audio folder not found: " + text + ". The local possession loop will be silent.")); yield break; } yield return LoadLooseClip(Path.Combine(text, "plt_possession_loop_01.wav"), delegate(AudioClip clip) { PossessedLoopClip = clip; }); Log.LogInfo((object)$"[PoltergeistAudio] Local possession loop loaded: {(Object)(object)PossessedLoopClip != (Object)null}."); } private IEnumerator LoadLooseClip(string path, Action<AudioClip> onLoaded) { if (!File.Exists(path)) { Log.LogWarning((object)("[PoltergeistAudio] Audio file not found: " + path)); yield break; } string text = "file:///" + path.Replace('\\', '/'); AudioType val = (AudioType)(string.Equals(Path.GetExtension(path), ".ogg", StringComparison.OrdinalIgnoreCase) ? 14 : 20); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, val); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Log.LogWarning((object)("[PoltergeistAudio] Failed to load " + path + ": " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { yield break; } ((Object)content).name = Path.GetFileNameWithoutExtension(path); onLoaded(content); } finally { ((IDisposable)request)?.Dispose(); } } private static GameObject LoadBundlePrefab() { GameObject val = ModAssets.LoadAsset<GameObject>("Poltergeist") ?? ModAssets.LoadAsset<GameObject>("thc3"); if ((Object)(object)val != (Object)null) { return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text.Replace('\\', '/')); if (string.Equals(fileNameWithoutExtension, "Poltergeist", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "thc3", StringComparison.OrdinalIgnoreCase)) { val = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val != (Object)null) { return val; } } } return null; } private static void LoadPhaseEffectPrefabs() { BreachEffectPrefabs = (GameObject[])(object)new GameObject[BreachEffectNames.Length]; List<string> list = new List<string>(); for (int i = 0; i < BreachEffectNames.Length; i++) { BreachEffectPrefabs[i] = LoadBundleGameObject(BreachEffectNames[i]); if ((Object)(object)BreachEffectPrefabs[i] == (Object)null) { list.Add(BreachEffectNames[i]); } } PhaseAuraPrefab = LoadBundleGameObject("PoltergeistPhaseAura"); if ((Object)(object)PhaseAuraPrefab == (Object)null) { list.Add("PoltergeistPhaseAura"); } if (list.Count > 0) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[PoltergeistVFX] y4ngzpoltergeist.bundle is missing phase effect prefab(s): " + string.Join(", ", list) + ". Phasing keeps its material treatment and its light; those candidates will not spawn.")); } } else { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)$"[PoltergeistVFX] Loaded {BreachEffectPrefabs.Length} breach candidate(s) and the phase aura."); } } } private static GameObject LoadBundleGameObject(string name) { if ((Object)(object)ModAssets == (Object)null) { return null; } GameObject val = ModAssets.LoadAsset<GameObject>(name); if ((Object)(object)val != (Object)null) { return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { if (string.Equals(Path.GetFileNameWithoutExtension(text.Replace('\\', '/')), name, StringComparison.OrdinalIgnoreCase)) { GameObject val2 = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } internal static void RepairParticleRenderers(GameObject root, bool force = false) { if ((Object)(object)root == (Object)null) { return; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if (!((Object)(object)val2 == (Object)null) && (force || IsMaterialBroken(val2))) { sharedMaterials[j] = GetOrCreateRuntimeParticleMaterial(val2); flag = true; } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static Material GetOrCreateRuntimeParticleMaterial(Material source) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source != (Object)null && RuntimeParticleMaterials.TryGetValue(source, out var value) && (Object)(object)value != (Object)null) { return value; } Shader val = Shader.Find("HDRP/Unlit") ?? Shader.Find("High Definition Render Pipeline/Unlit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Transparent"); if ((Object)(object)val == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogError((object)"[PoltergeistVFX] No usable unlit shader in the game; particle materials cannot be repaired."); } return source; } Material val2 = new Material(val) { name = (((Object)(object)source != (Object)null) ? ((Object)source).name : "Poltergeist") + "_RuntimeParticle" }; Texture val3 = GetTextureIfPresent(source, "_BaseColorMap") ?? GetTextureIfPresent(source, "_MainTex") ?? GetTextureIfPresent(source, "_UnlitColorMap"); if ((Object)(object)val3 != (Object)null) { SetTextureIfPresent(val2, "_UnlitColorMap", val3); SetTextureIfPresent(val2, "_BaseColorMap", val3); SetTextureIfPresent(val2, "_MainTex", val3); } SetMaterialColor(val2, "_UnlitColor", ReadParticleColor(source)); SetMaterialColor(val2, "_BaseColor", ReadParticleColor(source)); SetMaterialColor(val2, "_Color", ReadParticleColor(source)); SetMaterialFloat(val2, "_SurfaceType", 1f); SetMaterialFloat(val2, "_BlendMode", 1f); SetMaterialFloat(val2, "_ZWrite", 0f); SetMaterialFloat(val2, "_TransparentZWrite", 0f); SetMaterialFloat(val2, "_CullMode", 0f); val2.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); val2.EnableKeyword("_BLENDMODE_ADD"); val2.renderQueue = 3000; if ((Object)(object)source != (Object)null) { RuntimeParticleMaterials[source] = val2; } return val2; } private static Color ReadParticleColor(Material material) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return Color.white; } string[] array = new string[4] { "_TintColor", "_BaseColor", "_Color", "_UnlitColor" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { return material.GetColor(array[i]); } } return Color.white; } private static void SetTextureIfPresent(Material material, string property, Texture texture) { if ((Object)(object)material != (Object)null && material.HasProperty(property)) { material.SetTexture(property, texture); } } internal static Color ResolvePhaseLightColor() { //IL_0029: 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_003a: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); ((Color)(ref result))..ctor(0.44f, 0.66f, 1f, 1f); string text = "#6FA8FF"; if (string.IsNullOrWhiteSpace(text)) { return result; } Color result2 = default(Color); if (!ColorUtility.TryParseHtmlString(text.Trim(), ref result2)) { return result; } return result2; } internal static Color ResolvePhaseDissolveEdgeColor() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) string text = "#6FA8FF"; if (string.IsNullOrWhiteSpace(text)) { return ResolvePhaseLightColor(); } Color result = default(Color); if (!ColorUtility.TryParseHtmlString(text.Trim(), ref result)) { return ResolvePhaseLightColor(); } return result; } private static void PreparePrefab(GameObject prefab) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) AssignUniqueNetworkHash(prefab); prefab.SetActive(true); TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); prefab.transform.localScale = Vector3.one * Mathf.Clamp(1f, 0.5f, 2.5f); PoltergeistAI poltergeistAI = prefab.GetComponent<PoltergeistAI>(); if ((Object)(object)poltergeistAI == (Object)null) { poltergeistAI = prefab.AddComponent<PoltergeistAI>(); } if ((Object)(object)prefab.GetComponent<NetworkObject>() == (Object)null) { prefab.AddComponent<NetworkObject>(); } Animator val = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true); if ((Object)(object)val != (Object)null) { val.applyRootMotion = false; val.cullingMode = (AnimatorCullingMode)0; ((EnemyAI)poltergeistAI).creatureAnimator = val; } else { Log.LogWarning((object)"[Poltergeist] Prefab has no Animator."); } NavMeshAgent val2 = prefab.GetComponent<NavMeshAgent>(); if ((Object)(object)val2 == (Object)null) { val2 = prefab.AddComponent<NavMeshAgent>(); } ConfigureAgent(val2); ((EnemyAI)poltergeistAI).agent = val2; ((EnemyAI)poltergeistAI).creatureSFX = FindOrCreateAudioSource(prefab.transform, "CreatureSFX", 38f); ((EnemyAI)poltergeistAI).creatureVoice = FindOrCreateAudioSource(prefab.transform, "CreatureVoice", 44f); ((EnemyAI)poltergeistAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 1.7f, 0.4f)); poltergeistAI.attackOrigin = FindOrCreateChild(prefab.transform, "AttackOrigin", new Vector3(0f, 1.15f, 0.85f)); poltergeistAI.phaseFxAnchor = FindOrCreateChild(prefab.transform, "PhaseFx", new Vector3(0f, 1.15f, 0f)); Light component = ((Component)poltergeistAI.phaseFxAnchor).GetComponent<Light>(); if ((Object)(object)component != (Object)null) { component.intensity = 0f; ((Behaviour)component).enabled = false; } poltergeistAI.phaseLight = null; AssignPoltergeistAudio(poltergeistAI); EnsureRenderers(prefab, (EnemyAI)(object)poltergeistAI); RepairBrokenMaterials(prefab); EnsureBehaviourStates(poltergeistAI); EnsureScanNode(prefab); EnsureCollision(prefab, poltergeistAI); } private static void ConfigureAgent(NavMeshAgent agent) { agent.speed = ModConfig.RoamSpeed.Value; agent.angularSpeed = 380f; agent.acceleration = 16f; agent.stoppingDistance = Mathf.Max(0.4f, ModConfig.AttackRange.Value * 0.6f); agent.radius = 0.55f; agent.height = 2.1f; agent.baseOffset = 0f; agent.autoBraking = true; agent.autoRepath = true; agent.updateRotation = false; agent.areaMask = -1; agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; agent.avoidancePriority = 34; } private static void EnsureRenderers(GameObject prefab, EnemyAI ai) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true); MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true); ai.skinnedMeshRenderers = componentsInChildren; ai.meshRenderers = componentsInChildren2; Bounds localBounds = default(Bounds); ((Bounds)(ref localBounds))..ctor(Vector3.up * 1.1f, new Vector3(5.5f, 4.5f, 5.5f)); foreach (SkinnedMeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val)) { ActivateRendererHierarchy(prefab.transform, ((Component)val).transform); ((Component)val).gameObject.SetActive(true); ((Renderer)val).enabled = true; ((Renderer)val).forceRenderingOff = false; val.updateWhenOffscreen = true; ((Renderer)val).localBounds = localBounds; ((Renderer)val).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val).receiveShadows = true; } } foreach (MeshRenderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val2)) { ActivateRendererHierarchy(prefab.transform, ((Component)val2).transform); ((Component)val2).gameObject.SetActive(true); ((Renderer)val2).enabled = true; ((Renderer)val2).forceRenderingOff = false; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val2).receiveShadows = true; } } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"[PoltergeistRenderer] Prepared {componentsInChildren.Length} skinned renderer(s), {componentsInChildren2.Length} mesh renderer(s)."); } } private static void RepairBrokenMaterials(GameObject prefab) { Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); int num = 0; foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || IsRuntimeHelperRenderer(val)) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (IsMaterialBroken(sharedMaterials[j])) { Material val2 = RebuildMaterial(sharedMaterials[j]); if (!((Object)(object)val2 == (Object)null)) { sharedMaterials[j] = val2; flag = true; num++; } } } if (flag) { val.sharedMaterials = sharedMaterials; } } if (num > 0) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[PoltergeistMaterial] Rebuilt {num} material(s) that lost their shader during bundling."); } } else { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[PoltergeistMaterial] All bundled materials kept their shader; no repair needed."); } } } private static bool IsMaterialBroken(Material material) { if ((Object)(object)material == (Object)null) { return false; } if ((Object)(object)material.shader == (Object)null) { return true; } if (((Object)material.shader).name.IndexOf("InternalError", StringComparison.OrdinalIgnoreCase) < 0) { return ((Object)material.shader).name.IndexOf("Hidden/InternalError", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static Material RebuildMaterial(Material source) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("High Definition Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogError((object)"[PoltergeistMaterial] No usable shader found in the game; cannot repair materials."); } return null; } Material val2 = new Material(val) { name = (((Object)(object)source != (Object)null) ? ((Object)source).name : "Poltergeist") + "_Runtime" }; CopyTexture(source, val2, "_BaseColorMap", "_MainTex"); CopyTexture(source, val2, "_NormalMap", "_BumpMap"); CopyTexture(source, val2, "_MaskMap", "_MetallicGlossMap"); CopyTexture(source, val2, "_EmissiveColorMap", "_EmissionMap"); SetMaterialColor(val2, "_BaseColor", Color.white); SetMaterialColor(val2, "_Color", Color.white); SetMaterialFloat(val2, "_SurfaceType", 0f); SetMaterialFloat(val2, "_AlphaCutoffEnable", 1f); SetMaterialFloat(val2, "_AlphaCutoff", 0.5f); SetMaterialFloat(val2, "_Cutoff", 0.5f); val2.EnableKeyword("_ALPHATEST_ON"); SetMaterialFloat(val2, "_DoubleSidedEnable", 1f); SetMaterialFloat(val2, "_CullMode", 0f); SetMaterialFloat(val2, "_CullModeForward", 0f); val2.EnableKeyword("_DOUBLESIDED_ON"); val2.doubleSidedGI = true; if ((Object)(object)val2.GetTexture("_NormalMap") != (Object)null || (Object)(object)val2.GetTexture("_BumpMap") != (Object)null) { val2.EnableKeyword("_NORMALMAP"); } return val2; } private static void CopyTexture(Material source, Material destination, string hdrpProperty, string standardProperty) { if ((Object)(object)source == (Object)null) { return; } Texture val = GetTextureIfPresent(source, hdrpProperty) ?? GetTextureIfPresent(source, standardProperty); if (!((Object)(object)val == (Object)null)) { if (destination.HasProperty(hdrpProperty)) { destination.SetTexture(hdrpProperty, val); } if (destination.HasProperty(standardProperty)) { destination.SetTexture(standardProperty, val); } } } private static Texture GetTextureIfPresent(Material material, string property) { if (!((Object)(object)material != (Object)null) || !material.HasProperty(property)) { return null; } return material.GetTexture(property); } private static void SetMaterialColor(Material material, string property, Color value) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material != (Object)null && material.HasProperty(property)) { material.SetColor(property, value); } } private static void SetMaterialFloat(Material material, string property, float value) { if ((Object)(object)material != (Object)null && material.HasProperty(property)) { material.SetFloat(property, value); } } private static void ActivateRendererHierarchy(Transform prefabRoot, Transform rendererTransform) { Transform val = rendererTransform; while ((Object)(object)val != (Object)null) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } if (!((Object)(object)val == (Object)(object)prefabRoot)) { val = val.parent; continue; } break; } } private static bool IsRuntimeHelperRenderer(Renderer renderer) { Transform val = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).transform : null); while ((Object)(object)val != (Object)null) { string text = ((Object)val).name ?? string.Empty; if (text.IndexOf("ScanNode", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Collision", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("MapDot", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static void EnsureBehaviourStates(PoltergeistAI ai) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown ((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[8] { new EnemyBehaviourState { name = "Roaming" }, new EnemyBehaviourState { name = "Stalking" }, new EnemyBehaviourState { name = "Phasing" }, new EnemyBehaviourState { name = "Attacking" }, new EnemyBehaviourState { name = "PossessCast" }, new EnemyBehaviourState { name = "Possessing" }, new EnemyBehaviourState { name = "Fleeing" }, new EnemyBehaviourState { name = "Dead" } }; ((EnemyAI)ai).currentBehaviourStateIndex = 0; ((EnemyAI)ai).previousBehaviourStateIndex = 0; ((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0]; } internal static void EnsureScanNode(GameObject prefab) { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { bool flag = val2.creatureScanID >= 0; bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0; bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal); bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal); if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4)) { val = val2; } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Poltergeist] Found {componentsInChildren.Length} scan nodes; retiring every duplicate."); } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)(object)val) { RetireExtraScanNode(componentsInChildren[j], val, prefab); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.3f, 0f))); ((Object)((Component)val3).gameObject).name = "ScanNode"; TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)($"[Poltergeist] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } } BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>(); } ((Collider)val4).enabled = true; ((Collider)val4).isTrigger = true; val4.center = Vector3.zero; val4.size = new Vector3(1.5f, 2.1f, 1.2f); if ((Object)(object)val == (Object)null) { val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); } val.headerText = "Passenger"; val.subText = ""; val.maxRange = 18; val.minRange = 1; val.requiresLineOfSight = true; val.nodeType = 1; } private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)extra == (Object)null) { return; } Scene scene; if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject)) { scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)extra); } else { Object.DestroyImmediate((Object)(object)extra, true); } return; } GameObject gameObject = ((Component)extra).gameObject; gameObject.SetActive(false); Collider[] components = gameObject.GetComponents<Collider>(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)gameObject); } else { Object.DestroyImmediate((Object)(object)gameObject, true); } } private static void EnsureCollision(GameObject prefab, PoltergeistAI ai) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) CapsuleCollider obj = prefab.GetComponent<CapsuleCollider>() ?? prefab.AddComponent<CapsuleCollider>(); ((Collider)obj).isTrigger = false; obj.direction = 1; obj.center = new Vector3(0f, 1.05f, 0f); obj.radius = 0.55f; obj.height = 2.1f; Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1f, 0f)); TrySetTag(((Component)val).gameObject, "Enemy"); TrySetLayer(((Component)val).gameObject, "Enemies"); BoxCollider obj2 = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>(); ((Collider)obj2).isTrigger = true; obj2.center = Vector3.zero; obj2.size = new Vector3(1.5f, 2f, 1.4f); Rigidbody obj3 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>(); obj3.isKinematic = true; obj3.useGravity = false; obj3.detectCollisions = true; EnemyAICollisionDetect obj4 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>(); obj4.mainScript = (EnemyAI)(object)ai; obj4.alwaysAllowHitting = true; obj4.canCollideWithEnemies = true; obj4.onlyCollideWhenGrounded = false; } private static EnemyType CreateEnemyType(GameObject prefab) { EnemyType obj = ScriptableObject.CreateInstance<EnemyType>(); obj.enemyName = "Passenger"; obj.enemyPrefab = prefab; obj.PowerLevel = ModConfig.PowerLevel.Value; obj.DiversityPowerLevel = 1; obj.MaxCount = ModConfig.MaxCount.Value; obj.canDie = true; obj.canBeStunned = true; obj.canBeDestroyed = true; obj.stunTimeMultiplier = 1f; obj.stunGameDifficultyMultiplier = 1f; obj.destroyOnDeath = false; obj.doorSpeedMultiplier = 1f; obj.isOutsideEnemy = false; obj.isDaytimeEnemy = false; obj.normalizedTimeInDayToLeave = 1f; obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f); obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.35f); obj.useNumberSpawnedFalloff = true; obj.disableAnimatorWhenFar = false; return obj; } private static Light FindOrCreatePhaseLight(Transform anchor) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) Light obj = ((Component)anchor).GetComponent<Light>() ?? ((Component)anchor).gameObject.AddComponent<Light>(); obj.type = (LightType)2; obj.color = ResolvePhaseLightColor(); obj.intensity = 0f; obj.range = Mathf.Max(1f, (ModConfig != null) ? 7f : 7f); obj.shadows = (LightShadows)0; obj.renderMode = (LightRenderMode)1; ((Behaviour)obj).enabled = false; return obj; } private static AudioSource FindOrCreateAudioSource(Transform parent, string childName, float maxDistance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(parent, childName, Vector3.zero); AudioSource obj = ((Component)val).GetComponent<AudioSource>() ?? ((Component)val).gameObject.AddComponent<AudioSource>(); ConfigureWorldAudioSource(obj, 3f, maxDistance); return obj; } internal static void ConfigureWorldAudioSource(AudioSource source, float minDistance, float maxDistance) { if (!((Object)(object)source == (Object)null)) { source.playOnAwake = false; source.spatialBlend = 1f; source.rolloffMode = (AudioRolloffMode)1; source.minDistance = Mathf.Max(0.1f, minDistance); source.maxDistance = Mathf.Max(source.minDistance, maxDistance); source.reverbZoneMix = 1f; source.bypassReverbZones = false; AudioMixerGroup val = ResolveDiegeticMaster(); if ((Object)(object)val != (Object)null) { source.outputAudioMixerGroup = val; } OccludeAudio val2 = ((Component)source).GetComponent<OccludeAudio>(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)source).gameObject.AddComponent<OccludeAudio>(); } val2.useReverb = true; } } internal static void ConfigureLocalAudioSource(AudioSource source) { if (!((Object)(object)source == (Object)null)) { source.playOnAwake = false; source.spatialBlend = 0f; source.rolloffMode = (AudioRolloffMode)1; source.reverbZoneMix = 0f; source.bypassReverbZones = true; AudioMixerGroup val = ResolveDiegeticMaster(); if ((Object)(object)val != (Object)null) { source.outputAudioMixerGroup = val; } } } private static AudioMixerGroup ResolveDiegeticMaster() { if ((Object)(object)_diegeticMaster != (Object)null) { return _diegeticMaster; } SoundManager instance = SoundManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.diageticMixer == (Object)null) { return null; } AudioMixerGroup[] array = instance.diageticMixer.FindMatchingGroups("Master"); if (array != null && array.Length != 0) { _diegeticMaster = array[0]; } return _diegeticMaster; } private static void AssignPoltergeistAudio(PoltergeistAI ai) { if (!((Object)(object)ai == (Object)null) && !((Object)(object)ModAssets == (Object)null)) { string[] allAssetNames = ModAssets.GetAllAssetNames(); ai.ambientClips = LoadAudioClipSet(allAssetNames, "plt_passive_01", "plt_passive_02"); ai.aggroClips = LoadAudioClipSet(allAssetNames, "plt_detect_01"); ai.attackWhooshClips = LoadAudioClipSet(allAssetNames, "plt_attack_swipe_01"); ai.attackImpactClips = LoadAudioClipSet(allAssetNames, "plt_impact_body_01", "plt_impact_body_02"); ai.footstepClips = LoadAudioClipSet(allAssetNames, "plt_foley_01", "plt_foley_02"); ai.phaseInClips = LoadAudioClipSet(allAssetNames, "plt_phase_01", "plt_phase_02"); ai.phaseOutClips = (AudioClip[])(object)new AudioClip[0]; ai.possessionClips = LoadAudioClipSet(allAssetNames, "plt_possession_01"); AudioClip[] array = LoadAudioClipSet(allAssetNames, "plt_presence_loop_01"); ai.presenceLoopClip = ((array.Length != 0) ? array[0] : null); ai.painClips = (AudioClip[])(object)new AudioClip[0]; ai.fleeClips = (AudioClip[])(object)new AudioClip[0]; ai.deathClips = (AudioClip[])(object)new AudioClip[0]; ai.howlClips = (AudioClip[])(object)new AudioClip[0]; int num = ai.ambientClips.Length + ai.aggroClips.Length + ai.attackWhooshClips.Length + ai.attackImpactClips.Length + ai.footstepClips.Length + ai.phaseInClips.Length + ai.possessionClips.Length + array.Length; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)string.Format("[PoltergeistAudio] Loaded {0}/12 approved world clip(s) from {1}.", num, "y4ngzpoltergeist.bundle")); } } } private static AudioClip[] LoadAudioClipSet(string[] bundleAssets, params string[] clipNames) { List<AudioClip> list = new List<AudioClip>(clipNames.Length); for (int i = 0; i < clipNames.Length; i++) { AudioClip val = LoadAudioClip(bundleAssets, clipNames[i]); if ((Object)(object)val != (Object)null) { list.Add(val); } } return list.ToArray(); } private static AudioClip LoadAudioClip(string[] bundleAssets, string clipName) { foreach (string text in bundleAssets) { if (string.Equals(Path.GetFileNameWithoutExtension(text), clipName, StringComparison.OrdinalIgnoreCase)) { AudioClip val = ModAssets.LoadAsset<AudioClip>(text); if ((Object)(object)val != (Object)null) { return val; } } } return null; } private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { val.localPosition = localPosition; return val; } val = new GameObject(name).transform; val.SetParent(parent, false); val.localPosition = localPosition; return val; } private static void AssignUniqueNetworkHash(GameObject prefab) { try { NetworkObject val = prefab.GetComponent<NetworkObject>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NetworkObject>(); } uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.poltergeist.Poltergeist")), 0); PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(val, num); return; } FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (fieldInfo != null) { fieldInfo.SetValue(val, num); } } catch (Exception ex) { Log.LogWarning((object)("Could not assign NetworkObject hash for Poltergeist: " + ex.Message)); } } private static void DumpBundleAssets() { if (!((Object)(object)ModAssets == (Object)null)) { string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { Log.LogError((object)(" - " + text)); } } } private static void TrySetTag(GameObject gameObject, string tag) { try { gameObject.tag = tag; } catch { } } private static void TrySetLayer(GameObject gameObject, string layerName) { if ((Object)(object)gameObject == (Object)null) { return; } int num = LayerMask.NameToLayer(layerName); if (num < 0) { num = ResolveLayerFallback(layerName); } if (num >= 0 && num <= 31) { gameObject.layer = num; return; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Poltergeist] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}."); } } private static int ResolveLayerFallback(string layerName) { if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase)) { return 22; } if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase)) { return 19; } return -1; } private static void EnsureHierarchyActive(Transform child, Transform stopAt) { Transform val = child; while ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); if (!((Object)(object)val == (Object)(object)stopAt)) { val = val.parent; continue; } break; } } } internal static class PluginInfo { public const string PLUGIN_GUID = "y4ngz.lethalcompany.poltergeist"; public const string PLUGIN_NAME = "Y4NGZ Poltergeist"; public const string PLUGIN_VERSION = "0.1.0"; } internal sealed class PoltergeistConfig { private const string SectionGeneral = "General"; private const string SectionSpawning = "Spawning"; private const string SectionCoreStats = "Core Stats"; private const string SectionDetection = "Detection"; private const string SectionMovement = "Movement"; private const string SectionCombat = "Combat"; private const string SectionAbilities = "Abilities"; private const string SectionPresentation = "Audio and Presentation"; private const string SectionDiagnostics = "Diagnostics"; public ConfigEntry<bool> Enabled { get; } public ConfigEntry<float> SpawnWeightMultiplier { get; } public ConfigEntry<int> MaxCount { get; } public ConfigEntry<float> PowerLevel { get; } public ConfigEntry<int> Health { get; } public ConfigEntry<float> SightRange { get; } public ConfigEntry<float> RoamSpeed { get; } public ConfigEntry<float> StalkSpeed { get; } public ConfigEntry<float> ChaseSpeed { get; } public ConfigEntry<float> FleeSpeed { get; } public ConfigEntry<int> AttackDamage { get; } public ConfigEntry<float> AttackRange { get; } public ConfigEntry<float> AttackCooldown { get; } public ConfigEntry<bool> TacticsEnabled { get; } public ConfigEntry<float> SightingRetreatChance { get; } public ConfigEntry<bool> WallPhasingEnabled { get; } public ConfigEntry<float> PhaseCooldown { get; } public ConfigEntry<bool> PossessionEnabled { get; } public ConfigEntry<int> PossessionHealthThreshold { get; } public ConfigEntry<float> PossessionDurationSeconds { get; } public ConfigEntry<float> PossessionRange { get; } public ConfigEntry<float> PossessionCooldownPerPlayerSeconds { get; } public ConfigEntry<bool> PossessedFriendlyFire { get; } public ConfigEntry<bool> PossessedAttacksEnabled { get; } public ConfigEntry<float> PossessedAttackCooldownSeconds { get; } public ConfigEntry<int> PossessedAttackDamage { get; } public ConfigEntry<bool> StealthPossessionEnabled { get; } public ConfigEntry<bool> PhaseVfxEnabled { get; } public ConfigEntry<float> PossessionLoopVolume { get; } public ConfigEntry<bool> PossessedVoiceFilterEnabled { get; } public ConfigEntry<bool> DebugLogs { get; } public ConfigEntry<bool> PhaseDiagnostics { get; } public ConfigEntry<float> PhaseDiagnosticsSeconds { get; } public ConfigEntry<bool> PossessionDiagnostics { get; } public ConfigEntry<bool> PossessionDebugAllowSolo { get; } public PoltergeistConfig(ConfigFile config) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Expected O, but got Unknown //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Expected O, but got Unknown //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Expected O, but got Unknown //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Expected O, but got Unknown //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Expected O, but got Unknown //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Expected O, but got Unknown //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Expected O, but got Unknown //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Expected O, but got Unknown //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Expected O, but got Unknown //IL_058f: Unknown result type (might be due to invalid IL or missing references) //IL_0599: Expected O, but got Unknown bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { PoltergeistConfigMigration.TryMigrate(config, Plugin.Log); ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Passenger"); Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Passenger encounter."); SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Passenger's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Passengers at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>())); PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.5f, new ConfigDescription("Indoor enemy power budget cost for each Passenger.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())); Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits Passenger can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); SightRange = config.Bind<float>("Detection", "SightRange", 45f, new ConfigDescription("Maximum distance at which Passenger tracks line of sight to players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 150f), Array.Empty<object>())); RoamSpeed = BindSpeed(config, "RoamSpeed", 2.2f, "Movement speed while searching the interior."); StalkSpeed = BindSpeed(config, "StalkSpeed", 3f, "Movement speed while stalking a known target."); ChaseSpeed = BindSpeed(config, "ChaseSpeed", 4.6f, "Movement speed during committed pursuit."); FleeSpeed = BindSpeed(config, "FleeSpeed", 5.4f, "Movement speed while retreating after damage."); AttackDamage = config.Bind<int>("Combat", "AttackDamage", 20, new ConfigDescription("Damage dealt by one claw swing.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); AttackRange = config.Bind<float>("Combat", "AttackRange", 2.2f, new ConfigDescription("Distance required to begin a claw attack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>())); AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.6f, new ConfigDescription("Seconds between claw attacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>())); TacticsEnabled = config.Bind<bool>("Combat", "TacticsEnabled", true, "Allow Passenger to flank, stalk, ambush, withdraw, and phase-reposition instead of only approaching directly."); SightingRetreatChance = config.Bind<float>("Combat", "SightingRetreatChance", 0.3f, new ConfigDescription("Chance that acquiring a player opens with a retreat.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); WallPhasingEnabled = config.Bind<bool>("Abilities", "WallPhasingEnabled", true, "Allow Passenger to phase through geometry when the navigable route is much longer than the direct route."); PhaseCooldown = config.Bind<float>("Abilities", "PhaseCooldown", 5f, new ConfigDescription("Seconds between wall-phase traversals.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); PossessionEnabled = config.Bind<bool>("Abilities", "PossessionEnabled", true, "Allow Passenger to possess eligible workers."); PossessionHealthThreshold = config.Bind<int>("Abilities", "PossessionHealthThreshold", 75, new ConfigDescription("A wounded worker below this health can be possessed while Passenger is visible.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); PossessionDurationSeconds = config.Bind<float>("Abilities", "PossessionDurationSeconds", 20f, new ConfigDescription("Base possession duration in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>())); PossessionRange = config.Bind<float>("Abilities", "PossessionRange", 3f, new ConfigDescription("Maximum distance for Passenger to begin possession.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 12f), Array.Empty<object>())); PossessionCooldownPerPlayerSeconds = config.Bind<float>("Abilities", "PossessionCooldownPerPlayerSeconds", 90f, new ConfigDescription("Seconds before the same worker can be possessed again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>())); PossessedFriendlyFire = config.Bind<bool>("Abilities", "PossessedFriendlyFire", true, "Allow a possessed worker to attack teammates."); PossessedAttacksEnabled = config.Bind<bool>("Abilities", "PossessedAttacksEnabled", true, "Allow Passenger to force possessed workers to perform claw attacks."); PossessedAttackCooldownSeconds = config.Bind<float>("Abilities", "PossessedAttackCooldownSeconds", 1.6f, new ConfigDescription("Seconds between forced attacks by a possessed worker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>())); PossessedAttackDamage = config.Bind<int>("Abilities", "PossessedAttackDamage", 10, new ConfigDescription("Damage dealt when a possessed worker hits a teammate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); StealthPossessionEnabled = config.Bind<bool>("Abilities", "StealthPossessionEnabled", true, "Allow Passenger to attempt possession before the worker is wounded when it remains unseen."); PhaseVfxEnabled = config.Bind<bool>("Audio and Presentation", "PhaseVfxEnabled", true, "Fade Passenger to neutral transparency during wall-phase traversals."); PossessionLoopVolume = config.Bind<float>("Audio and Presentation", "PossessionLoopVolume", 0.7f, new ConfigDescription("Volume of the local possession loop.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); PossessedVoiceFilterEnabled = config.Bind<bool>("Audio and Presentation", "PossessedVoiceFilterEnabled", true, "Apply Passenger's authored voice effect to a possessed worker."); DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose Passenger AI state logs."); PhaseDiagnostics = config.Bind<bool>("Diagnostics", "PhaseDiagnostics", true, "Write periodic wall-phase planning diagnostics."); PhaseDiagnosticsSeconds = config.Bind<float>("Diagnostics", "PhaseDiagnosticsSeconds", 20f, new ConfigDescription("Seconds between phase diagnostic summaries.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 300f), Array.Empty<object>())); PossessionDiagnostics = config.Bind<bool>("Diagnostics", "PossessionDiagnostics", true, "Write possession eligibility and lifecycle diagnostics."); PossessionDebugAllowSolo = config.Bind<bool>("Diagnostics", "PossessionDebugAllowSolo", false, "Permit possession with no other living teammate for local diagnostics."); } finally { config.SaveOnConfigSet = saveOnConfigSet; if (saveOnConfigSet) { config.Save(); } } } private static ConfigEntry<float> BindSpeed(ConfigFile config, string key, float defaultValue, string description) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return config.Bind<float>("Movement", key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); } } internal static class PoltergeistConfigMigration { private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("10 - Spawning", "SpawnWeight"); private static readonly Dictionary<ConfigDefinition, string> RemovedDefaults = new Dictionary<ConfigDefinition, string> { { new ConfigDefinition("10 - Spawning", "LevelMask"), "-1" }, { new ConfigDefinition("20 - Core Stats", "ModelScale"), "1.0" }, { new ConfigDefinition("30 - Detection", "SightConeWidth"), "75" }, { new ConfigDefinition("30 - Detection", "ProximityAwarenessRange"), "4" }, { new ConfigDefinition("30 - Detection", "LoseTargetSeconds"), "6" }, { new ConfigDefinition("30 - Detection", "LoseTargetDistance"), "55" }, { new ConfigDefinition("30 - Detection", "RoamSearchWidth"), "50" }, { new ConfigDefinition("30 - Detection", "RoamSearchPrecision"), "6" }, { new ConfigDefinition("40 - Movement", "TurnSpeed"), "380" }, { new ConfigDefinition("40 - Movement", "Acceleration"), "16" }, { new ConfigDefinition("50 - Combat", "AttackDamageDelay"), "0.42" }, { new ConfigDefinition("50 - Combat", "FleeSeconds"), "9" }, { new ConfigDefinition("50 - Combat", "FleeBackpedalSeconds"), "1.2" }, { new ConfigDefinition("50 - Combat", "TacticCommitSeconds"), "3" }, { new ConfigDefinition("50 - Combat", "TacticStalkHoldDistance"), "11" }, { new ConfigDefinition("50 - Combat", "TacticAmbushRange"), "6.5" }, { new ConfigDefinition("50 - Combat", "TacticPlayerGazeAngle"), "50" }, { new ConfigDefinition("50 - Combat", "TacticWeightDirect"), "16" }, { new ConfigDefinition("50 - Combat", "TacticWeightFlank"), "22" }, { new ConfigDefinition("50 - Combat", "TacticWeightStalk"), "16" }, { new ConfigDefinition("50 - Combat", "TacticWeightAmbush"), "20" }, { new ConfigDefinition("50 - Combat", "TacticWeightWithdraw"), "16" }, { new ConfigDefinition("50 - Combat", "TacticWeightPhaseReposition"), "22" }, { new ConfigDefinition("60 - Abilities", "PhasePathRatioThreshold"), "1.7" }, { new ConfigDefinition("60 - Abilities", "PhaseMinDistance"), "4" }, { new ConfigDefinition("60 - Abilities", "PhaseMaxDistance"), "18" }, { new ConfigDefinition("60 - Abilities", "PhaseDriftSpeed"), "3.2" }, { new ConfigDefinition("60 - Abilities", "PhaseRepositionPathRatio"), "1.2" }, { new ConfigDefinition("60 - Abilities", "PhaseImpulseChance"), "0.35" }, { new ConfigDefinition("60 - Abilities", "PhaseWhileRoaming"), "true" }, { new ConfigDefinition("60 - Abilities", "PhaseRoamPathRatio"), "1.5" }, { new ConfigDefinition("60 - Abilities", "PossessionCastSeconds"), "1.6" }, { new ConfigDefinition("60 - Abilities", "PossessionBreakHealthFloor"), "20" }, { new ConfigDefinition("60 - Abilities", "PuppetWalkSpeed"), "3.5" }, { new ConfigDefinition("60 - Abilities", "PuppetSprintDistance"), "6" }, { new ConfigDefinition("60 - Abilities", "PuppetSprintMultiplier"), "2.25" }, { new ConfigDefinition("60 - Abilities", "PossessionExtensionSeconds"), "10" }, { new ConfigDefinition("60 - Abilities", "PossessionExtensionRange"), "2.5" }, { new ConfigDefinition("60 - Abilities", "PuppetTurretAvoidRadius"), "5" }, { new ConfigDefinition("60 - Abilities", "PuppetMineAvoidRadius"), "2.5" }, { new ConfigDefinition("60 - Abilities", "PossessedAttackRange"), "2.2" }, { new ConfigDefinition("60 - Abilities", "PossessionShipSafeRadius"), "20" }, { new ConfigDefinition("60 - Abilities", "StealthSneakAbortDistance"), "4" }, { new ConfigDefinition("60 - Abilities", "StealthSneakCooldownSeconds"), "12" }, { new ConfigDefinition("70 - Audio and Presentation", "MatchAnimationToMovement"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "AuthoredWalkSpeed"), "1.9" }, { new ConfigDefinition("70 - Audio and Presentation", "DeathDissipateDelay"), "0.9" }, { new ConfigDefinition("70 - Audio and Presentation", "DeathDissipateSeconds"), "2" }, { new ConfigDefinition("70 - Audio and Presentation", "AuthoredRunSpeed"), "4.2" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseVfxVariant"), "0" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachAlignAxis"), "0" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachScale"), "1" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseForceHdrpParticleShaders"), "false" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachLingerSeconds"), "2.5" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseLightIntensity"), "14" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseLightRange"), "7" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseLightColor"), "#6FA8FF" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEnabled"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveOffsetAxis"), "0" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveDepth"), "0.65" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeWidth"), "0.5" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeIntensity"), "40" }, { new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeColor"), "#6FA8FF" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeVfxEnabled"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeSeconds"), "0.7" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionEmergeSeconds"), "0.9" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeMinScale"), "0.12" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionRelocateOnRelease"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionVisorGlowIntensity"), "10" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionVisorGlowRange"), "3" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoicePitch"), "0.68" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDistortionV2"), "0.35" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoDelayV2"), "110" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoDecayV2"), "0.45" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoWetMixV2"), "0.45" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDemonLayerMix"), "0.8" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceRingModHzV2"), "48" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceRingModMixV2"), "0.5" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceNoiseGateMix"), "0.12" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceBitcrushMixV2"), "0.25" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDriveV2"), "1.6" }, { new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsEnabled"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsScale"), "0.8" }, { new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsHeightOffset"), "0.08" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedHandsOutEnabled"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedHandsOutWeight"), "1" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionBlurIntensity"), "0.75" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessionAudioLowPassCutoff"), "1000" }, { new ConfigDefinition("70 - Audio and Presentation", "UpdateBoundsWhenOffscreen"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "AlwaysAnimate"), "true" }, { new ConfigDefinition("70 - Audio and Presentation", "PossessedHitVolume"), "0.9" } }; internal static bool TryMigrate(ConfigFile config, ManualLogSource log) { string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return false; } Dictionary<ConfigDefinition, string> dictionary = null; string text = null; try { dictionary = ReadValues(configFilePath); if (!ContainsLegacyConfig(dictionary)) { return false; } text = GetBackupPath(configFilePath); File.Copy(configFilePath, text, overwrite: false); File.WriteAllText(configFilePath, BuildMigratedConfig(dictionary), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } catch (Exception ex) { string text2 = "The original config was not modified."; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Copy(text, configFilePath, overwrite: true); config.Reload(); text2 = "The original config was restored from its backup."; } catch (Exception ex2) { text2 = "Automatic restore also failed: " + ex2.GetBaseException().Message + ". Recover manually from " + text + "."; } } if (log != null) { log.LogWarning((object)("[Poltergeist] Could not migrate legacy config: " + ex.GetBaseException().Message + " " + text2)); } return false; } List<string> list = FindCustomizedDroppedKeys(dictionary); if (log != null) { log.LogInfo((object)("[Poltergeist] Migrated legacy config to the compact DawnLib layout. Backup: " + text)); } if (list.Count > 0 && log != null) { log.LogWarning((object)("[Poltergeist] These customized legacy settings are now authored source tuning and were not carried forward: " + string.Join(", ", list))); } return true; } private static bool ContainsLegacyConfig(Dictionary<ConfigDefinition, string> values) { if (values.ContainsKey(LegacySpawnWeight)) { return true; } foreach (ConfigDefinition key in RemovedDefaults.Keys) { if (values.ContainsKey(key)) { return true; } } return false; } private static string BuildMigratedConfig(Dictionary<ConfigDefinition, string> values) { string text = GetValue(values, "10 - Spawning", "SpawnWeightMultiplier", null); if (string.IsNullOrWhiteSpace(text)) { text = ((!float.TryParse(GetValue(values, LegacySpawnWeight, "14"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) ? "1" : Math.Max(0f, Math.Min(5f, result / 14f)).ToString("0.###", CultureInfo.InvariantCulture)); } StringBuilder stringBuilder = new StringBuilder(); AppendSection(stringBuilder, "00 - General", ("Enabled", GetValue(values, "00 - General", "Enabled", "true"))); AppendSection(stringBuilder, "10 - Spawning", ("SpawnWeightMultiplier", text), ("MaxCount", GetValue(values, "10 - Spawning", "MaxCount", "1")), ("PowerLevel", GetValue(values, "10 - Spawning", "PowerLevel", "2.5"))); AppendSection(stringBuilder, "20 - Core Stats", ("Health", GetValue(values, "20 - Core Stats", "Health", "5"))); AppendSection(stringBuilder, "30 - Detection", ("SightRange", GetValue(values, "30 - Detection", "SightRange", "45"))); AppendSection(stringBuilder, "40 - Movement", ("RoamSpeed", GetValue(values, "40 - Movement", "RoamSpeed", "2.2")), ("StalkSpeed", GetValue(values, "40 - Movement", "StalkSpeed", "3")), ("ChaseSpeed", GetValue(values, "40 - Movement", "ChaseSpeed", "4.6")), ("FleeSpeed", GetValue(values, "40 - Movement", "FleeSpeed", "5.4"))); AppendSection(stringBuilder, "50 - Combat", ("AttackDamage", GetValue(values, "50 - Combat", "AttackDamage", "20")), ("AttackRange", GetValue(values, "50 - Combat", "AttackRange", "2.2")), ("AttackCooldown", GetValue(values, "50 - Combat", "AttackCooldown", "1.6")), ("TacticsEnabled", GetValue(values, "50 - Combat", "TacticsEnabled", "true")), ("SightingRetreatChance", GetValue(values, "50 - Combat", "SightingRetreatChance", "0.3"))); AppendSection(stringBuilder, "60 - Abilities", ("WallPhasingEnabled", GetValue(values, "60 - Abilities", "WallPhasingEnabled", "true")), ("PhaseCooldown", GetValue(values, "60 - Abilities", "PhaseCooldown", "5")), ("PossessionEnabled", GetValue(values, "60 - Abilities", "PossessionEnabled", "true")), ("PossessionHealthThreshold", GetValue(values, "60 - Abilities", "PossessionHealthThreshold", "75")), ("PossessionDurationSeconds", GetValue(values, "60 - Abilities", "PossessionDurationSeconds", "20")), ("PossessionRange", GetValue(values, "60 - Abilities", "PossessionRange", "3")), ("PossessionCooldownPerPlayerSeconds", GetValue(values, "60 - Abilities", "PossessionCooldownPerPlayerSeconds", "90")), ("PossessedFriendlyFire", GetValue(values, "60 - Abilities", "PossessedFriendlyFire", "true")), ("PossessedAttacksEnabled", GetValue(values, "60 - Abilities", "PossessedAttacksEnabled", "true")), ("PossessedAttackCooldownSeconds", GetValue(values, "60 - Abilities", "PossessedAttackCooldownSeconds", "1.6")), ("PossessedAttackDamage", GetValue(values, "60 - Abilities", "PossessedAttackDamage", "10")), ("StealthPossessionEnabled", GetValue(values, "60 - Abilities", "StealthPossessionEnabled", "true"))); AppendSection(stringBuilder, "70 - Audio and Presentation", ("PhaseVfxEnabled", GetValue(values, "70 - Audio and Presentation", "PhaseVfxEnabled", "true")), ("PossessionLoopVolume", GetValue(values, "70 - Audio and Presentation", "PossessionLoopVolume", "0.7")), ("PossessedVoiceFilterEnabled", GetValue(values, "70 - Audio and Presentation", "PossessedVoiceFilterEnabled", "true"))); AppendSection(stringBuilder, "99 - Diagnostics", ("DebugLogs", GetValue(values, "99 - Diagnostics", "DebugLogs", "false")), ("PhaseDiagnostics", GetValue(values, "99 - Diagnostics", "PhaseDiagnostics", "true")), ("PhaseDiagnosticsSeconds", GetValue(values, "99 - Diagnostics", "PhaseDiagnosticsSeconds", "20")), ("PossessionDiagnostics", GetValue(values, "99 - Diagnostics", "PossessionDiagnostics", "true")), ("PossessionDebugAllowSolo", GetValue(values, "99 - Diagnostics", "PossessionDebugAllowSolo", "false"))); return stringBuilder.ToString(); } private static void AppendSection(StringBuilder output, string section, params (string Key, string Value)[] entries) { output.Append('[').Append(section).AppendLine("]"); for (int i = 0; i < entries.Length; i++) { output.Append(entries[i].Key).Append(" = ").AppendLine(entries[i].Value); } output.AppendLine(); } private static string GetValue(Dictionary<ConfigDefinition, string> values, string section, string key, string fallback) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return GetValue(values, new ConfigDefinition(section, key), fallback); } private static string GetValue(Dictionary<ConfigDefinition, string> values, ConfigDefinition definition, string fallback) { if (!values.TryGetValue(definition, out var value)) { return fallback; } return value; } private static Dictionary<ConfigDefinition, string> ReadValues(string path) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(); string text = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string value = text2.Substring(num + 1).Trim(); dictionary[new ConfigDefinition(text, text3)] = value; } } return dictionary; } private static List<string> FindCustomizedDroppedKeys(Dictionary<ConfigDefinition, string> values) { List<string> list = new List<string>(); foreach (KeyValuePair<ConfigDefinition, string> removedDefault in RemovedDefaults) { if (values.TryGetValue(removedDefault.Key, out var value) && !ValuesEquivalent(value, removedDefault.Value)) { list.Add(removedDefault.Key.Section + "." + removedDefault.Key.Key); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private static bool ValuesEquivalent(string left, string right) { if (string.Equals(left.Trim(), right.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } if (float.TryParse(left, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(right, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) < 0.0001f; } return false; } private static string GetBackupPath(string configPath) { string text = configPath + ".pre-dawn.bak"; if (!File.Exists(text)) { return text; } for (int i = 2; i < 1000; i++) { string text2 = configPath + $".pre-dawn.{i}.bak"; if (!File.Exists(text2)) { return text2; } } throw new IOException("Could not allocate a Poltergeist config backup filename."); } } internal sealed class PoltergeistSpawnWeights : IWeighted, IContextualWeighted<SpawnWeightContext> { internal const int DefaultWeight = 3; internal const int MaximumWeight = 100; private readonly Func<float> _multiplier; internal PoltergeistSpawnWeights(Func<float> multiplier) { _multiplier = multiplier ?? throw new ArgumentNullException("multiplier"); } public int GetWeight() { return Scale(3, 1f); } public int GetWeight(SpawnWeightContext context) { int moonWeight = GetMoonWeight(((SpawnWeightContext)(ref context)).Moon); if (moonWeight <= 0) { return 0; } return Scale(moonWeight, GetDungeonMultiplier(((SpawnWeightContext)(ref context)).Dungeon)); } internal static int GetMoonWeight(DawnMoonInfo moon) { if (moon == null) { return 3; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Company) || ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Unimplemented) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Test)) { return 0; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Experimentation)) { return 1; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Assurance) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Vow)) { return 3; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Offense) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.March) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Embrion)) { return 5; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Adamance)) { return 7; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Rend) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Dine)) { return 9; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Titan) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Artifice) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Liquidation)) { return 11; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Paid)) { return 8; } ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Free); return 3; } internal static float GetDungeonMultiplier(DawnDungeonInfo dungeon) { if (dungeon == null) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MansionFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Gothic) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Grand) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Ornate) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Lavish) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Eerie)) { return 1.25f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlow) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowThreeExits) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowExtraLarge) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Industrial) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Mechanical) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Factory) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Bunker)) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MineshaftFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Cavern) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Quarry) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Flooded)) { return 0.5f; } return 0.75f; } private int Scale(int moonWeight, float dungeonMultiplier) { float num = Mathf.Clamp(_multiplier(), 0f, 5f); return Mathf.Clamp(Mathf.RoundToInt((float)moonWeight * dungeonMultiplier * num), 0, 100); } private static bool KeyEquals<T>(NamespacedKey<T> left, NamespacedKey<T> right) where T : INamespaced { if (left != null && right != null) { return ((object)left).Equals((object?)right); } return false; } } internal static class PoltergeistTuning { internal const float ModelScale = 1f; internal const float SightConeWidth = 75f; internal const float ProximityAwarenessRange = 4f; internal const float LoseTargetSeconds = 6f; internal const float LoseTargetDistance = 55f; internal const float RoamSearchWidth = 50f; internal const float RoamSearchPrecision = 6f; internal const float TurnSpeed = 380f; internal const float Acceleration = 16f; internal const float AttackAnimationSpeed = 1.4f; internal const float AttackContactWindupSeconds = 0.08f; internal const float AttackContactWindowSeconds = 0.72f; internal const float AttackHandRadius = 0.18f; internal const float FleeSeconds = 9f; internal const float FleeBackpedalSeconds = 1.2f; internal const float TacticCommitSeconds = 3f; internal const float TacticStalkHoldDistance = 11f; internal const float TacticAmbushRange = 6.5f; internal const float TacticPlayerGazeAngle = 50f; internal const int TacticWeightDirect = 16; internal const int TacticWeightFlank = 22; internal const int TacticWeightStalk = 16; internal const int TacticWeightAmbush = 20; internal const int TacticWeightWithdraw = 16; internal const int TacticWeightPhaseReposition = 22; internal const float PhasePathRatioThreshold = 1.7f; internal const float PhaseMinDistance = 4f; internal const float PhaseMaxDistance = 18f; internal const float PhaseDriftSpeed = 3.2f; internal const float PhaseBodyClearanceMargin = 0.15f; internal const float PhaseLandingSearchStep = 0.35f; internal const float PhaseLandingSearchDistance = 6f; internal const float PhaseRepositionPathRatio = 1.2f; internal const float PhaseImpulseChance = 0.35f; internal const bool PhaseWhileRoaming = true; internal const float PhaseRoamPathRatio = 1.5f; internal const float PossessionCastSeconds = 1.6f; internal const int PossessionBreakHealthFloor = 20; internal const float PuppetWalkSpeed = 3.5f; internal const float PuppetSprintDistance = 6f; internal const float PuppetSprintMultiplier = 2.25f; internal const float PossessionExtensionSeconds = 10f; internal const float PossessionExtensionRange = 2.5f; internal const float PuppetTurretAvoidRadius = 5f; internal const float PuppetMineAvoidRadius = 2.5f; internal const float PossessedAttackRange = 2.2f; internal const float PossessionShipSafeRadius = 20f; internal const float StealthSneakAbortDistance = 4f; internal const float StealthSneakCooldownSeconds = 12f; internal const bool MatchAnimationToMovement = true; internal const float AuthoredWalkSpeed = 1.9f; internal const float AuthoredRunSpeed = 4.2f; internal const float DeathDissipateDelay = 0.9f; internal const float DeathDissipateSeconds = 2f; internal const float PresenceLoopVolume = 0.45f; internal const float PresenceLoopFadePerSecond = 1.5f; internal const float PresenceLoopMaxDistance = 12f; internal const float FoleyVolume = 0.5f; internal const float FoleyMaxDistance = 10f; internal const float FoleyWalkSpacing = 1.25f; internal const float FoleyRunSpacing = 1.65f; internal const float SwipeVolume = 0.65f; internal const float SwipeMaxDistance = 18f; internal const float PhaseAudioVolume = 0.75f; internal const float PhaseAudioMaxDistance = 30f; internal const int PhaseVfxVariant = 0; internal const int PhaseBreachAlignAxis = 0; internal const float PhaseBreachScale = 1f; internal const bool PhaseForceHdrpParticleShaders = false; internal const float PhaseBreachLingerSeconds = 2.5f; internal const float PhaseLightIntensity = 14f; internal const float PhaseLightRange = 7f; internal const string PhaseLightColor = "#6FA8FF"; internal const bool PhaseDissolveEnabled = true; internal const int PhaseDissolveOffsetAxis = 0; internal const float PhaseDissolveDepth = 0.65f; internal const float PhaseDissolveEdgeWidth = 0.5f; internal const float PhaseDissolveEdgeIntensity = 40f; internal const string PhaseDissolveEdgeColor = "#6FA8FF"; internal const bool PossessionMergeVfxEnabled = true; internal const float PossessionMergeSeconds = 0.7f; internal const float PossessionEmergeSeconds = 0.9f; internal const float PossessionMergeMinScale = 0.12f; internal const bool PossessionRelocateOnRelease = true; internal const float PossessionVisorGlowIntensity = 10f; internal const float PossessionVisorGlowRange = 3f; internal const float PossessedVoicePitch = 0.68f; internal const float PossessedVoiceDistortion = 0.35f; internal const float PossessedVoiceEchoDelay = 110f; internal const float PossessedVoiceEchoDecay = 0.45f; internal const float PossessedVoiceEchoWetMix = 0.45f; internal const float PossessedVoiceDemonLayerMix = 0.8f; internal const float PossessedVoiceRingModHz = 48f; internal const float PossessedVoiceRingModMix = 0.5f; internal const float PossessedVoiceNoiseGateMix = 0.12f; internal const float PossessedVoiceBitcrushMix = 0.25f; internal const float PossessedVoiceDrive = 1.6f; internal const bool SpectralArmsEnabled = true; internal const float SpectralArmsScale = 0.8f; internal const float SpectralArmsHeightOffset = 0.08f; internal const bool PossessedHandsOutEnabled = true; internal const float PossessedHandsOutWeight = 1f; internal const bool UpdateBoundsWhenOffscreen = true; internal const bool AlwaysAnimate = true; } } namespace Y4NGZPoltergeist.Patches { [HarmonyPatch] internal static class PossessedVoicePatches { [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void UpdatePostfix(PlayerControllerB __instance) { if (PoltergeistPossessedVoice.AnyActive && !((Object)(object)__instance == (Object)null)) { PoltergeistPossessedVoice.ReassertPitchFor(__instance); } } [HarmonyPatch(typeof(StartOfRound), "UpdatePlayerVoiceEffects")] [HarmonyPostfix] private static void UpdatePlayerVoiceEffectsPostfix() { if (PoltergeistPossessedVoice.AnyActive) { PoltergeistPossessedVoice.ReassertAll(); } } } [HarmonyPatch] internal static class PossessionInputPatches { private static bool LocalPlayerIsPossessed(PlayerControllerB player) { if ((Object)(object)player == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)player != (Object)(object)GameNetworkManager.Instance.localPlayerController) { return false; } PoltergeistPossessionLock component = ((Component)player).GetComponent<PoltergeistPossessionLock>(); if ((Object)(object)component != (Object)null) { return component.Holds; } return false; } [HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")] [HarmonyPrefix] private static bool JumpPerformedPrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "Crouch_performed")] [HarmonyPrefix] private static bool CrouchPerformedPrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "ClickHoldInteraction")] [HarmonyPrefix] private static bool ClickHoldInteractionPrefix(PlayerControllerB __instance) { if (!LocalPlayerIsPossessed(__instance)) { return true; } __instance.isHoldingInteract = false; return false; } [HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")] [HarmonyPrefix] private static bool InteractPerformedPrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "PerformEmote")] [HarmonyPrefix] private static bool PerformEmotePrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "Discard_performed")] [HarmonyPrefix] private static bool DiscardPerformedPrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void UpdatePostfix(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController)) { PoltergeistPossessionLock component = ((Component)__instance).GetComponent<PoltergeistPossessionLock>(); if ((Object)(object)component != (Object)null && component.Holds) { component.DrivePuppetMovement(); } } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void LateUpdatePostfix(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController)) { PoltergeistPossessionLock component = ((Component)__instance).GetComponent<PoltergeistPossessionLock>(); if ((Object)(object)component != (Object)null && component.Holds) { component.DrivePuppetLook(); } } } [HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_performed")] [HarmonyPriority(800)] [HarmonyPrefix] private static bool ActivateItemPerformedPrefix(PlayerControllerB __instance) { return !LocalPlayerIsPossessed(__instance); } } internal static class PossessionInteractionBridge { private const string PackId = "y4ngz.poltergeist.possessed-claws"; private const string FirstPersonManifestFile = "y4ngz-upgrades-fists-firstperson.manifest.json"; private const string ThirdPersonManifestFile = "y4ngz-upgrades-fists-thirdperson.manifest.json"; internal const string FirstPersonInteractionId = "y4ngz.native-fists.firstperson"; internal const string ThirdPersonInteractionId = "y4ngz.native-fists.thirdperson"; internal const string EnterTrigger = "Y4NGZ_Fists_Enter"; internal const string PunchLeftTrigger = "PunchLeft"; internal const string PunchRightTrigger = "PunchRight"; private static bool _resolved; private static MethodInfo _tryStopPlayerInteractions; private static object _interruptedReason; private static Type _packType; private static Type _definitionType; private static Type _requestType; private static Type _presentationKindType; private static MethodInfo _tryRegisterPack; private static MethodInfo _tryStartInteraction; private static MethodInfo _tryStopInteraction; private static MethodInfo _isInteractionActive; private static MethodInfo _tryFireTrigger; private static MethodInfo _tryBeginExit; private static bool _packRegistered; private static bool _packUnavailableLogged; internal static void TryStopInteractions(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } try { if (!_resolved) { Resolve(); } if (_tryStopPlayerInteractions != null) { _tryStopPlayerInteractions.Invoke(null, new object[2] { player, _interruptedReason }); } } catch (Exception ex) { PoltergeistAI.LogPossession("Interaction-API arbitration failed: " + ex.Message); } } private static void Resolve() { _resolved = true; Type type = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.LCInteractionAnimationAPI, Y4NGZInteractions"); Type type2 = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationStopReason, Y4NGZInteractions"); if (!(type == null) && !(type2 == null)) { _interruptedReason = Enum.Parse(type2, "Interrupted"); _tryStopPlayerInteractions = type.GetMethod("TryStopPlayerInteractions", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(PlayerControllerB), type2 }, null); _packType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationPackDefinition, Y4NGZInteractions"); _definitionType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationDefinition, Y4NGZInteractions"); _requestType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationRequest, Y4NGZInteractions"); _presentationKindType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationPresentationKind, Y4NGZInteractions"); _tryRegisterPack = type.GetMethod("TryRegisterInteractionPack", BindingFlags.Static | BindingFlags.Public); _tryStartInteraction = type.GetMethod("TryStartInteraction", BindingFlags.Static | BindingFlags.Public); _tryStopInteraction = type.GetMethod("TryStopInteraction", BindingFlags.Static | BindingFlags.Public); _isInteractionActive = type.GetMethod("IsInteractionActive", BindingFlags.Static | BindingFlags.Public); _tryFireTrigger = type.GetMethod("TryFireInteractionTrigger", BindingFlags.Static | BindingFlags.Public); _tryBeginExit = type.GetMethod("TryBeginInteractionExit", BindingFlags.Static | BindingFlags.Public); } } internal static bool EnsureFistsPackRegistered() { if (_packRegistered) { return true; } try { if (!_resolved) { Resolve(); } if (_tryRegisterPack == null || _packType == null || _definitionType == null) { return LogPackUnavailable("Y4NGZInteractions' animation API is not present"); } if (!TryFindFistsAssetRoot(out var root)) { return LogPackUnavailable("Y4NGZUpgrades' fists manifests were not found under BepInEx/plugins"); } object obj = Activator.CreateInstance(_packType); SetProperty(obj, "PackId", "y4ngz.poltergeist.possessed-claws"); SetProperty(obj, "DisplayName", "Y4NGZ Poltergeist Possessed Claws"); SetProperty(obj, "Version", "0.1.0"); SetProperty(obj, "Author", "Y4NGZ"); SetProperty(obj, "AssetRootPath", root); Array array = Array.CreateInstance(_definitionType, 2); array.SetValue(BuildDefinition("y4ngz.native-fists.firstperson", "Possessed Claws (First Person)", "DedicatedLocalViewmodel", File.ReadAllText(Path.Combine(root, "y4ngz-upgrades-fists-firstperson.manifest.json"))), 0); array.SetValue(BuildDefinition("y4ngz.native-fists.thirdperson", "Possessed Claws (Third Person)", "BodyWorld", File.ReadAllText(Path.Combine(root, "y4ngz-upgrades-fists-thirdperson.manifest.json"))), 1); SetProperty(obj, "Interactions", array); object[] array2 = new object[2] { obj, null }; bool num = (bool)_tryRegisterPack.Invoke(null, array2); string text = (array2[1] as string) ?? string.Empty; if (!num && !string.Equals(text, "pack_already_registered", StringComparison.OrdinalIgnoreCase)) { return LogPackUnavailable("pack registration refused (" + text + ")"); } _packRegistered = true; PoltergeistAI.LogPossession("Possessed-attack pack registered against '" + root + "'."); return true; } catch (Exception ex) { return LogPackUnavailable(ex.Message); } } internal static bool TryStartFistsPresentation(PlayerControllerB player, bool firstPerson, out object handle) { handle = null; if ((Object)(object)player == (Object)null || !EnsureFistsPackRegistered() || _requestType == null || _tryStartInteraction == null) { return false; } try { object obj = Activator.CreateInstance(_requestType); SetProperty(obj, "Player", player); SetProperty(obj, "PackId", "y4ngz.poltergeist.possessed-claws"); SetProperty(obj, "InteractionId", firstPerson ? "y4ngz.native-fists.firstperson" : "y4ngz.native-fists.thirdperson"); SetProperty(obj, "OwnerModId", "y4ngz.lethalcompany.poltergeist"); object[] array = new object[3] { obj, null, null }; if (!(bool)_tryStartInteraction.Invoke(null, array)) { PoltergeistAI.LogPossession("Possessed-attack " + (firstPerson ? "FP" : "TP") + " presentation refused: " + (array[2] as string) + "."); return false; } handle = array[1]; return true; } catch (Exception ex) { PoltergeistAI.LogPossession("Possessed-attack presentation failed: " + ex.Message); return false; } } internal static bool IsPresentationActive(object handle) { if (handle != null && _isInteractionActive != null) { return Safe(() => (bool)_isInteractionActive.Invoke(null, new object[1] { handle })); } return false; } internal static bool FirePresentationTrigger(object handle, string trigger) { if (IsPresentationActive(handle) && _tryFireTrigger != null) { return Safe(() => (bool)_tryFireTrigger.Invoke(null, new object[2] { handle, trigger })); } return false; } internal static void EndPresentation(object handle, bool immediate) { if (IsPresentationActive(handle) && (immediate || !(_tryBeginExit != null) || !Safe(() => (bool)_tryBeginExit.Invoke(null, new object[2] { handle, null }))) && _tryStopInteraction != null && _interruptedReason != null) { Safe(() => (bool)_tryStopInteraction.Invoke(null, new object[2] { handle, _interruptedReason })); } } private static bool TryFindFistsAssetRoot(out string root) { root = null; string pluginPath = Paths.PluginPath; if (string.IsNullOrEmpty(pluginPath) || !Directory.Exists(pluginPath)) { return false; } string[] files = D
EyeMonster.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using EyeMonster.AI; using EyeMonster.NetcodePatcher; using EyeMonster.Utils; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("EyeMonster")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("EyeMonster")] [assembly: AssemblyTitle("EyeMonster")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 EyeMonster { public sealed class EyeMonsterConfig { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<float> SpawnWeightMultiplier { get; } public ConfigEntry<int> MaxCount { get; } public ConfigEntry<float> PowerLevel { get; } public ConfigEntry<int> Health { get; } public ConfigEntry<float> NoticeRange { get; } public ConfigEntry<float> GazeAngle { get; } public ConfigEntry<float> FlashlightRange { get; } public ConfigEntry<float> RoamSpeed { get; } public ConfigEntry<float> ChaseSpeed { get; } public ConfigEntry<float> FleeSpeed { get; } public ConfigEntry<int> AttackDamage { get; } public ConfigEntry<float> AttackCooldown { get; } public ConfigEntry<float> FleeDuration { get; } public ConfigEntry<bool> DebugLogs { get; } public EyeMonsterConfig(ConfigFile config) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Expected O, but got Unknown //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Expected O, but got Unknown bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { EyeMonsterConfigMigration.TryMigrate(config, Plugin.Log); ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Eye Monster"); Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Eye Monster encounter."); SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Eye Monster's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); MaxCount = config.Bind<int>("Spawning", "MaxCount", 2, new ConfigDescription("Maximum number of living Eye Monsters at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>())); PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2f, new ConfigDescription("Indoor enemy power budget cost for each Eye Monster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits the Eye Monster can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); NoticeRange = config.Bind<float>("Detection", "NoticeRange", 12f, new ConfigDescription("Maximum range at which an Eye Monster facing a player can begin investigating.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 80f), Array.Empty<object>())); GazeAngle = config.Bind<float>("Detection", "GazeAngle", 28f, new ConfigDescription("Half-angle within which looking at its eye confirms aggression.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), Array.Empty<object>())); FlashlightRange = config.Bind<float>("Detection", "FlashlightRange", 15f, new ConfigDescription("Maximum range at which a direct flashlight beam makes the Eye Monster flee.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 80f), Array.Empty<object>())); RoamSpeed = config.Bind<float>("Movement", "RoamSpeed", 2f, new ConfigDescription("Movement speed while roaming.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>())); ChaseSpeed = config.Bind<float>("Movement", "ChaseSpeed", 5f, new ConfigDescription("Movement speed after a player confirms aggression through eye contact.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 15f), Array.Empty<object>())); FleeSpeed = config.Bind<float>("Movement", "FleeSpeed", 7f, new ConfigDescription("Movement speed while fleeing a direct flashlight beam.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); AttackDamage = config.Bind<int>("Combat", "AttackDamage", 35, new ConfigDescription("Damage dealt by a successful attack.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.5f, new ConfigDescription("Seconds between attack attempts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>())); FleeDuration = config.Bind<float>("Abilities", "FleeDuration", 6f, new ConfigDescription("Seconds the Eye Monster flees after being directly lit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>())); DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Log detailed Eye Monster targeting and setup diagnostics."); } finally { config.SaveOnConfigSet = saveOnConfigSet; if (saveOnConfigSet) { config.Save(); } } } } internal static class EyeMonsterConfigMigration { private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight"); private static readonly ConfigDefinition[] RetainedLegacyDefinitions = (ConfigDefinition[])(object)new ConfigDefinition[10] { new ConfigDefinition("Combat", "EnemyHP"), new ConfigDefinition("Movement", "RoamSpeed"), new ConfigDefinition("Movement", "ChaseSpeed"), new ConfigDefinition("Movement", "FleeSpeed"), new ConfigDefinition("Combat", "AttackDamage"), new ConfigDefinition("Combat", "AttackCooldown"), new ConfigDefinition("Detection", "AggroRange"), new ConfigDefinition("Detection", "PlayerGazeAngle"), new ConfigDefinition("Detection", "FlashlightDetectionRange"), new ConfigDefinition("Behavior", "FleeDuration") }; private static readonly Dictionary<ConfigDefinition, string> RemovedDefaults = new Dictionary<ConfigDefinition, string> { { new ConfigDefinition("Movement", "InvestigateSpeed"), "2.6" }, { new ConfigDefinition("Combat", "AttackRange"), "2.5" }, { new ConfigDefinition("Detection", "NoticeViewAngle"), "52" }, { new ConfigDefinition("Behavior", "InvestigationStopDistance"), "4.5" }, { new ConfigDefinition("Behavior", "InvestigationDecisionDelay"), "0.8" }, { new ConfigDefinition("Detection", "FlashlightDetectionAngle"), "25" }, { new ConfigDefinition("Behavior", "LoseTargetSeconds"), "3.5" }, { new ConfigDefinition("Behavior", "FailedNoticeCooldown"), "4" } }; internal static bool TryMigrate(ConfigFile config, ManualLogSource log) { string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return false; } Dictionary<ConfigDefinition, string> dictionary = null; string text = null; try { dictionary = ReadValues(configFilePath); if (!ContainsLegacyConfig(dictionary)) { return false; } text = GetBackupPath(configFilePath); File.Copy(configFilePath, text, overwrite: false); File.WriteAllText(configFilePath, BuildMigratedConfig(dictionary), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } catch (Exception ex) { string text2 = "The original config was not modified."; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Copy(text, configFilePath, overwrite: true); config.Reload(); text2 = "The original config was restored from its backup."; } catch (Exception ex2) { text2 = "Automatic restore also failed: " + ex2.GetBaseException().Message + ". Recover manually from " + text + "."; } } if (log != null) { log.LogWarning((object)("[Eye Monster] Could not migrate legacy config: " + ex.GetBaseException().Message + " " + text2)); } return false; } List<string> list = FindCustomizedDroppedKeys(dictionary); if (log != null) { log.LogInfo((object)("[Eye Monster] Migrated legacy config to the compact DawnLib layout. Backup: " + text)); } if (list.Count > 0 && log != null) { log.LogWarning((object)("[Eye Monster] These customized legacy settings are now authored source tuning and were not carried forward: " + string.Join(", ", list))); } return true; } private static bool ContainsLegacyConfig(Dictionary<ConfigDefinition, string> values) { if (values.ContainsKey(LegacySpawnWeight)) { return true; } for (int i = 0; i < RetainedLegacyDefinitions.Length; i++) { if (values.ContainsKey(RetainedLegacyDefinitions[i])) { return true; } } foreach (ConfigDefinition key in RemovedDefaults.Keys) { if (values.ContainsKey(key)) { return true; } } return false; } private static string BuildMigratedConfig(Dictionary<ConfigDefinition, string> values) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_0174: Expected O, but got Unknown //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_01bf: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_01f9: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_0233: Expected O, but got Unknown //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_027e: Expected O, but got Unknown //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected O, but got Unknown //IL_02b8: Expected O, but got Unknown //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Expected O, but got Unknown //IL_02f2: Expected O, but got Unknown //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Expected O, but got Unknown //IL_033d: Expected O, but got Unknown //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Expected O, but got Unknown //IL_0377: Expected O, but got Unknown //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Expected O, but got Unknown //IL_03c2: Expected O, but got Unknown //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Expected O, but got Unknown string text = GetValue(values, new ConfigDefinition("10 - Spawning", "SpawnWeightMultiplier"), null, null); if (string.IsNullOrWhiteSpace(text)) { text = ((!float.TryParse(GetValue(values, LegacySpawnWeight, null, "40"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) ? "1" : Math.Max(0f, Math.Min(5f, result / 40f)).ToString("0.###", CultureInfo.InvariantCulture)); } StringBuilder stringBuilder = new StringBuilder(); AppendSection(stringBuilder, "00 - General", ("Enabled", GetValue(values, new ConfigDefinition("00 - General", "Enabled"), null, "true"))); AppendSection(stringBuilder, "10 - Spawning", ("SpawnWeightMultiplier", text), ("MaxCount", GetValue(values, new ConfigDefinition("10 - Spawning", "MaxCount"), null, "2")), ("PowerLevel", GetValue(values, new ConfigDefinition("10 - Spawning", "PowerLevel"), null, "2"))); AppendSection(stringBuilder, "20 - Core Stats", ("Health", GetValue(values, new ConfigDefinition("20 - Core Stats", "Health"), new ConfigDefinition("Combat", "EnemyHP"), "5"))); AppendSection(stringBuilder, "30 - Detection", ("NoticeRange", GetValue(values, new ConfigDefinition("30 - Detection", "NoticeRange"), new ConfigDefinition("Detection", "AggroRange"), "12")), ("GazeAngle", GetValue(values, new ConfigDefinition("30 - Detection", "GazeAngle"), new ConfigDefinition("Detection", "PlayerGazeAngle"), "28")), ("FlashlightRange", GetValue(values, new ConfigDefinition("30 - Detection", "FlashlightRange"), new ConfigDefinition("Detection", "FlashlightDetectionRange"), "15"))); AppendSection(stringBuilder, "40 - Movement", ("RoamSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "RoamSpeed"), new ConfigDefinition("Movement", "RoamSpeed"), "2")), ("ChaseSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "ChaseSpeed"), new ConfigDefinition("Movement", "ChaseSpeed"), "5")), ("FleeSpeed", GetValue(values, new ConfigDefinition("40 - Movement", "FleeSpeed"), new ConfigDefinition("Movement", "FleeSpeed"), "7"))); AppendSection(stringBuilder, "50 - Combat", ("AttackDamage", GetValue(values, new ConfigDefinition("50 - Combat", "AttackDamage"), new ConfigDefinition("Combat", "AttackDamage"), "35")), ("AttackCooldown", GetValue(values, new ConfigDefinition("50 - Combat", "AttackCooldown"), new ConfigDefinition("Combat", "AttackCooldown"), "1.5"))); AppendSection(stringBuilder, "60 - Abilities", ("FleeDuration", GetValue(values, new ConfigDefinition("60 - Abilities", "FleeDuration"), new ConfigDefinition("Behavior", "FleeDuration"), "6"))); AppendSection(stringBuilder, "99 - Diagnostics", ("DebugLogs", GetValue(values, new ConfigDefinition("99 - Diagnostics", "DebugLogs"), null, "false"))); return stringBuilder.ToString(); } private static void AppendSection(StringBuilder output, string section, params (string Key, string Value)[] entries) { output.Append('[').Append(section).AppendLine("]"); for (int i = 0; i < entries.Length; i++) { output.Append(entries[i].Key).Append(" = ").AppendLine(entries[i].Value); } output.AppendLine(); } private static string GetValue(Dictionary<ConfigDefinition, string> values, ConfigDefinition preferred, ConfigDefinition legacy, string fallback) { if (preferred != (ConfigDefinition)null && values.TryGetValue(preferred, out var value)) { return value; } if (legacy != (ConfigDefinition)null && values.TryGetValue(legacy, out value)) { return value; } return fallback; } private static Dictionary<ConfigDefinition, string> ReadValues(string path) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(); string text = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string value = text2.Substring(num + 1).Trim(); dictionary[new ConfigDefinition(text, text3)] = value; } } return dictionary; } private static List<string> FindCustomizedDroppedKeys(Dictionary<ConfigDefinition, string> values) { List<string> list = new List<string>(); foreach (KeyValuePair<ConfigDefinition, string> removedDefault in RemovedDefaults) { if (values.TryGetValue(removedDefault.Key, out var value) && !ValuesEquivalent(value, removedDefault.Value)) { list.Add(removedDefault.Key.Section + "." + removedDefault.Key.Key); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private static bool ValuesEquivalent(string left, string right) { if (string.Equals(left.Trim(), right.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } if (float.TryParse(left, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(right, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) < 0.0001f; } return false; } private static string GetBackupPath(string configPath) { string text = configPath + ".pre-dawn.bak"; if (!File.Exists(text)) { return text; } for (int i = 2; i < 1000; i++) { string text2 = configPath + $".pre-dawn.{i}.bak"; if (!File.Exists(text2)) { return text2; } } throw new IOException("Could not allocate an Eye Monster config backup filename."); } } internal sealed class EyeMonsterSpawnWeights : IWeighted, IContextualWeighted<SpawnWeightContext> { internal const int DefaultWeight = 5; internal const int MaximumWeight = 100; private readonly Func<float> _multiplier; internal EyeMonsterSpawnWeights(Func<float> multiplier) { _multiplier = multiplier ?? throw new ArgumentNullException("multiplier"); } public int GetWeight() { return Scale(5, 1f); } public int GetWeight(SpawnWeightContext context) { int moonWeight = GetMoonWeight(((SpawnWeightContext)(ref context)).Moon); if (moonWeight <= 0) { return 0; } return Scale(moonWeight, GetDungeonMultiplier(((SpawnWeightContext)(ref context)).Dungeon)); } internal static int GetMoonWeight(DawnMoonInfo moon) { if (moon == null) { return 5; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Company) || ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Unimplemented) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Test)) { return 0; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Experimentation)) { return 3; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Assurance) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Vow)) { return 5; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Offense) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.March) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Embrion)) { return 7; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Adamance)) { return 9; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Rend) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Dine)) { return 11; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Titan) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Artifice) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Liquidation)) { return 13; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Paid)) { return 10; } ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Free); return 5; } internal static float GetDungeonMultiplier(DawnDungeonInfo dungeon) { if (dungeon == null) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlow) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowThreeExits) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowExtraLarge) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Industrial) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Mechanical) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Factory) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Bunker)) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MansionFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Gothic) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Grand) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Ornate) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Lavish) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Eerie)) { return 0.75f; } if (!KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MineshaftFlow) && !((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Cavern) && !((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Quarry)) { ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Flooded); } return 0.75f; } private int Scale(int moonWeight, float dungeonMultiplier) { float num = Mathf.Clamp(_multiplier(), 0f, 5f); return Mathf.Clamp(Mathf.RoundToInt((float)moonWeight * dungeonMultiplier * num), 0, 100); } private static bool KeyEquals<T>(NamespacedKey<T> left, NamespacedKey<T> right) where T : INamespaced { if (left != null && right != null) { return ((object)left).Equals((object?)right); } return false; } } internal static class EyeMonsterTuning { internal const float InvestigateSpeed = 2.6f; internal const float AttackRange = 2.5f; internal const float NoticeViewAngle = 52f; internal const float InvestigationStopDistance = 4.5f; internal const float InvestigationDecisionDelay = 0.8f; internal const float FlashlightDetectionAngle = 25f; internal const float LoseTargetSeconds = 3.5f; internal const float FailedNoticeCooldown = 4f; internal const float AgentAngularSpeed = 180f; internal const float AgentAcceleration = 12f; internal const float AgentRadius = 0.42f; internal const float AgentHeight = 2.45f; } [BepInPlugin("y4ngz.lethalcompany.eyemonster", "Y4NGZ Eye Monster", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "eye_monster"; internal const string ScanNodeSubtitle = "Avoid its gaze"; internal const string BestiaryText = "Eye Monster\n\nDanger level: high\n\nA roaming ocular predator that approaches cautiously until a worker meets its gaze. Avoid eye contact to make it lose interest, or drive it away with a direct flashlight beam.\n\n"; internal static ManualLogSource Log; internal static EyeMonsterConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType EyeMonsterEnemy; private static bool _netcodeInitialized; private static bool _loggedScanNodeLayer; private Harmony _harmony; private void Awake() { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new EyeMonsterConfig(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Eye Monster is disabled by config."); return; } string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "eyemonster.bundle"); ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("Failed to load asset bundle at: " + text)); return; } GameObject val = ModAssets.LoadAsset<GameObject>("EyeMonster"); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Failed to load EyeMonster prefab from bundle."); return; } SetupPrefabComponents(val); EyeMonsterEnemy = CreateEnemyType(val); EyeMonsterAI component = val.GetComponent<EyeMonsterAI>(); if ((Object)(object)component == (Object)null) { Log.LogError((object)"EyeMonster prefab does not contain EyeMonsterAI."); return; } ((EnemyAI)component).enemyType = EyeMonsterEnemy; RegisterWithDawn(val); _harmony = new Harmony("y4ngz.lethalcompany.eyemonster"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"Y4NGZ Eye Monster v1.0.0 loaded."); } catch (Exception arg) { Log.LogError((object)string.Format("Failed to initialize {0}: {1}", "Y4NGZ Eye Monster", arg)); } } private static void RegisterWithDawn(GameObject prefab) { EyeMonsterSpawnWeights spawnWeights = new EyeMonsterSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(prefab); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "eye_monster"), EyeMonsterEnemy, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Eye Monster\n\nDanger level: high\n\nA roaming ocular predator that approaches cautiously until a worker meets its gaze. Avoid eye contact to make it lose interest, or drive it away with a direct flashlight beam.\n\n").CreateNameKeyword("eye monster")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[4] { Tags.Hostile, Tags.Organic, Tags.Killable, Tags.Medium }); }); } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0) { continue; } try { methodInfo.Invoke(null, null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message)); } } } } } private static void SetupPrefabComponents(GameObject prefab) { TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); EyeMonsterAI component = prefab.GetComponent<EyeMonsterAI>(); if ((Object)(object)component == (Object)null) { Log.LogError((object)"[EyeMon] EyeMonsterAI is missing from the bundled prefab."); return; } NavMeshAgent val = prefab.GetComponent<NavMeshAgent>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NavMeshAgent>(); } ConfigureAgent(val); ((EnemyAI)component).agent = val; Animator animator = ResolveAnimator(prefab, component); EnsureAnimationRelay(prefab, component, animator); EnsureEyeAnchor(prefab, component); EnsureScanNode(prefab); EnsureMapDot(prefab); EnsureCollision(prefab, component); EnsureExclusiveAudio(prefab, component); EnsureSlimeTrail(prefab, component); EnsureBehaviourStates(component); WireAudioClips(component); } private static void ConfigureAgent(NavMeshAgent agent) { agent.speed = ModConfig.RoamSpeed.Value; agent.angularSpeed = 180f; agent.acceleration = 12f; agent.stoppingDistance = 0f; agent.radius = 0.42f; agent.height = 2.45f; agent.baseOffset = 0f; agent.autoRepath = true; agent.autoTraverseOffMeshLink = true; } private static Animator ResolveAnimator(GameObject prefab, EyeMonsterAI ai) { Transform val = prefab.transform.Find("VisualRoot"); Animator val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Animator>() : prefab.GetComponent<Animator>()); if ((Object)(object)val2 == (Object)null) { val2 = prefab.GetComponentInChildren<Animator>(true); } ((EnemyAI)ai).creatureAnimator = val2; return val2; } private static void EnsureAnimationRelay(GameObject prefab, EyeMonsterAI ai, Animator animator) { if (!((Object)(object)animator == (Object)null) && !((Object)(object)((Component)animator).gameObject == (Object)(object)prefab)) { EyeMonsterAnimationRelay eyeMonsterAnimationRelay = ((Component)animator).GetComponent<EyeMonsterAnimationRelay>(); if ((Object)(object)eyeMonsterAnimationRelay == (Object)null) { eyeMonsterAnimationRelay = ((Component)animator).gameObject.AddComponent<EyeMonsterAnimationRelay>(); } eyeMonsterAnimationRelay.owner = ai; } } private static void EnsureEyeAnchor(GameObject prefab, EyeMonsterAI ai) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(prefab.transform, "Eye", new Vector3(0f, 1.45f, 0.45f)); TrySetLayer(((Component)val).gameObject, "Enemies"); ((EnemyAI)ai).eye = val; } internal static void EnsureScanNode(GameObject prefab) { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { bool flag = val2.creatureScanID >= 0; bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0; bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal); bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal); if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4)) { val = val2; } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[EyeMon] Found {componentsInChildren.Length} scan nodes; retiring every duplicate."); } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)(object)val) { RetireExtraScanNode(componentsInChildren[j], val, prefab); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.45f, 0f))); ((Object)((Component)val3).gameObject).name = "ScanNode"; TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; Log.LogInfo((object)($"[EyeMon] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>(); } ((Collider)val4).enabled = true; ((Collider)val4).isTrigger = true; val4.center = Vector3.zero; val4.size = new Vector3(1.8f, 2.2f, 1.8f); val = val ?? ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); val.headerText = "Eye Monster"; val.subText = "Avoid its gaze"; val.maxRange = 25; val.minRange = 1; val.nodeType = 1; val.requiresLineOfSight = true; } private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)extra == (Object)null) { return; } Scene scene; if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject)) { scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)extra); } else { Object.DestroyImmediate((Object)(object)extra, true); } return; } GameObject gameObject = ((Component)extra).gameObject; gameObject.SetActive(false); Collider[] components = gameObject.GetComponents<Collider>(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)gameObject); } else { Object.DestroyImmediate((Object)(object)gameObject, true); } } private static void EnsureMapDot(GameObject prefab) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Transform obj = FindOrCreateChild(prefab.transform, "MapDot", new Vector3(0f, 1.2f, 0f)); TrySetTag(((Component)obj).gameObject, "DoNotSet"); TrySetLayer(((Component)obj).gameObject, "MapRadar"); } private static void EnsureCollision(GameObject prefab, EyeMonsterAI ai) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) BoxCollider val = prefab.GetComponent<BoxCollider>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<BoxCollider>(); } ((Collider)val).enabled = true; ((Collider)val).isTrigger = false; val.center = new Vector3(0f, 1.4f, 0f); val.size = new Vector3(2.05f, 2.8f, 2.05f); Transform val2 = FindOrCreateChild(prefab.transform, "Collision", Vector3.zero); TrySetTag(((Component)val2).gameObject, "Enemy"); TrySetLayer(((Component)val2).gameObject, "Enemies"); BoxCollider val3 = ((Component)val2).GetComponent<BoxCollider>(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val2).gameObject.AddComponent<BoxCollider>(); } ((Collider)val3).enabled = true; ((Collider)val3).isTrigger = true; val3.center = new Vector3(0f, 1.45f, 0f); val3.size = new Vector3(2.3f, 2.9f, 2.3f); Rigidbody val4 = ((Component)val2).GetComponent<Rigidbody>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val2).gameObject.AddComponent<Rigidbody>(); } val4.isKinematic = true; val4.useGravity = false; val4.detectCollisions = true; WireHitDetector(((Component)val2).gameObject, ai); } private static void WireHitDetector(GameObject host, EyeMonsterAI ai) { EnemyAICollisionDetect val = host.GetComponent<EnemyAICollisionDetect>(); if ((Object)(object)val == (Object)null) { val = host.AddComponent<EnemyAICollisionDetect>(); } val.mainScript = (EnemyAI)(object)ai; val.alwaysAllowHitting = true; val.canCollideWithEnemies = false; val.onlyCollideWhenGrounded = false; } private static void EnsureExclusiveAudio(GameObject prefab, EyeMonsterAI ai) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Transform val = FindOrCreateChild(prefab.transform, "CreatureAudio", new Vector3(0f, 1.35f, 0f)); TrySetLayer(((Component)val).gameObject, "Enemies"); AudioSource val2 = ((Component)val).GetComponent<AudioSource>(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).gameObject.AddComponent<AudioSource>(); } ConfigureSpatialAudio(val2); ai.exclusiveAudioSource = val2; ((EnemyAI)ai).creatureSFX = val2; ((EnemyAI)ai).creatureVoice = val2; DisableLegacyAudio(prefab.transform.Find("CreatureSFX"), val2); DisableLegacyAudio(prefab.transform.Find("CreatureVoice"), val2); DisableLegacyAudio(prefab.transform.Find("LoopSource"), val2); } private static void DisableLegacyAudio(Transform legacyTransform, AudioSource retainedSource) { if (!((Object)(object)legacyTransform == (Object)null)) { AudioSource component = ((Component)legacyTransform).GetComponent<AudioSource>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component == (Object)(object)retainedSource)) { component.Stop(); component.playOnAwake = false; component.loop = false; component.clip = null; ((Behaviour)component).enabled = false; } } } private static void ConfigureSpatialAudio(AudioSource source) { source.playOnAwake = false; source.loop = false; source.spatialBlend = 1f; source.rolloffMode = (AudioRolloffMode)1; source.minDistance = 1f; source.maxDistance = 25f; } private static void EnsureSlimeTrail(GameObject prefab, EyeMonsterAI ai) { EyeMonsterSlimeTrail eyeMonsterSlimeTrail = prefab.GetComponent<EyeMonsterSlimeTrail>(); if ((Object)(object)eyeMonsterSlimeTrail == (Object)null) { eyeMonsterSlimeTrail = prefab.AddComponent<EyeMonsterSlimeTrail>(); } eyeMonsterSlimeTrail.slimeMaterial = LoadMaterial("EyeMonsterSlime"); ai.slimeTrail = eyeMonsterSlimeTrail; if ((Object)(object)eyeMonsterSlimeTrail.slimeMaterial == (Object)null) { Log.LogWarning((object)"[EyeMon] EyeMonsterSlime material is missing from the bundle."); } } private static void EnsureBehaviourStates(EyeMonsterAI ai) { ((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[5] { WalkingState("Roaming", walking: false), WalkingState("Investigating", walking: true), WalkingState("Chasing", walking: true), WalkingState("Attacking", walking: false), WalkingState("Fleeing", walking: true) }; ((EnemyAI)ai).currentBehaviourStateIndex = 0; ((EnemyAI)ai).previousBehaviourStateIndex = 0; ((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0]; } private static EnemyBehaviourState WalkingState(string name, bool walking) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown return new EnemyBehaviourState { name = name, IsAnimTrigger = false, parameterString = "isWalking", boolValue = walking }; } private static void WireAudioClips(EyeMonsterAI ai) { ai.idleClips = LoadAudioClips("eyemonster_idle_01", "eyemonster_idle_02"); ai.vocalClips = LoadAudioClips("eyemonster_vocal_01", "eyemonster_vocal_02"); ai.playerHitClips = LoadAudioClips("eyemonster_player_hit_01"); ai.runStepClips = LoadAudioClips("eyemonster_step_01", "eyemonster_step_02", "eyemonster_step_03"); } private static AudioClip[] LoadAudioClips(params string[] names) { AudioClip[] array = (AudioClip[])(object)new AudioClip[names.Length]; int num = 0; for (int i = 0; i < names.Length; i++) { AudioClip val = LoadAudioClip(names[i]); if ((Object)(object)val != (Object)null) { array[num++] = val; } } if (num == array.Length) { return array; } AudioClip[] array2 = (AudioClip[])(object)new AudioClip[num]; Array.Copy(array, array2, num); return array2; } private static AudioClip LoadAudioClip(string shortName) { AudioClip val = ModAssets.LoadAsset<AudioClip>(shortName) ?? ModAssets.LoadAsset<AudioClip>(shortName + ".wav"); if ((Object)(object)val != (Object)null) { return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { if (text.EndsWith("/" + shortName + ".wav", StringComparison.OrdinalIgnoreCase)) { return ModAssets.LoadAsset<AudioClip>(text); } } Log.LogWarning((object)("[EyeMon] Audio clip missing from bundle: " + shortName)); return null; } private static Material LoadMaterial(string shortName) { Material val = ModAssets.LoadAsset<Material>(shortName) ?? ModAssets.LoadAsset<Material>(shortName + ".mat"); if ((Object)(object)val != (Object)null) { return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { if (text.EndsWith("/" + shortName + ".mat", StringComparison.OrdinalIgnoreCase)) { return ModAssets.LoadAsset<Material>(text); } } return null; } private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition) { //IL_0026: 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) Transform val = parent.Find(name); if ((Object)(object)val == (Object)null) { val = new GameObject(name).transform; val.SetParent(parent, false); } val.localPosition = localPosition; return val; } private static void TrySetTag(GameObject target, string tagName) { try { target.tag = tagName; } catch (UnityException) { Log.LogWarning((object)("[EyeMon] Tag '" + tagName + "' is unavailable for '" + ((Object)target).name + "'.")); } } internal static void TrySetLayer(GameObject target, string layerName) { if (!((Object)(object)target == (Object)null)) { int num = LayerMask.NameToLayer(layerName); if (num < 0) { num = ResolveLayerFallback(layerName); } if (num < 0 || num > 31) { Log.LogWarning((object)("[EyeMon] Layer '" + layerName + "' is unavailable for '" + ((Object)target).name + "'.")); } else { target.layer = num; } } } private static int ResolveLayerFallback(string layerName) { if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase)) { return 22; } if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase)) { return 19; } return -1; } private static void EnsureHierarchyActive(Transform child, Transform stopAt) { Transform val = child; while ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); if (!((Object)(object)val == (Object)(object)stopAt)) { val = val.parent; continue; } break; } } private static EnemyType CreateEnemyType(GameObject prefab) { EnemyType obj = ScriptableObject.CreateInstance<EnemyType>(); obj.enemyName = "Eye Monster"; obj.enemyPrefab = prefab; obj.PowerLevel = ModConfig.PowerLevel.Value; obj.DiversityPowerLevel = 1; obj.MaxCount = ModConfig.MaxCount.Value; obj.canDie = true; obj.canBeStunned = true; obj.stunTimeMultiplier = 1f; obj.doorSpeedMultiplier = 1f; obj.stunGameDifficultyMultiplier = 1f; obj.destroyOnDeath = false; obj.isOutsideEnemy = false; obj.isDaytimeEnemy = false; obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f); obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.65f); obj.useNumberSpawnedFalloff = true; return obj; } } public static class PluginInfo { public const string PLUGIN_GUID = "y4ngz.lethalcompany.eyemonster"; public const string PLUGIN_NAME = "Y4NGZ Eye Monster"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace EyeMonster.Utils { public static class CreatureAudio { public static bool PlayExclusive(AudioSource source, AudioClip clip, bool interrupt) { if ((Object)(object)source == (Object)null || (Object)(object)clip == (Object)null) { return false; } if (source.isPlaying && !interrupt) { return false; } source.Stop(); source.loop = false; source.clip = clip; source.Play(); return true; } public static void Stop(AudioSource source) { if (!((Object)(object)source == (Object)null)) { source.Stop(); source.loop = false; source.clip = null; } } } } namespace EyeMonster.AI { public class EyeMonsterAI : EnemyAI { private enum AudioCue { Idle, Vocal, PlayerHit, Step } public const int StateRoaming = 0; public const int StateInvestigating = 1; public const int StateChasing = 2; public const int StateAttacking = 3; public const int StateFleeing = 4; [Header("Exclusive audio")] public AudioClip[] idleClips; public AudioClip[] vocalClips; public AudioClip[] playerHitClips; public AudioClip[] runStepClips; public AudioSource exclusiveAudioSource; [Header("Cosmetics")] public EyeMonsterSlimeTrail slimeTrail; private const float LightCheckInterval = 0.2f; private const float PassiveEyelidClosure = 0.24f; private const float FlashlightEyelidClosure = 0.72f; private const float PassiveEyelidSmoothTime = 0.42f; private const float RevealEyelidSmoothTime = 0.24f; private const float FlashlightEyelidSmoothTime = 0.16f; private const float DeathEyelidSmoothTime = 0.13f; private const float IdleAudioMinSeconds = 7.5f; private const float IdleAudioMaxSeconds = 14f; private const float ChaseRangeMultiplier = 1.75f; private const float RootBodyHeight = 2.8f; private const float RootBodyWidth = 2.05f; private const float TriggerHeight = 2.9f; private const float TriggerWidth = 2.3f; private static readonly Vector3 UpperLidOpenPosition = new Vector3(0f, 0.53408f, 0.668f); private static readonly Vector3 LowerLidOpenPosition = new Vector3(0f, 0.53408f, 0.668f); private static readonly Vector3 UpperLidClosedPosition = new Vector3(0f, 0.53408f, 0.668f); private static readonly Vector3 LowerLidClosedPosition = new Vector3(0.44242f, 0.53408f, 0.668f); private static readonly Quaternion UpperLidOpenRotation = Quaternion.identity; private static readonly Quaternion LowerLidOpenRotation = Quaternion.identity; private static readonly Quaternion UpperLidClosedRotation = Quaternion.Euler(35.10085f, 0.00239f, 0.00126f); private static readonly Quaternion LowerLidClosedRotation = Quaternion.Euler(-37.8065f, 0.00281f, -0.00115f); private readonly Dictionary<ulong, float> _noticeCooldownUntil = new Dictionary<ulong, float>(); private readonly int[] _lastAudioIndices = new int[4] { -1, -1, -1, -1 }; private float _loseTargetTimer; private float _attackCooldownTimer; private float _lightCheckTimer; private float _fleeTimer; private float _investigationStartedAt; private float _nextIdleAudioTime; private float _eyelidClosure = 0.24f; private float _eyelidClosureVelocity; private float _remoteMovingUntil; private Vector3 _lastAnimationPosition; private bool _hasLastAnimationPosition; private bool _eyelidsInitialized; private Vector3 _fleeDestination; private Vector3 _lastLightThreatPosition; private Coroutine _attackCoroutine; private bool _gazeConfirmedForTarget; private Transform _visualRoot; private Transform _eyeBone; private Transform _upperLid; private Transform _lowerLid; private float RoamSpeed => Mathf.Max(0.1f, Plugin.ModConfig.RoamSpeed.Value); private float InvestigateSpeed => 2.6f; private float ChaseSpeed => Mathf.Max(0.1f, Plugin.ModConfig.ChaseSpeed.Value); private float FleeSpeed => Mathf.Max(0.1f, Plugin.ModConfig.FleeSpeed.Value); private int AttackDamage => Mathf.Max(0, Plugin.ModConfig.AttackDamage.Value); private float AttackCooldown => Mathf.Max(0.1f, Plugin.ModConfig.AttackCooldown.Value); private float AttackRange => 2.5f; private float NoticeRange => Mathf.Max(2f, Plugin.ModConfig.NoticeRange.Value); private float NoticeViewAngle => 52f; private float PlayerGazeAngle => Mathf.Clamp(Plugin.ModConfig.GazeAngle.Value, 5f, 90f); private float InvestigationStopDistance => 4.5f; private float InvestigationDecisionDelay => 0.8f; private float FlashlightDetectionRange => Mathf.Max(2f, Plugin.ModConfig.FlashlightRange.Value); private float FlashlightDetectionAngle => 25f; private float FleeDuration => Mathf.Max(0.5f, Plugin.ModConfig.FleeDuration.Value); private float LoseTargetSeconds => 3.5f; private float FailedNoticeCooldown => 4f; internal bool ShouldEmitSlimeTrail { get { if (!base.isEnemyDead && base.ventAnimationFinished) { return base.currentBehaviourStateIndex != 3; } return false; } } private bool AgentCanNavigate { get { if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled) { return base.agent.isOnNavMesh; } return false; } } private void LogError(string message) { Plugin.Log.LogError((object)message); } private void LogDebug(string message) { EyeMonsterConfig modConfig = Plugin.ModConfig; if (modConfig != null && modConfig.DebugLogs.Value) { Plugin.Log.LogInfo((object)("[EyeMon] " + message)); } } public override void Awake() { try { ((EnemyAI)this).Awake(); RepairRuntimeLayersAndTags(); EnsureRuntimeGeometryAndHitDetection(); CacheVisualRig(); ConsolidateAudioSources(); } catch (Exception arg) { LogError($"EyeMonsterAI.Awake: {arg}"); } } public override void Start() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Start(); RepairRuntimeLayersAndTags(); EnsureRuntimeGeometryAndHitDetection(); CacheVisualRig(); ConsolidateAudioSources(); base.enemyHP = Mathf.Max(1, Plugin.ModConfig.Health.Value); ConfigureSearchDefaults(); if (((NetworkBehaviour)this).IsOwner) { RepairAgentPlacementIfNeeded(); } ConfigureAgent(RoamSpeed, 0f); slimeTrail?.Bind(this); if (((NetworkBehaviour)this).IsServer) { ResetIdleAudioTimer(); } LogDebug($"Spawned at {((Component)this).transform.position}, HP={base.enemyHP}"); } catch (Exception arg) { LogError($"EyeMonsterAI.Start: {arg}"); } } private void RepairRuntimeLayersAndTags() { int num = LayerMask.NameToLayer("Enemies"); if (num >= 0) { ((Component)this).gameObject.layer = num; } TrySetTag(((Component)this).gameObject, "Enemy"); Plugin.EnsureScanNode(((Component)this).gameObject); FixNamedChildLayer("MapDot", "MapRadar"); Transform val = ((Component)this).transform.Find("Collision"); if ((Object)(object)val != (Object)null) { if (num >= 0) { ((Component)val).gameObject.layer = num; } TrySetTag(((Component)val).gameObject, "Enemy"); } } private void FixNamedChildLayer(string childName, string layerName) { Transform val = ((Component)this).transform.Find(childName); if (!((Object)(object)val == (Object)null)) { int num = LayerMask.NameToLayer(layerName); if (num < 0) { Plugin.Log.LogWarning((object)$"[EyeMon] Layer '{layerName}' is unavailable; '{childName}' remains on layer {((Component)val).gameObject.layer}."); } else { ((Component)val).gameObject.layer = num; } } } private static void TrySetTag(GameObject target, string tagName) { if ((Object)(object)target == (Object)null) { return; } try { target.tag = tagName; } catch (UnityException) { Plugin.Log.LogWarning((object)("[EyeMon] Tag '" + tagName + "' is unavailable for '" + ((Object)target).name + "'.")); } } private void EnsureRuntimeGeometryAndHitDetection() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.agent != (Object)null) { base.agent.baseOffset = 0f; base.agent.radius = 0.42f; base.agent.height = 2.45f; base.agent.acceleration = 12f; base.agent.angularSpeed = 180f; base.agent.autoRepath = true; base.agent.autoTraverseOffMeshLink = true; } BoxCollider val = ((Component)this).GetComponent<BoxCollider>(); if ((Object)(object)val == (Object)null) { val = ((Component)this).gameObject.AddComponent<BoxCollider>(); } ((Collider)val).enabled = true; ((Collider)val).isTrigger = false; val.center = new Vector3(0f, 1.4f, 0f); val.size = new Vector3(2.05f, 2.8f, 2.05f); Transform val2 = ((Component)this).transform.Find("Collision"); if ((Object)(object)val2 == (Object)null) { val2 = new GameObject("Collision").transform; val2.SetParent(((Component)this).transform, false); } val2.localPosition = Vector3.zero; TrySetTag(((Component)val2).gameObject, "Enemy"); int num = LayerMask.NameToLayer("Enemies"); if (num >= 0) { ((Component)val2).gameObject.layer = num; } BoxCollider val3 = ((Component)val2).GetComponent<BoxCollider>(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val2).gameObject.AddComponent<BoxCollider>(); } ((Collider)val3).enabled = true; ((Collider)val3).isTrigger = true; val3.center = new Vector3(0f, 1.45f, 0f); val3.size = new Vector3(2.3f, 2.9f, 2.3f); Rigidbody val4 = ((Component)val2).GetComponent<Rigidbody>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val2).gameObject.AddComponent<Rigidbody>(); } val4.isKinematic = true; val4.useGravity = false; val4.detectCollisions = true; WireHitDetector(((Component)val2).gameObject); } private void WireHitDetector(GameObject host) { if (!((Object)(object)host == (Object)null)) { EnemyAICollisionDetect val = host.GetComponent<EnemyAICollisionDetect>(); if ((Object)(object)val == (Object)null) { val = host.AddComponent<EnemyAICollisionDetect>(); } val.mainScript = (EnemyAI)(object)this; val.alwaysAllowHitting = true; val.canCollideWithEnemies = false; val.onlyCollideWhenGrounded = false; } } private void CacheVisualRig() { if ((Object)(object)_visualRoot == (Object)null) { _visualRoot = ((Component)this).transform.Find("VisualRoot"); } if ((Object)(object)_eyeBone == (Object)null) { _eyeBone = FindDescendantByExactName(((Component)this).transform, "eye"); } if ((Object)(object)_upperLid == (Object)null) { _upperLid = FindDescendantByExactName(((Component)this).transform, "lid_up"); } if ((Object)(object)_lowerLid == (Object)null) { _lowerLid = FindDescendantByExactName(((Component)this).transform, "lid_down"); } } private static Transform FindDescendantByExactName(Transform root, string childName) { if ((Object)(object)root == (Object)null) { return null; } for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); if (string.Equals(((Object)child).name, childName, StringComparison.OrdinalIgnoreCase)) { return child; } Transform val = FindDescendantByExactName(child, childName); if ((Object)(object)val != (Object)null) { return val; } } return null; } private void LateUpdate() { try { CacheVisualRig(); SyncEyeAnchorToBone(); UpdateEyelidExpression(); } catch (Exception arg) { LogError($"EyeMonsterAI.LateUpdate: {arg}"); } } private void SyncEyeAnchorToBone() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.eye == (Object)null) { base.eye = ((Component)this).transform.Find("Eye"); } if (!((Object)(object)base.eye == (Object)null) && !((Object)(object)_eyeBone == (Object)null)) { base.eye.position = _eyeBone.position; base.eye.rotation = ((Component)this).transform.rotation; } } private void UpdateEyelidExpression() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_upperLid == (Object)null) && !((Object)(object)_lowerLid == (Object)null)) { if (!_eyelidsInitialized) { _eyelidClosure = (base.isEnemyDead ? 1f : GetDesiredEyelidClosure()); _eyelidClosureVelocity = 0f; _eyelidsInitialized = true; } float num = (base.isEnemyDead ? 1f : GetDesiredEyelidClosure()); float eyelidSmoothTime = GetEyelidSmoothTime(num); _eyelidClosure = Mathf.SmoothDamp(_eyelidClosure, num, ref _eyelidClosureVelocity, eyelidSmoothTime, 4f, Time.deltaTime); if (Mathf.Abs(_eyelidClosure - num) < 0.0005f) { _eyelidClosure = num; } float num2 = Mathf.Clamp01(_eyelidClosure); _upperLid.localPosition = Vector3.Lerp(UpperLidOpenPosition, UpperLidClosedPosition, num2); _lowerLid.localPosition = Vector3.Lerp(LowerLidOpenPosition, LowerLidClosedPosition, num2); _upperLid.localRotation = Quaternion.Slerp(UpperLidOpenRotation, UpperLidClosedRotation, num2); _lowerLid.localRotation = Quaternion.Slerp(LowerLidOpenRotation, LowerLidClosedRotation, num2); } } private float GetDesiredEyelidClosure() { switch (base.currentBehaviourStateIndex) { case 1: case 2: case 3: return 0f; case 4: return 0.72f; default: return 0.24f; } } private float GetEyelidSmoothTime(float desiredClosure) { if (base.isEnemyDead) { return 0.13f; } if (base.currentBehaviourStateIndex == 4) { return 0.16f; } if (desiredClosure <= 0.001f) { return 0.24f; } return 0.42f; } private void ConsolidateAudioSources() { AudioSource val = (((Object)(object)exclusiveAudioSource != (Object)null) ? exclusiveAudioSource : (((Object)(object)base.creatureVoice != (Object)null) ? base.creatureVoice : base.creatureSFX)); if ((Object)(object)base.creatureVoice != (Object)null && (Object)(object)base.creatureVoice != (Object)(object)val) { CreatureAudio.Stop(base.creatureVoice); } if ((Object)(object)base.creatureSFX != (Object)null && (Object)(object)base.creatureSFX != (Object)(object)val) { CreatureAudio.Stop(base.creatureSFX); } exclusiveAudioSource = val; if ((Object)(object)val != (Object)null) { val.playOnAwake = false; val.loop = false; base.creatureVoice = val; base.creatureSFX = val; } } private void RepairAgentPlacementIfNeeded() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && !base.agent.isOnNavMesh) { int num = ((base.agent.areaMask == 0) ? (-1) : base.agent.areaMask); NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(((Component)this).transform.position, ref val, 4f, num)) { Plugin.Log.LogWarning((object)$"[EyeMon] Could not place NavMeshAgent near spawn position {((Component)this).transform.position}."); return; } ((Behaviour)base.agent).enabled = false; ((Component)this).transform.position = ((NavMeshHit)(ref val)).position; ((Behaviour)base.agent).enabled = true; LogDebug($"Repaired NavMeshAgent placement to {((NavMeshHit)(ref val)).position}."); } } public override void Update() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Update(); if (base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead) { return; } if (_attackCooldownTimer > 0f) { _attackCooldownTimer -= Time.deltaTime; } UpdateWalkingAnimation(); if (((NetworkBehaviour)this).IsOwner) { switch (base.currentBehaviourStateIndex) { case 1: UpdateTargetDestination(InvestigateSpeed, InvestigationStopDistance); break; case 2: UpdateTargetDestination(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f)); break; case 4: ConfigureAgent(FleeSpeed, 0f); if (AgentCanNavigate) { ((EnemyAI)this).SetDestinationToPosition(_fleeDestination, false); } break; } } if (((NetworkBehaviour)this).IsServer) { TickIdleAudio(); } } catch (Exception arg) { LogError($"EyeMonsterAI.Update: {arg}"); } } private void UpdateWalkingAnimation() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; Vector3 val; if (_hasLastAnimationPosition) { val = position - _lastAnimationPosition; if (((Vector3)(ref val)).sqrMagnitude > 1E-06f) { _remoteMovingUntil = Time.time + 0.15f; } } _lastAnimationPosition = position; _hasLastAnimationPosition = true; if (!((Object)(object)base.creatureAnimator == (Object)null)) { int num; if (!((NetworkBehaviour)this).IsOwner) { num = ((Time.time < _remoteMovingUntil) ? 1 : 0); } else if (AgentCanNavigate) { val = base.agent.velocity; num = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; if (!base.ventAnimationFinished || base.currentBehaviourStateIndex == 3) { flag = false; } base.creatureAnimator.SetBool("isWalking", flag); } } private void UpdateTargetDestination(float speed, float stoppingDistance) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (IsValidTarget(base.targetPlayer) && AgentCanNavigate) { ConfigureAgent(speed, stoppingDistance); ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); ((EnemyAI)this).SetDestinationToPosition(((Component)base.targetPlayer).transform.position, false); } } public override void DoAIInterval() { try { ((EnemyAI)this).DoAIInterval(); if (!base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && ((NetworkBehaviour)this).IsOwner && (base.currentBehaviourStateIndex == 4 || !TryBeginFlashlightFlee())) { switch (base.currentBehaviourStateIndex) { case 0: DoRoaming(); break; case 1: DoInvestigating(); break; case 2: DoChasing(); break; case 4: DoFleeing(); break; case 3: break; } } } catch (Exception arg) { LogError($"EyeMonsterAI.DoAIInterval: {arg}"); } } private void DoRoaming() { ConfigureAgent(RoamSpeed, 0f); StartFacilitySearchIfNeeded(); PlayerControllerB val = FindNoticeTarget(); if (!((Object)(object)val == (Object)null)) { StopFacilitySearch(); base.targetPlayer = val; _gazeConfirmedForTarget = false; _loseTargetTimer = 0f; _investigationStartedAt = Time.time; ((EnemyAI)this).SetMovingTowardsTargetPlayer(val); PlayNetworkedCue(AudioCue.Vocal, interrupt: true); ((EnemyAI)this).SwitchToBehaviourState(1); LogDebug("Noticed " + val.playerUsername + "; beginning cautious approach."); } } private void DoInvestigating() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!IsValidTarget(base.targetPlayer)) { DropTarget(addNoticeCooldown: false); return; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position); if (!(num <= NoticeRange * 1.75f) || !HasClearSightToPlayer(base.targetPlayer)) { _loseTargetTimer += base.AIIntervalTime; if (_loseTargetTimer >= LoseTargetSeconds) { DropTarget(addNoticeCooldown: true); } return; } _loseTargetTimer = 0f; ConfigureAgent(InvestigateSpeed, InvestigationStopDistance); ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); if (!(num > InvestigationStopDistance) && !(Time.time - _investigationStartedAt < InvestigationDecisionDelay)) { StopAgentPath(); FaceTarget(base.targetPlayer); if (IsMutualGaze(base.targetPlayer)) { _gazeConfirmedForTarget = true; PlayNetworkedCue(AudioCue.Vocal, interrupt: true); ConfigureAgent(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f)); ((EnemyAI)this).SwitchToBehaviourState(2); LogDebug(base.targetPlayer.playerUsername + " looked at the eye; aggro confirmed."); } else { LogDebug(base.targetPlayer.playerUsername + " refused eye contact; forgetting target."); DropTarget(addNoticeCooldown: true); } } } private void DoChasing() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!IsValidTarget(base.targetPlayer) || !_gazeConfirmedForTarget) { DropTarget(addNoticeCooldown: false); return; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position); if (!(num <= NoticeRange * 1.75f) || !HasClearSightToPlayer(base.targetPlayer)) { _loseTargetTimer += base.AIIntervalTime; if (_loseTargetTimer >= LoseTargetSeconds) { LogDebug($"Lost {base.targetPlayer.playerUsername} after {_loseTargetTimer:F1}s."); DropTarget(addNoticeCooldown: false); return; } } else { _loseTargetTimer = 0f; } ConfigureAgent(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f)); ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); if (num <= AttackRange && _attackCooldownTimer <= 0f) { EnterAttacking(); } } private void EnterAttacking() { if (_gazeConfirmedForTarget && IsValidTarget(base.targetPlayer)) { StopAgentPath(); ((EnemyAI)this).SwitchToBehaviourState(3); TriggerAttackAnimationNetworked(); if (_attackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_attackCoroutine); } _attackCoroutine = ((MonoBehaviour)this).StartCoroutine(AttackRoutine()); } } private IEnumerator AttackRoutine() { try { _attackCooldownTimer = AttackCooldown; } catch (Exception arg) { LogError($"AttackRoutine begin: {arg}"); _attackCoroutine = null; yield break; } yield return (object)new WaitForSeconds(AttackCooldown); try { if (base.isEnemyDead || base.currentBehaviourStateIndex == 4) { _attackCoroutine = null; yield break; } if (!IsValidTarget(base.targetPlayer) || !_gazeConfirmedForTarget) { DropTarget(addNoticeCooldown: false); } else if (Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) <= NoticeRange * 1.75f) { ((EnemyAI)this).SwitchToBehaviourState(2); } else { DropTarget(addNoticeCooldown: false); } } catch (Exception arg2) { LogError($"AttackRoutine end: {arg2}"); } _attackCoroutine = null; } private void TriggerAttackAnimationNetworked() { if (((NetworkBehaviour)this).IsServer) { PlayAttackAnimationClientRpc(); } else { RequestAttackAnimationServerRpc(); } } [ServerRpc(RequireOwnership = false)] public void RequestAttackAnimationServerRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(4159574820u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 4159574820u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!base.isEnemyDead) { PlayAttackAnimationClientRpc(); } } } [ClientRpc] public void PlayAttackAnimationClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1996458905u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1996458905u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!base.isEnemyDead && (Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.SetTrigger("doAttack"); } } } private PlayerControllerB FindNoticeTarget() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_009d: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB result = null; float num = float.PositiveInfinity; float num2 = NoticeRange * NoticeRange; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (IsValidTarget(val) && !IsNoticeCoolingDown(val)) { Vector3 val2 = (((Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform.position : (((Component)val).transform.position + Vector3.up)); Vector3 val3 = val2 - GetEyeFocusPosition(); float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (!(sqrMagnitude > num2) && !(sqrMagnitude >= num) && ((EnemyAI)this).CheckLineOfSightForPosition(val2, NoticeViewAngle, Mathf.CeilToInt(NoticeRange), -1f, base.eye)) { result = val; num = sqrMagnitude; } } } return result; } private bool IsMutualGaze(PlayerControllerB player) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (!IsValidTarget(player)) { return false; } Vector3 val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : (((Component)player).transform.position + Vector3.up)) - GetEyeFocusPosition(); if (!(((Vector3)(ref val)).sqrMagnitude > 0.001f) || !(Vector3.Angle(((Component)this).transform.forward, val) <= NoticeViewAngle) || !HasClearSightToPlayer(player)) { return false; } return player.HasLineOfSightToPosition(GetEyeFocusPosition(), PlayerGazeAngle, Mathf.CeilToInt(NoticeRange + 6f), -1f, -1); } private bool HasClearSightToPlayer(PlayerControllerB player) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!IsValidTarget(player)) { return false; } Vector3 val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : (((Component)player).transform.position + Vector3.up)); return ((EnemyAI)this).CheckLineOfSightForPosition(val, 180f, Mathf.CeilToInt(NoticeRange * 1.75f), -1f, base.eye); } private Vector3 GetEyeFocusPosition() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.eye != (Object)null)) { return ((Component)this).transform.position + Vector3.up * 1.45f; } return base.eye.position; } private static bool IsValidTarget(PlayerControllerB player) { if ((Object)(object)player != (Object)null && player.isPlayerControlled) { return !player.isPlayerDead; } return false; } private bool IsNoticeCoolingDown(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } if (_noticeCooldownUntil.TryGetValue(player.actualClientId, out var value)) { return Time.time < value; } return false; } private void DropTarget(bool addNoticeCooldown) { PlayerControllerB targetPlayer = base.targetPlayer; if (addNoticeCooldown && (Object)(object)targetPlayer != (Object)null) { _noticeCooldownUntil[targetPlayer.actualClientId] = Time.time + FailedNoticeCooldown; } base.targetPlayer = null; base.movingTowardsTargetPlayer = false; _gazeConfirmedForTarget = false; _loseTargetTimer = 0f; if (_attackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_attackCoroutine); _attackCoroutine = null; } ConfigureAgent(RoamSpeed, 0f); if (base.currentBehaviourStateIndex != 0) { ((EnemyAI)this).SwitchToBehaviourState(0); } } private void FaceTarget(PlayerControllerB player) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null)) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f)) { Quaternion rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); ((Component)this).transform.rotation = rotation; } } } private void ConfigureSearchDefaults() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown if (base.currentSearch == null) { base.currentSearch = new AISearchRoutine(); } base.currentSearch.loopSearch = true; base.currentSearch.randomized = true; base.currentSearch.searchWidth = 200f; base.currentSearch.searchPrecision = 5f; } private void StartFacilitySearchIfNeeded() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsOwner && AgentCanNavigate) { ConfigureSearchDefaults(); if (!base.currentSearch.inProgress) { ((EnemyAI)this).StartSearch(((Component)this).transform.position, base.currentSearch); } } } private void StopFacilitySearch() { if (base.currentSearch != null && base.currentSearch.inProgress) { ((EnemyAI)this).StopSearch(base.currentSearch, false); } } private void ConfigureAgent(float speed, float stoppingDistance) { if (AgentCanNavigate) { base.agent.speed = speed; base.agent.stoppingDistance = stoppingDistance; } } private void StopAgentPath() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) base.movingTowardsTargetPlayer = false; if (AgentCanNavigate) { base.agent.ResetPath(); base.agent.velocity = Vector3.zero; base.agent.speed = 0f; } } private bool TryBeginFlashlightFlee() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) _lightCheckTimer += base.AIIntervalTime; if (_lightCheckTimer < 0.2f) { return false; } _lightCheckTimer = 0f; if (!TryGetFlashlightThreat(out var threatPosition, out var threatPlayer)) { return false; } if ((Object)(object)threatPlayer != (Object)null) { _lastLightThreatPosition = ((Component)threatPlayer).transform.position; } StartFleeFrom(threatPosition); return true; } private void DoFleeing() { ConfigureAgent(FleeSpeed, 0f); TryRefreshFlashlightFlee(); _fleeTimer -= base.AIIntervalTime; if (_fleeTimer <= 0f) { LogDebug("Flashlight flee expired; returning to facility search."); DropTarget(addNoticeCooldown: false); } } private void TryRefreshFlashlightFlee() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) _lightCheckTimer += base.AIIntervalTime; if (_lightCheckTimer < 0.2f) { return; } _lightCheckTimer = 0f; if (TryGetFlashlightThreat(out var threatPosition, out var threatPlayer)) { if ((Object)(object)threatPlayer != (Object)null) { _lastLightThreatPosition = ((Component)threatPlayer).transform.position; } StartFleeFrom(threatPosition); } } private void StartFleeFrom(Vector3 threatPosition) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //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_007c: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) bool num = base.currentBehaviourStateIndex != 4; _fleeTimer = FleeDuration; base.targetPlayer = null; base.movingTowardsTargetPlayer = false; _gazeConfirmedForTarget = false; _loseTargetTimer = 0f; if (_attackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_attackCoroutine); _attackCoroutine = null; } StopFacilitySearch(); Vector3 val = ((threatPosition == Vector3.zero) ? _lastLightThreatPosition : threatPosition); Vector3 val2 = ((Component)this).transform.position - val; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = -((Component)this).transform.forward; } ((Vector3)(ref val2)).Normalize(); NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(((Component)this).transform.position + val2 * 20f, ref val3, 15f, -1)) { _fleeDestination = ((NavMeshHit)(ref val3)).position; } else { _fleeDestination = ((Component)this).transform.position + val2 * 10f; } ConfigureAgent(FleeSpeed, 0f); if (AgentCanNavigate) { ((EnemyAI)this).SetDestinationToPosition(_fleeDestination, false); } if (num) { ((EnemyAI)this).SwitchToBehaviourState(4); } } private bool TryGetFlashlightThreat(out Vector3 threatPosition, out PlayerControllerB threatPlayer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) threatPosition = Vector3.zero; threatPlayer = null; if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return false; } float angleCosine = Mathf.Cos(Mathf.Clamp(FlashlightDetectionAngle, 1f, 89f) * (MathF.PI / 180f)); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (IsValidTarget(val) && (CheckFlashlightSource(val, FlashlightDetectionRange, angleCosine, out threatPosition) || CheckHelmetLight(val, FlashlightDetectionRange, angleCosine, out threatPosition))) { threatPlayer = val; _lastLightThreatPosition = threatPosition; return true; } } return false; } private bool CheckFlashlightSource(PlayerControllerB player, float range, float angleCosine, out Vector3 sourcePosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) sourcePosition = Vector3.zero; GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer; FlashlightItem val = (FlashlightItem)(object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null); if ((Object)(object)val == (Object)null || !((GrabbableObject)val).isBeingUsed) { return false; } Transform val2 = (((Object)(object)val.flashlightBulb != (Object)null) ? ((Component)val.flashlightBulb).transform : ((Component)val).transform); if (CheckLightBeam(val2.position, val2.forward, GetEyeFocusPosition(), range, angleCosine)) { sourcePosition = val2.position; return true; } if ((Object)(object)val.flashlightBulbGlow != (Object)null && CheckLightBeam(((Component)val.flashlightBulbGlow).transform.position, ((Component)val.flashlightBulbGlow).transform.forward, GetEyeFocusPosition(), range, angleCosine)) { sourcePosition = ((Component)val.flashlightBulbGlow).transform.position; return true; } return false; } private bool CheckHelmetLight(PlayerControllerB player, float range, float angleCosine, out Vector3 sourcePosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //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) sourcePosition = Vector3.zero; Light helmetLight = player.helmetLight; if ((Object)(object)helmetLight == (Object)null || !((Behaviour)helmetLight).enabled || helmetLight.intensity <= 0f) { return false; } Transform val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)helmetLight).transform); if (!CheckLightBeam(val.position, val.forward, GetEyeFocusPosition(), range, angleCosine)) { return false; } sourcePosition = val.position; return true; } private bool CheckLightBeam(Vector3 sourcePosition, Vector3 sourceForward, Vector3 detectionPoint, float range, float angleCosine) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = detectionPoint - sourcePosition; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.01f || magnitude > range) { return false; } Vector3 val2 = val / magnitude; if (Vector3.Dot(((Vector3)(ref sourceForward)).normalized, val2) > angleCosine) { return HasClearLightPath(sourcePosition, detectionPoint); } return false; } private bool HasClearLightPath(Vector3 sourcePosition, Vector3 detectionPoint) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return true; } Vector3 val = detectionPoint - sourcePosition; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.01f) { return true; } RaycastHit[] array = Physics.RaycastAll(sourcePosition, val / magnitude, magnitude, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { Collider collider = ((RaycastHit)(ref array[i])).collider; if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)this).transform)) { return false; } } return true; } private void TickIdleAudio() { if (!(Time.time < _nextIdleAudioTime)) { ResetIdleAudioTimer(); if (base.currentBehaviourStateIndex == 0 || base.currentBehaviourStateIndex == 1) { BroadcastAudioCue(AudioCue.Idle, interrupt: false); } } } private void ResetIdleAudioTimer() { _nextIdleAudioTime = Time.time + Random.Range(7.5f, 14f); } private void PlayNetworkedCue(AudioCue cue, bool interrupt) { if (((NetworkBehaviour)this).IsServer) { BroadcastAudioCue(cue, interrupt); } else { RequestAudioCueServerRpc((int)cue, interrupt); } } [ServerRpc(RequireOwnership = false)] public void RequestAudioCueServerRpc(int cueValue, bool interrupt) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (migh
SimonSays.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using SimonSays.AI; using SimonSays.NetcodePatcher; using SimonSays.Utils; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SimonSays")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("SimonSays")] [assembly: AssemblyTitle("SimonSays")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 SimonSays { [BepInPlugin("y4ngz.lethalcompany.simonsays", "Y4NGZ Simon Says", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string DisplayName = "Simon Says"; internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "simon_says"; internal const string TerminalKeyword = "simon"; internal const string ScanNodeSubtitle = "Only obey when Simon says"; internal const string BestiaryText = "Simon Says\n\nDanger level: 100%\n\nSigurd's notes: It's a wheeled jester cart with a clockwork skull. It picks one crew member, puts a spotlight on them, and plays a game. Three commands. It cannot be killed, and when it is done it leaves in a cloud of smoke.\n\nThe rule is the whole trick: only obey a command it prefixes with \"Simon says\". Obey one it does not, and it kills you for it. Ignore one it does, and it kills you for that too. Listen for the words \"and\" (either order) versus \"then\" (that order).\n\n"; internal static ManualLogSource Log; private static bool _loggedScanNodeLayer; internal static SimonSaysConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType SimonSaysEnemy; internal static AudioClip LetsPlayClip; internal static AudioClip SimonSaysWordClip; internal static AudioClip AndClip; internal static AudioClip ThenClip; internal static AudioClip CongratulationsClip; internal static AudioClip GoodbyeClip; private static readonly AudioClip[] _actionClips = (AudioClip[])(object)new AudioClip[4]; internal static AudioClip SpotlightStartClip; internal static GameObject VanishSmokePrefab; private const string SpotlightStartSfxFileName = "simon_says_spotlight.mp3"; private static bool _netcodeInitialized = false; private Harmony _harmony; internal static AudioClip ActionClip(ActionType action) { if (action < ActionType.Jump || (int)action >= _actionClips.Length) { return null; } return _actionClips[(int)action]; } private void Awake() { //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new SimonSaysConfig(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Simon Says is disabled in config; skipping registration."); return; } if (ModConfig?.DebugLogs?.Value == true) { ProbeRpcFuncTables(); } string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ((MonoBehaviour)this).StartCoroutine(LoadSpotlightStartClip(directoryName)); string text = Path.Combine(directoryName, "simonsays.bundle"); ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("Failed to load asset bundle at: " + text)); return; } GameObject val = LoadEnemyPrefab(); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Failed to load SimonSays prefab from bundle. Available assets:"); string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text2 in allAssetNames) { Log.LogError((object)(" - " + text2)); } return; } Log.LogInfo((object)("Loaded prefab '" + ((Object)val).name + "' with " + $"{val.GetComponents<Component>().Length} root components.")); LoadAudioFromBundle(); LoadEffectsFromBundle(); AssignUniqueNetworkHash(val); RebindTexturesFromBundle(val); SetupPrefabComponents(val); SimonSaysEnemy = CreateEnemyType(val); SimonSaysAI component = val.GetComponent<SimonSaysAI>(); if ((Object)(object)component != (Object)null) { ((EnemyAI)component).enemyType = SimonSaysEnemy; } SimonSaysSpawnWeights spawnWeights = new SimonSaysSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(val); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "simon_says"), SimonSaysEnemy, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Simon Says\n\nDanger level: 100%\n\nSigurd's notes: It's a wheeled jester cart with a clockwork skull. It picks one crew member, puts a spotlight on them, and plays a game. Three commands. It cannot be killed, and when it is done it leaves in a cloud of smoke.\n\nThe rule is the whole trick: only obey a command it prefixes with \"Simon says\". Obey one it does not, and it kills you for it. Ignore one it does, and it kills you for that too. Listen for the words \"and\" (either order) versus \"then\" (that order).\n\n").CreateNameKeyword("simon")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[3] { Tags.Hostile, Tags.Mechanical, Tags.Medium }); }); _harmony = new Harmony("y4ngz.lethalcompany.simonsays"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"Y4NGZ Simon Says v1.0.1 loaded."); } catch (Exception arg) { Log.LogError((object)string.Format("Failed to initialize {0}: {1}", "Y4NGZ Simon Says", arg)); } } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch (Exception ex) { Log.LogWarning((object)("[NetcodeInit] skipped type " + type.FullName + ": " + ex.GetType().Name)); continue; } MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0) { try { methodInfo.Invoke(null, null); Log.LogInfo((object)("[NetcodeInit] invoked " + type.Name + "." + methodInfo.Name)); } catch (Exception arg) { Log.LogError((object)$"[NetcodeInit] {type.Name}.{methodInfo.Name} threw: {arg}"); } } } } } private static void ProbeRpcFuncTables() { try { FieldInfo fieldInfo = AccessTools.TypeByName("Unity.Netcode.NetworkManager")?.GetField("__rpc_func_table", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { IDictionary dictionary = fieldInfo.GetValue(null) as IDictionary; Log.LogInfo((object)$"[NetcodeInit] post-scan NetworkManager.__rpc_func_table count: {dictionary?.Count ?? (-1)}"); if (dictionary != null) { foreach (object key in dictionary.Keys) { Log.LogInfo((object)$"[NetcodeInit] NM key: {key}"); } } } else { Log.LogWarning((object)"[NetcodeInit] NetworkManager.__rpc_func_table field not found"); } } catch (Exception arg) { Log.LogError((object)$"[NetcodeInit] NM probe threw: {arg}"); } try { FieldInfo fieldInfo2 = AccessTools.TypeByName("Unity.Netcode.NetworkBehaviour")?.GetField("__rpc_func_table", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo2 != null) { IDictionary dictionary2 = fieldInfo2.GetValue(null) as IDictionary; Log.LogInfo((object)$"[NetcodeInit] post-scan NetworkBehaviour.__rpc_func_table type-count: {dictionary2?.Count ?? (-1)}"); if (dictionary2 == null) { return; } { foreach (DictionaryEntry item in dictionary2) { int num = (item.Value as IDictionary)?.Count ?? (-1); Log.LogInfo((object)$"[NetcodeInit] NB type={item.Key} inner-count={num}"); } return; } } Log.LogWarning((object)"[NetcodeInit] NetworkBehaviour.__rpc_func_table field not found"); } catch (Exception arg2) { Log.LogError((object)$"[NetcodeInit] NB probe threw: {arg2}"); } } private static GameObject LoadEnemyPrefab() { string[] array = new string[4] { "Assets/Y4NGZ/SimonSays/SimonSays.prefab", "assets/y4ngz/simonsays/simonsays.prefab", "Assets/SimonSays/SimonSays.prefab", "assets/simonsays/simonsays.prefab" }; foreach (string text in array) { GameObject val = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<SimonSaysAI>() != (Object)null) { Log.LogInfo((object)("Loaded SimonSays prefab by path '" + text + "'.")); return val; } } GameObject[] array2 = ModAssets.LoadAllAssets<GameObject>(); foreach (GameObject val2 in array2) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<SimonSaysAI>() != (Object)null) { Log.LogWarning((object)("SimonSays prefab not at any known path; recovered '" + ((Object)val2).name + "' by scanning the bundle for SimonSaysAI. Update knownPaths.")); return val2; } } return null; } private static void LoadAudioFromBundle() { LetsPlayClip = LoadClip("ss_lets_play"); SimonSaysWordClip = LoadClip("ss_simon_says"); AndClip = LoadClip("ss_and"); ThenClip = LoadClip("ss_then"); CongratulationsClip = LoadClip("ss_congratulations"); GoodbyeClip = LoadClip("ss_goodbye"); _actionClips[0] = LoadClip("ss_jump"); _actionClips[1] = LoadClip("ss_crouch"); _actionClips[2] = LoadClip("ss_dance"); _actionClips[3] = LoadClip("ss_turn_around"); WarnIfMissing(LetsPlayClip, "ss_lets_play"); WarnIfMissing(CongratulationsClip, "ss_congratulations"); WarnIfMissing(GoodbyeClip, "ss_goodbye"); if ((1u & (RequireCommandClip(SimonSaysWordClip, "ss_simon_says") ? 1u : 0u) & (RequireCommandClip(AndClip, "ss_and") ? 1u : 0u) & (RequireCommandClip(ThenClip, "ss_then") ? 1u : 0u) & (RequireCommandClip(_actionClips[0], "ss_jump") ? 1u : 0u) & (RequireCommandClip(_actionClips[1], "ss_crouch") ? 1u : 0u) & (RequireCommandClip(_actionClips[2], "ss_dance") ? 1u : 0u) & (RequireCommandClip(_actionClips[3], "ss_turn_around") ? 1u : 0u)) == 0) { Log.LogFatal((object)"[SimonSays] Command word bank is incomplete; SimonSays will not register because a partial spoken command must never be judged."); throw new InvalidDataException("[SimonSays] Command word bank is incomplete; SimonSays will not register because a partial spoken command must never be judged."); } } private static void WarnIfMissing(AudioClip clip, string name) { if ((Object)(object)clip == (Object)null) { Log.LogError((object)("SimonSays audio '" + name + "' not found in bundle.")); } } private static bool RequireCommandClip(AudioClip clip, string name) { if ((Object)(object)clip != (Object)null) { return true; } Log.LogFatal((object)("[SimonSays] Required command clip '" + name + "' not found in bundle.")); return false; } private static void LoadEffectsFromBundle() { VanishSmokePrefab = ModAssets.LoadAsset<GameObject>("SimonSaysVanishSmoke") ?? ModAssets.LoadAsset<GameObject>("Assets/Y4NGZ/SimonSays/Effects/SimonSaysVanishSmoke.prefab"); if ((Object)(object)VanishSmokePrefab == (Object)null) { Log.LogWarning((object)"SimonSaysVanishSmoke prefab not in bundle; the vanish will use the code-built smoke cloud instead."); } } private static void RebindTexturesFromBundle(GameObject prefab) { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) try { Texture2D val = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture"); Texture2D val2 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_normal"); Texture2D val3 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_metallic"); Texture2D val4 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_emission"); if ((Object)(object)val == (Object)null) { Log.LogWarning((object)"Albedo texture missing from bundle."); } else { Log.LogInfo((object)$"Albedo loaded: {((Texture)val).width}x{((Texture)val).height}"); } int num = 0; Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val5 in sharedMaterials) { if (!((Object)(object)val5 == (Object)null)) { if ((Object)(object)val != (Object)null) { val5.SetTexture("_BaseColorMap", (Texture)(object)val); val5.SetTexture("_MainTex", (Texture)(object)val); val5.SetColor("_BaseColor", Color.white); val5.SetColor("_Color", Color.white); } if ((Object)(object)val2 != (Object)null) { val5.SetTexture("_NormalMap", (Texture)(object)val2); val5.SetTexture("_BumpMap", (Texture)(object)val2); val5.EnableKeyword("_NORMALMAP"); val5.EnableKeyword("_NORMALMAP_TANGENT_SPACE"); } if ((Object)(object)val3 != (Object)null) { val5.SetTexture("_MaskMap", (Texture)(object)val3); val5.SetTexture("_MetallicGlossMap", (Texture)(object)val3); val5.EnableKeyword("_MASKMAP"); } if ((Object)(object)val4 != (Object)null) { val5.SetTexture("_EmissiveColorMap", (Texture)(object)val4); val5.SetTexture("_EmissionMap", (Texture)(object)val4); val5.EnableKeyword("_EMISSIVE_COLOR_MAP"); } num++; } } } Log.LogInfo((object)$"RebindTexturesFromBundle: applied to {num} material slot(s)."); } catch (Exception arg) { Log.LogError((object)$"RebindTexturesFromBundle: {arg}"); } } private static void AssignUniqueNetworkHash(GameObject prefab) { try { NetworkObject component = prefab.GetComponent<NetworkObject>(); if ((Object)(object)component == (Object)null) { Log.LogWarning((object)"Prefab missing NetworkObject — skipping hash override"); return; } uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.simonsays.SimonSays")), 0); PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(component, num); } else { FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(component, num); } else { Log.LogWarning((object)"Could not locate GlobalObjectIdHash via property or field — hash unchanged"); } } Log.LogInfo((object)$"SimonSays NetworkObject GlobalObjectIdHash = {num}"); } catch (Exception arg) { Log.LogError((object)$"AssignUniqueNetworkHash: {arg}"); } } private static AudioClip LoadClip(params string[] candidates) { foreach (string text in candidates) { AudioClip val = ModAssets.LoadAsset<AudioClip>(text); if ((Object)(object)val != (Object)null) { return val; } } return null; } private IEnumerator LoadSpotlightStartClip(string assemblyDir) { string path = Path.Combine(assemblyDir, "simon_says_spotlight.mp3"); if (!File.Exists(path)) { Log.LogWarning((object)("Spotlight start sound missing: " + path)); yield break; } UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, (AudioType)13); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Log.LogWarning((object)("Failed loading spotlight start sound '" + path + "': " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { Log.LogWarning((object)("Spotlight start sound decoded null: " + path)); yield break; } ((Object)content).name = "SimonSays_SpotlightStart"; SpotlightStartClip = content; Log.LogInfo((object)("Loaded spotlight start sound from '" + path + "'.")); } finally { ((IDisposable)request)?.Dispose(); } } private static void SetupPrefabComponents(GameObject prefab) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown EnsureScanNode(prefab); SimonSaysAI component = prefab.GetComponent<SimonSaysAI>(); if ((Object)(object)component != (Object)null) { EnsureNavigation(prefab, component); ((EnemyAI)component).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[8] { new EnemyBehaviourState { name = "Roaming", IsAnimTrigger = false, parameterString = "isWalking", boolValue = true }, new EnemyBehaviourState { name = "Approaching", IsAnimTrigger = false, parameterString = "isWalking", boolValue = true }, new EnemyBehaviourState { name = "Intro", IsAnimTrigger = true, parameterString = "command" }, new EnemyBehaviourState { name = "Commanding", IsAnimTrigger = true, parameterString = "command" }, new EnemyBehaviourState { name = "Judging", IsAnimTrigger = false, parameterString = "isWalking", boolValue = false }, new EnemyBehaviourState { name = "Punishing", IsAnimTrigger = true, parameterString = "playerFailed" }, new EnemyBehaviourState { name = "Celebrating", IsAnimTrigger = true, parameterString = "playerPassed" }, new EnemyBehaviourState { name = "Departing", IsAnimTrigger = false, parameterString = "isWalking", boolValue = true } }; EnsureCollision(prefab, component); } } private static void EnsureNavigation(GameObject prefab, SimonSaysAI ai) { NavMeshAgent val = prefab.GetComponent<NavMeshAgent>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<NavMeshAgent>(); val.radius = 0.5f; val.height = 2f; val.baseOffset = 0f; val.angularSpeed = 240f; val.acceleration = 12f; val.autoBraking = true; val.areaMask = -1; Log.LogWarning((object)"[SimonSays] Prefab was missing a root NavMeshAgent; added a vanilla-compatible runtime agent."); } val.speed = ModConfig?.ApproachSpeed?.Value ?? 3.5f; ((EnemyAI)ai).agent = val; } internal static void EnsureScanNode(GameObject prefab) { //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)(object)prefab)) { bool flag = val2.creatureScanID >= 0; bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0; bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal); bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal); if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4)) { val = val2; } } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[SimonSays] Found {componentsInChildren.Length} scan nodes; retiring every duplicate."); } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)(object)val) { RetireExtraScanNode(componentsInChildren[j], val, prefab); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.25f, 0f))); ((Object)((Component)val3).gameObject).name = "ScanNode"; val3.localRotation = Quaternion.identity; val3.localScale = Vector3.one; TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)($"[SimonSays] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } } BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>(); } ((Collider)val4).enabled = true; ((Collider)val4).isTrigger = true; val4.center = Vector3.zero; val4.size = new Vector3(1.2f, 1.8f, 1.2f); if ((Object)(object)val == (Object)null) { val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); } val.headerText = "Simon Says"; val.subText = "Only obey when Simon says"; val.maxRange = 13; val.minRange = 1; val.requiresLineOfSight = true; val.nodeType = 1; } private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)extra == (Object)null) { return; } Scene scene; if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject)) { ((Behaviour)extra).enabled = false; scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)extra); } else { Object.DestroyImmediate((Object)(object)extra, true); } return; } GameObject gameObject = ((Component)extra).gameObject; gameObject.SetActive(false); Collider[] components = gameObject.GetComponents<Collider>(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)gameObject); } else { Object.DestroyImmediate((Object)(object)gameObject, true); } } private static void EnsureCollision(GameObject prefab, SimonSaysAI ai) { //IL_0030: 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_0098: Unknown result type (might be due to invalid IL or missing references) TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1f, 0f)); TrySetTag(((Component)val).gameObject, "Enemy"); TrySetLayer(((Component)val).gameObject, "Enemies"); BoxCollider obj = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>(); ((Collider)obj).enabled = true; ((Collider)obj).isTrigger = true; obj.center = Vector3.zero; obj.size = new Vector3(1.25f, 1.85f, 1.25f); Rigidbody obj2 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>(); obj2.isKinematic = true; obj2.useGravity = false; obj2.detectCollisions = true; EnemyAICollisionDetect obj3 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>(); obj3.mainScript = (EnemyAI)(object)ai; obj3.alwaysAllowHitting = true; obj3.canCollideWithEnemies = false; obj3.onlyCollideWhenGrounded = false; } private static EnemyType CreateEnemyType(GameObject prefab) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown EnemyType val = ScriptableObject.CreateInstance<EnemyType>(); val.enemyName = "Simon Says"; val.enemyPrefab = prefab; val.PowerLevel = ModConfig.PowerLevel.Value; val.DiversityPowerLevel = 1; val.MaxCount = 1; val.canDie = false; val.canBeStunned = false; val.canBeDestroyed = true; val.stunTimeMultiplier = 1f; val.stunGameDifficultyMultiplier = 1f; val.destroyOnDeath = false; val.doorSpeedMultiplier = 1f; val.isOutsideEnemy = false; val.isDaytimeEnemy = false; val.normalizedTimeInDayToLeave = 1f; val.probabilityCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 1f), new Keyframe(1f, 1f) }); val.numberSpawnedFalloff = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 1f), new Keyframe(1f, 1f) }); return val; } private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { return val; } val = new GameObject(name).transform; val.SetParent(parent, false); val.localPosition = localPosition; return val; } private static void TrySetTag(GameObject gameObject, string tag) { try { gameObject.tag = tag; } catch { } } private static void TrySetLayer(GameObject gameObject, string layerName) { if ((Object)(object)gameObject == (Object)null) { return; } int num = LayerMask.NameToLayer(layerName); if (num < 0) { num = ResolveLayerFallback(layerName); } if (num >= 0 && num <= 31) { gameObject.layer = num; return; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[SimonSays] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}."); } } private static int ResolveLayerFallback(string layerName) { if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase)) { return 22; } if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase)) { return 19; } return -1; } private static void EnsureHierarchyActive(Transform child, Transform stopAt) { Transform val = child; while ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(true); if (!((Object)(object)val == (Object)(object)stopAt)) { val = val.parent; continue; } break; } } } public static class PluginInfo { public const string PLUGIN_GUID = "y4ngz.lethalcompany.simonsays"; public const string PLUGIN_NAME = "Y4NGZ Simon Says"; public const string PLUGIN_VERSION = "1.0.1"; } public sealed class SimonSaysConfig { private const string SectionGeneral = "General"; private const string SectionSpawning = "Spawning"; private const string SectionMovement = "Movement"; private const string SectionAbilities = "Abilities"; private const string SectionPresentation = "Audio and Presentation"; private const string SectionDiagnostics = "Diagnostics"; public ConfigEntry<bool> Enabled { get; } public ConfigEntry<float> SpawnWeightMultiplier { get; } public ConfigEntry<float> PowerLevel { get; } public ConfigEntry<float> ApproachSpeed { get; } public ConfigEntry<float> RetreatDuration { get; } public ConfigEntry<int> RoundsPerEncounter { get; } public ConfigEntry<float> ComplianceWindowSeconds { get; } public ConfigEntry<float> TrapWindowSeconds { get; } public ConfigEntry<float> SimonSaysChance { get; } public ConfigEntry<float> TwoActionRoundChance { get; } public ConfigEntry<float> BetweenRoundPause { get; } public ConfigEntry<float> SpotlightIntensity { get; } public ConfigEntry<bool> DebugLogs { get; } public ConfigEntry<bool> VanishSmokeForceHdrpShaders { get; } public int Rounds => Mathf.Clamp(RoundsPerEncounter.Value, 1, 8); public float Window => Mathf.Clamp(ComplianceWindowSeconds.Value, 0.75f, 30f); public float TrapWindow => Mathf.Clamp(TrapWindowSeconds.Value, 0.5f, 30f); public float SimonChance => Mathf.Clamp01(SimonSaysChance.Value); public float TwoActionChance => Mathf.Clamp01(TwoActionRoundChance.Value); public float RoundPause => Mathf.Clamp(BetweenRoundPause.Value, 0f, 5f); public SimonSaysConfig(ConfigFile config) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { SimonSaysConfigMigration.TryMigrate(config, Plugin.Log); ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Simon Says"); Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Simon Says encounter."); SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Simon Says' contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.5f, new ConfigDescription("Indoor enemy power budget cost for Simon Says.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())); ApproachSpeed = config.Bind<float>("Movement", "ApproachSpeed", 3.5f, new ConfigDescription("Movement speed while rolling toward the selected worker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); RetreatDuration = config.Bind<float>("Movement", "RetreatDuration", 3f, new ConfigDescription("Seconds the cart rolls away before vanishing after its game.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>())); RoundsPerEncounter = config.Bind<int>("Abilities", "RoundsPerEncounter", 3, new ConfigDescription("Number of challenges issued during one encounter.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>())); ComplianceWindowSeconds = config.Bind<float>("Abilities", "ComplianceWindowSeconds", 4f, new ConfigDescription("Seconds available to obey a command prefixed with 'Simon says'.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.75f, 30f), Array.Empty<object>())); TrapWindowSeconds = config.Bind<float>("Abilities", "TrapWindowSeconds", 1.75f, new ConfigDescription("Seconds a command without 'Simon says' remains dangerous while the correct response is to do nothing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>())); SimonSaysChance = config.Bind<float>("Abilities", "SimonSaysChance", 0.6f, new ConfigDescription("Chance that a round is a genuine 'Simon says' command instead of a trap.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); TwoActionRoundChance = config.Bind<float>("Abilities", "TwoActionRoundChance", 0.5f, new ConfigDescription("Chance that a round requests two actions instead of one.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); BetweenRoundPause = config.Bind<float>("Abilities", "BetweenRoundPause", 0.3f, new ConfigDescription("Pause between one round's judgment and the next spoken command.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); SpotlightIntensity = config.Bind<float>("Audio and Presentation", "SpotlightIntensity", 12f, new ConfigDescription("Brightness of the client-side focus spotlights.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose encounter and RPC diagnostics."); VanishSmokeForceHdrpShaders = config.Bind<bool>("Diagnostics", "VanishSmokeForceHdrpShaders", false, "Force fallback HDRP particle shaders when intact source materials render incorrectly."); } finally { config.SaveOnConfigSet = saveOnConfigSet; if (saveOnConfigSet) { config.Save(); } } } } internal static class SimonSaysConfigMigration { private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight"); private static readonly Dictionary<ConfigDefinition, string> RemovedDefaults = new Dictionary<ConfigDefinition, string> { { new ConfigDefinition("Movement", "StoppingDistance"), "3.5" }, { new ConfigDefinition("Encounter", "WordGapSeconds"), "0.06" }, { new ConfigDefinition("Detection", "TurnAroundYawDegrees"), "150" }, { new ConfigDefinition("Detection", "AllowTurnAroundInTrapRounds"), "false" } }; internal static bool TryMigrate(ConfigFile config, ManualLogSource log) { string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return false; } Dictionary<ConfigDefinition, string> dictionary = null; string text = null; try { dictionary = ReadValues(configFilePath); if (!ContainsLegacyConfig(dictionary)) { return false; } text = GetBackupPath(configFilePath); File.Copy(configFilePath, text, overwrite: false); File.WriteAllText(configFilePath, BuildMigratedConfig(dictionary), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } catch (Exception ex) { string text2 = "The original config was not modified."; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Copy(text, configFilePath, overwrite: true); config.Reload(); text2 = "The original config was restored from its backup."; } catch (Exception ex2) { text2 = "Automatic restore also failed: " + ex2.GetBaseException().Message + ". Recover manually from " + text + "."; } } if (log != null) { log.LogWarning((object)("[SimonSays] Could not migrate legacy config: " + ex.GetBaseException().Message + " " + text2)); } return false; } List<string> list = FindCustomizedDroppedKeys(dictionary); if (log != null) { log.LogInfo((object)("[SimonSays] Migrated legacy config to the compact DawnLib layout. Backup: " + text)); } if (list.Count > 0 && log != null) { log.LogWarning((object)("[SimonSays] These customized legacy settings are now authored source tuning and were not carried forward: " + string.Join(", ", list))); } return true; } private static bool ContainsLegacyConfig(Dictionary<ConfigDefinition, string> values) { foreach (ConfigDefinition key in values.Keys) { if (key.Section == "Spawning" || key.Section == "Visuals" || key.Section == "Movement" || key.Section == "Behavior" || key.Section == "Encounter" || key.Section == "Detection") { return true; } } return false; } private static string BuildMigratedConfig(Dictionary<ConfigDefinition, string> values) { string text = GetValue(values, "10 - Spawning", "SpawnWeightMultiplier", null); if (string.IsNullOrWhiteSpace(text)) { text = ((!float.TryParse(GetValue(values, LegacySpawnWeight, "30"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) ? "1" : Math.Max(0f, Math.Min(5f, result / 30f)).ToString("0.###", CultureInfo.InvariantCulture)); } StringBuilder stringBuilder = new StringBuilder(); AppendSection(stringBuilder, "00 - General", ("Enabled", GetRetained(values, "00 - General", "General", "Enabled", "true"))); AppendSection(stringBuilder, "10 - Spawning", ("SpawnWeightMultiplier", text), ("PowerLevel", GetRetained(values, "10 - Spawning", "Spawning", "PowerLevel", "2.5"))); AppendSection(stringBuilder, "40 - Movement", ("ApproachSpeed", GetRetained(values, "40 - Movement", "Movement", "ApproachSpeed", "3.5")), ("RetreatDuration", GetRetained(values, "40 - Movement", "Behavior", "RetreatDuration", "3"))); AppendSection(stringBuilder, "60 - Abilities", ("RoundsPerEncounter", GetRetained(values, "60 - Abilities", "Encounter", "RoundsPerEncounter", "3")), ("ComplianceWindowSeconds", GetRetained(values, "60 - Abilities", "Encounter", "ComplianceWindowSeconds", "4")), ("TrapWindowSeconds", GetRetained(values, "60 - Abilities", "Encounter", "TrapWindowSeconds", "1.75")), ("SimonSaysChance", GetRetained(values, "60 - Abilities", "Encounter", "SimonSaysChance", "0.6")), ("TwoActionRoundChance", GetRetained(values, "60 - Abilities", "Encounter", "TwoActionRoundChance", "0.5")), ("BetweenRoundPause", GetRetained(values, "60 - Abilities", "Encounter", "BetweenRoundPause", "0.3"))); AppendSection(stringBuilder, "70 - Audio and Presentation", ("SpotlightIntensity", GetRetained(values, "70 - Audio and Presentation", "Visuals", "SpotlightIntensity", "12"))); AppendSection(stringBuilder, "99 - Diagnostics", ("DebugLogs", GetRetained(values, "99 - Diagnostics", "Behavior", "DebugLogs", "false")), ("VanishSmokeForceHdrpShaders", GetRetained(values, "99 - Diagnostics", "Visuals", "VanishSmokeForceHdrpShaders", "false"))); return stringBuilder.ToString(); } private static void AppendSection(StringBuilder output, string section, params (string Key, string Value)[] entries) { output.Append('[').Append(section).AppendLine("]"); for (int i = 0; i < entries.Length; i++) { output.Append(entries[i].Key).Append(" = ").AppendLine(entries[i].Value); } output.AppendLine(); } private static string GetRetained(Dictionary<ConfigDefinition, string> values, string currentSection, string legacySection, string key, string fallback) { return GetValue(values, currentSection, key, null) ?? GetValue(values, legacySection, key, fallback); } private static string GetValue(Dictionary<ConfigDefinition, string> values, string section, string key, string fallback) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return GetValue(values, new ConfigDefinition(section, key), fallback); } private static string GetValue(Dictionary<ConfigDefinition, string> values, ConfigDefinition definition, string fallback) { if (!values.TryGetValue(definition, out var value)) { return fallback; } return value; } private static Dictionary<ConfigDefinition, string> ReadValues(string path) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(); string text = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); string value = text2.Substring(num + 1).Trim(); dictionary[new ConfigDefinition(text, text3)] = value; } } return dictionary; } private static List<string> FindCustomizedDroppedKeys(Dictionary<ConfigDefinition, string> values) { List<string> list = new List<string>(); foreach (KeyValuePair<ConfigDefinition, string> removedDefault in RemovedDefaults) { if (values.TryGetValue(removedDefault.Key, out var value) && !ValuesEquivalent(value, removedDefault.Value)) { list.Add(removedDefault.Key.Section + "." + removedDefault.Key.Key); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private static bool ValuesEquivalent(string left, string right) { if (string.Equals(left.Trim(), right.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } if (float.TryParse(left, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(right, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) < 0.0001f; } return false; } private static string GetBackupPath(string configPath) { string text = configPath + ".pre-dawn.bak"; if (!File.Exists(text)) { return text; } for (int i = 2; i < 1000; i++) { string text2 = configPath + $".pre-dawn.{i}.bak"; if (!File.Exists(text2)) { return text2; } } throw new IOException("Could not allocate a Simon Says config backup filename."); } } internal sealed class SimonSaysSpawnWeights : IWeighted, IContextualWeighted<SpawnWeightContext> { internal const int DefaultWeight = 3; internal const int MaximumWeight = 100; private readonly Func<float> _multiplier; internal SimonSaysSpawnWeights(Func<float> multiplier) { _multiplier = multiplier ?? throw new ArgumentNullException("multiplier"); } public int GetWeight() { return Scale(3, 1f); } public int GetWeight(SpawnWeightContext context) { int moonWeight = GetMoonWeight(((SpawnWeightContext)(ref context)).Moon); if (moonWeight <= 0) { return 0; } return Scale(moonWeight, GetDungeonMultiplier(((SpawnWeightContext)(ref context)).Dungeon)); } internal static int GetMoonWeight(DawnMoonInfo moon) { if (moon == null) { return 3; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Company) || ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Unimplemented) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Test)) { return 0; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Experimentation)) { return 1; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Assurance) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Vow)) { return 3; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Offense) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.March) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Embrion)) { return 5; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Adamance)) { return 7; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Rend) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Dine)) { return 9; } if (KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Titan) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Artifice) || KeyEquals<DawnMoonInfo>(((DawnBaseInfo<DawnMoonInfo>)(object)moon).TypedKey, MoonKeys.Liquidation)) { return 11; } if (((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Paid)) { return 8; } ((DawnBaseInfo<DawnMoonInfo>)(object)moon).HasTag(Tags.Free); return 3; } internal static float GetDungeonMultiplier(DawnDungeonInfo dungeon) { if (dungeon == null) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlow) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowThreeExits) || KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.FacilityFlowExtraLarge) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Industrial) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Mechanical) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Factory) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Bunker)) { return 1.25f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MansionFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Gothic) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Grand) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Ornate) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Lavish) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Eerie)) { return 1f; } if (KeyEquals<DawnDungeonInfo>(((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).TypedKey, DungeonKeys.MineshaftFlow) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Cavern) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Quarry) || ((DawnBaseInfo<DawnDungeonInfo>)(object)dungeon).HasTag(Tags.Flooded)) { return 0.5f; } return 0.75f; } private int Scale(int moonWeight, float dungeonMultiplier) { float num = Mathf.Clamp(_multiplier(), 0f, 5f); return Mathf.Clamp(Mathf.RoundToInt((float)moonWeight * dungeonMultiplier * num), 0, 100); } private static bool KeyEquals<T>(NamespacedKey<T> left, NamespacedKey<T> right) where T : INamespaced { if (left != null && right != null) { return ((object)left).Equals((object?)right); } return false; } } internal static class SimonSaysTuning { internal const int MaxCount = 1; internal const float StoppingDistance = 3.5f; internal const float WordGapSeconds = 0.06f; internal const float TurnAroundYawDegrees = 150f; internal const bool AllowTurnAroundInTrapRounds = false; } } namespace SimonSays.Utils { public static class CreatureAudio { private static readonly HashSet<string> _warnedKeys = new HashSet<string>(); public static void PlayRandom(AudioSource source, AudioClip[] pool, string poolName, float volumeScale = 1f) { if ((Object)(object)source == (Object)null) { WarnOnce(poolName + ":source=null"); return; } if (pool == null || pool.Length == 0) { WarnOnce(poolName + ":empty"); return; } AudioClip val = pool[Random.Range(0, pool.Length)]; if ((Object)(object)val == (Object)null) { WarnOnce(poolName + ":nullclip"); } else { source.PlayOneShot(val, volumeScale); } } public static void StartLoop(AudioSource source, AudioClip clip) { if (!((Object)(object)source == (Object)null) && !((Object)(object)clip == (Object)null) && (!source.isPlaying || !((Object)(object)source.clip == (Object)(object)clip))) { source.loop = true; source.clip = clip; source.Play(); } } public static void StopLoop(AudioSource source) { if (!((Object)(object)source == (Object)null) && source.isPlaying) { source.Stop(); source.clip = null; } } private static void WarnOnce(string key) { if (_warnedKeys.Add(key)) { Debug.LogWarning((object)("[CreatureAudio] " + key)); } } } } namespace SimonSays.AI { public static class BlackHoleEffect { public static void BeginFor(PlayerControllerB player) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } try { player.KillPlayer(Vector3.zero, true, (CauseOfDeath)2, 0, default(Vector3), false); } catch (Exception arg) { Plugin.Log.LogError((object)$"BlackHoleEffect.BeginFor: {arg}"); } } } public enum SimonState { ROAMING, APPROACHING, INTRO, COMMANDING, JUDGING, PUNISHING, CELEBRATING, DEPARTING } public class SimonSaysAI : EnemyAI { private AudioSource _sfxSource; private AudioSource _voiceSource; private const float VoiceVolume = 1.35f; private const float SfxVolume = 1.15f; private const float FocusLeadIn = 0.45f; private const float PunishHold = 1.5f; private const float DespawnRpcGrace = 0.4f; public AudioClip wheelsRollLoopClip; public AudioClip jesterSwingClip; public AudioSource loopSource; private bool _wheelsLoopDesired; private Coroutine _stateCoroutine; private Coroutine _speechCoroutine; private bool _encounterStarted; private bool _encounterFinished; private ulong _targetClientId; private bool _hasTarget; private int _awaitingRoundIndex = -1; private bool _roundReported; private bool _roundComplied; private bool _judging; private SimonRound _judgeRound; private int _judgeRoundIndex = -1; private bool _judgeReported; private readonly Dictionary<ActionType, bool> _edgeState = new Dictionary<ActionType, bool>(); private readonly Dictionary<ActionType, int> _actionEnteredFrame = new Dictionary<ActionType, int>(); private readonly List<ActionType> _satisfied = new List<ActionType>(2); private int _nextOrderedIndex; private int _orderedStepAvailableFrame; private float _yawNet; private float _lastYaw; private bool _turnAroundFired; private SpotlightController _observerSpotlight; private Vector3 _lastAnimPosition; private bool _animInitialized; private float _smoothedSpeed; private bool _walkAnimOn; private static SimonSaysConfig Cfg => Plugin.ModConfig; private float ApproachSpeed => Cfg?.ApproachSpeed?.Value ?? 3.5f; private float StoppingDist => 3.5f; private float RetreatDuration => Cfg?.RetreatDuration?.Value ?? 3f; private bool DebugLogs => Cfg?.DebugLogs?.Value == true; private float WordGap => 0.06f; private void DLog(string m) { if (DebugLogs) { Plugin.Log.LogInfo((object)("[SimonSays] " + m)); } } private static float ClipLen(AudioClip c) { if (!((Object)(object)c != (Object)null)) { return 0f; } return c.length; } public override void Awake() { try { ((EnemyAI)this).Awake(); Transform val = ((Component)this).transform.Find("CreatureSFX"); if ((Object)(object)val != (Object)null) { _sfxSource = ((Component)val).GetComponent<AudioSource>(); } Transform val2 = ((Component)this).transform.Find("CreatureVoice"); if ((Object)(object)val2 != (Object)null) { _voiceSource = ((Component)val2).GetComponent<AudioSource>(); } if ((Object)(object)base.creatureSFX == (Object)null && (Object)(object)_sfxSource != (Object)null) { base.creatureSFX = _sfxSource; } if ((Object)(object)base.creatureVoice == (Object)null && (Object)(object)_voiceSource != (Object)null) { base.creatureVoice = _voiceSource; } if ((Object)(object)_sfxSource == (Object)null) { _sfxSource = base.creatureSFX; } if ((Object)(object)_voiceSource == (Object)null) { _voiceSource = base.creatureVoice; } if ((Object)(object)base.creatureAnimator == (Object)null) { base.creatureAnimator = ((Component)this).GetComponent<Animator>(); } if ((Object)(object)base.eye == (Object)null) { Transform val3 = ((Component)this).transform.Find("Eye"); if ((Object)(object)val3 != (Object)null) { base.eye = val3; } } ConfigureVoiceMix(); } catch (Exception arg) { Plugin.Log.LogError((object)$"SimonSaysAI.Awake: {arg}"); } } public override void Start() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Start(); Plugin.EnsureScanNode(((Component)this).gameObject); ConfigureVoiceMix(); if ((Object)(object)base.agent != (Object)null) { base.agent.speed = ApproachSpeed; base.agent.stoppingDistance = 0f; if (base.agent.areaMask == 0) { base.agent.areaMask = -1; } base.agent.autoTraverseOffMeshLink = true; if (base.openDoorSpeedMultiplier <= 0f) { base.openDoorSpeedMultiplier = (((Object)(object)base.enemyType != (Object)null && base.enemyType.doorSpeedMultiplier > 0f) ? base.enemyType.doorSpeedMultiplier : 1f); } } _lastAnimPosition = ((Component)this).transform.position; _animInitialized = true; if (((NetworkBehaviour)this).IsServer) { ((EnemyAI)this).SwitchToBehaviourClientRpc(0); } DLog($"spawned. IsServer={((NetworkBehaviour)this).IsServer} agentOnNavMesh={(Object)(object)base.agent != (Object)null && base.agent.isOnNavMesh} " + $"areaMask={(((Object)(object)base.agent != (Object)null) ? base.agent.areaMask : 0)} doorSpeed={base.openDoorSpeedMultiplier}"); } catch (Exception arg) { Plugin.Log.LogError((object)$"SimonSaysAI.Start: {arg}"); } } public override void Update() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Update(); UpdateWalkAnimation(); if (((NetworkBehaviour)this).IsServer) { int num; if ((Object)(object)base.agent != (Object)null) { Vector3 velocity = base.agent.velocity; num = ((((Vector3)(ref velocity)).sqrMagnitude > 0.01f) ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; if (flag != _wheelsLoopDesired) { _wheelsLoopDesired = flag; SetWheelsLoopClientRpc(flag); } } if (_judging) { RunLocalObedienceCheck(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"SimonSaysAI.Update: {arg}"); } } private void UpdateWalkAnimation() { //IL_0036: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.creatureAnimator == (Object)null) { return; } if (!_animInitialized) { _lastAnimPosition = ((Component)this).transform.position; _animInitialized = true; return; } Vector3 val = ((Component)this).transform.position - _lastAnimPosition; val.y = 0f; _lastAnimPosition = ((Component)this).transform.position; float num = ((Time.deltaTime > 0f) ? (((Vector3)(ref val)).magnitude / Time.deltaTime) : 0f); _smoothedSpeed = Mathf.Lerp(_smoothedSpeed, num, 1f - Mathf.Exp(-8f * Time.deltaTime)); if (_walkAnimOn && _smoothedSpeed < 0.1f) { _walkAnimOn = false; } else if (!_walkAnimOn && _smoothedSpeed > 0.22f) { _walkAnimOn = true; } base.creatureAnimator.SetBool("isWalking", _walkAnimOn); } public override void DoAIInterval() { try { ((EnemyAI)this).DoAIInterval(); if (((NetworkBehaviour)this).IsServer && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && !_encounterFinished) { switch ((SimonState)base.currentBehaviourStateIndex) { case SimonState.ROAMING: DoRoaming(); break; case SimonState.APPROACHING: DoApproaching(); break; } } } catch (Exception arg) { Plugin.Log.LogError((object)$"SimonSaysAI.DoAIInterval: {arg}"); } } public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { } public override void KillEnemy(bool destroy = false) { CleanupEffects(); } private void DoRoaming() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null)) { if (base.currentSearch == null || !base.currentSearch.inProgress) { ((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null); } base.agent.speed = ApproachSpeed; base.agent.stoppingDistance = 0f; PlayerControllerB val = ((EnemyAI)this).CheckLineOfSightForPlayer(70f, 30, -1); if ((Object)(object)val != (Object)null) { ((EnemyAI)this).StopSearch(base.currentSearch, true); _targetClientId = val.actualClientId; _hasTarget = true; base.targetPlayer = val; DLog("acquired target " + val.playerUsername); SetTargetPlayerClientRpc(_targetClientId); ((EnemyAI)this).SwitchToBehaviourClientRpc(1); } } } private void DoApproaching() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (!TargetStillValid()) { AbortEncounter(); } else { if ((Object)(object)base.agent == (Object)null) { return; } base.agent.speed = ApproachSpeed; base.agent.stoppingDistance = StoppingDist; ((EnemyAI)this).SetDestinationToPosition(((Component)base.targetPlayer).transform.position, false); if (Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) <= StoppingDist && !_encounterStarted) { _encounterStarted = true; if (base.currentSearch != null && base.currentSearch.inProgress) { ((EnemyAI)this).StopSearch(base.currentSearch, true); } HoldStationForEncounter(); _stateCoroutine = ((MonoBehaviour)this).StartCoroutine(EncounterRoutine()); } } } private void HoldStationForEncounter() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh) { base.agent.ResetPath(); base.agent.velocity = Vector3.zero; base.agent.isStopped = true; } } private bool TargetStillValid() { if (_hasTarget && (Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead) { return base.targetPlayer.isPlayerControlled; } return false; } private void FaceTarget() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.targetPlayer == (Object)null)) { Vector3 val = ((Component)base.targetPlayer).transform.position - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.01f) { ((Component)this).transform.rotation = Quaternion.LookRotation(val); } } } private IEnumerator EncounterRoutine() { FaceTarget(); ((EnemyAI)this).SwitchToBehaviourClientRpc(2); BeginFocusClientRpc(_targetClientId); yield return (object)new WaitForSeconds(0.45f); PlayIntroClientRpc(); yield return (object)new WaitForSeconds(ClipLen(Plugin.LetsPlayClip) + WordGap); int rounds = ((Cfg != null) ? Cfg.Rounds : 3); for (int i = 0; i < rounds; i++) { if (!TargetStillValid()) { yield return DepartRoutine(); yield break; } SimonRound round = SimonSaysWords.Roll((Cfg != null) ? Cfg.SimonChance : 0.6f, (Cfg != null) ? Cfg.TwoActionChance : 0.5f, allowTurnAroundInTraps: false); int packed = round.Pack(); DLog($"round {i + 1}/{rounds}: \"{round}\""); _awaitingRoundIndex = i; _roundReported = false; _roundComplied = false; ((EnemyAI)this).SwitchToBehaviourClientRpc(3); SpeakRoundClientRpc(packed, i); yield return (object)new WaitForSeconds(SimonSaysWords.UtteranceLength(round, WordGap) + 0.05f); if (!TargetStillValid()) { yield return DepartRoutine(); yield break; } ((EnemyAI)this).SwitchToBehaviourClientRpc(4); OpenWindowClientRpc(packed, i); float window = ((!round.SimonSaid) ? ((Cfg != null) ? Cfg.TrapWindow : 1.75f) : ((Cfg != null) ? Cfg.Window : 4f)); float elapsed = 0f; while (elapsed < window && !_roundReported && TargetStillValid()) { elapsed += Time.deltaTime; yield return null; } CloseWindowClientRpc(); _awaitingRoundIndex = -1; if (!TargetStillValid()) { yield return DepartRoutine(); yield break; } bool flag = _roundReported && _roundComplied; bool flag2 = (round.SimonSaid ? flag : (!flag)); DLog(string.Format("round {0} complied={1} simonSaid={2} -> {3}", i + 1, flag, round.SimonSaid, flag2 ? "PASS" : "FAIL")); if (!flag2) { yield return PunishRoutine(); yield break; } float num = ((Cfg != null) ? Cfg.RoundPause : 0.3f); if (num > 0f) { yield return (object)new WaitForSeconds(num); } } ((EnemyAI)this).SwitchToBehaviourClientRpc(6); PlayCongratulationsClientRpc(); yield return (object)new WaitForSeconds(ClipLen(Plugin.CongratulationsClip) + 0.2f); yield return DepartRoutine(); } private IEnumerator PunishRoutine() { ((EnemyAI)this).SwitchToBehaviourClientRpc(5); PlayerFailedClientRpc(_targetClientId); yield return (object)new WaitForSeconds(1.5f); yield return DepartRoutine(); } private IEnumerator DepartRoutine() { if (!_encounterFinished) { _encounterFinished = true; ((EnemyAI)this).SwitchToBehaviourClientRpc(7); EndFocusClientRpc(); PlayGoodbyeClientRpc(); SetRetreatDestination(); float num = Mathf.Max(RetreatDuration, ClipLen(Plugin.GoodbyeClip) + 0.2f); yield return (object)new WaitForSeconds(num); VanishClientRpc(((Component)this).transform.position); yield return (object)new WaitForSeconds(0.4f); DespawnSelf(); } } private void SetRetreatDestination() { //IL_0073: 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_0078: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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) try { if (!((Object)(object)base.agent == (Object)null) && base.agent.isOnNavMesh) { base.agent.isStopped = false; base.agent.speed = ApproachSpeed; base.agent.stoppingDistance = 0f; Vector3 val = (((Object)(object)base.targetPlayer != (Object)null) ? ((Component)base.targetPlayer).transform.position : ((Component)this).transform.position); Vector3 val2 = ((Component)this).transform.position - val; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = ((Component)this).transform.forward; } Vector3 val3 = ((Component)this).transform.position + ((Vector3)(ref val2)).normalized * 15f; int num = ((base.agentMask != 0) ? base.agentMask : (-1)); NavMeshHit val4 = default(NavMeshHit); if (NavMesh.SamplePosition(val3, ref val4, 12f, num)) { ((EnemyAI)this).SetDestinationToPosition(((NavMeshHit)(ref val4)).position, false); } else { ((EnemyAI)this).SetDestinationToPosition(val3, false); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"SetRetreatDestination: {arg}"); } } private void DespawnSelf() { try { if ((Object)(object)RoundManager.Instance != (Object)null && ((NetworkBehaviour)this).IsServer && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned) { RoundManager.Instance.DespawnEnemyOnServer(((NetworkBehaviour)this).NetworkObject); } } catch (Exception arg) { Plugin.Log.LogError((object)$"despawn failed: {arg}"); } } private void AbortEncounter() { if (!_encounterFinished) { _encounterStarted = true; if (_stateCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_stateCoroutine); _stateCoroutine = null; } _stateCoroutine = ((MonoBehaviour)this).StartCoroutine(DepartRoutine()); } } [ClientRpc] public void SetTargetPlayerClientRpc(ulong clientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3618932334u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, clientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3618932334u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { _targetClientId = clientId; _hasTarget = true; base.targetPlayer = ResolvePlayer(clientId) ?? base.targetPlayer; } catch (Exception arg) { Plugin.Log.LogError((object)$"SetTargetPlayerClientRpc: {arg}"); } } [ClientRpc] public void BeginFocusClientRpc(ulong targetClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1593938165u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, targetClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1593938165u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { _targetClientId = targetClientId; _hasTarget = true; PlayerControllerB val3 = ResolvePlayer(targetClientId); if ((Object)(object)val3 != (Object)null) { base.targetPlayer = val3; } if (IsLocalTarget()) { PlayerControllerB val4 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)val4 != (Object)null) { SimonSaysFocusEffect.Begin(this, val4, Cfg?.SpotlightIntensity?.Value ?? 8f); } } else if ((Object)(object)val3 != (Object)null) { if ((Object)(object)_observerSpotlight == (Object)null) { _observerSpotlight = SpotlightController.SpawnFor(val3, Cfg?.SpotlightIntensity?.Value ?? 8f); } else { _observerSpotlight.Retarget(val3); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"BeginFocusClientRpc: {arg}"); } } [ClientRpc] public void EndFocusClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1344786899u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1344786899u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { EndFocusLocal(); } catch (Exception arg) { Plugin.Log.LogError((object)$"EndFocusClientRpc: {arg}"); } } private void EndFocusLocal() { SimonSaysFocusEffect.EndFor(this); if ((Object)(object)_observerSpotlight != (Object)null) { _observerSpotlight.Despawn(); _observerSpotlight = null; } } [ClientRpc] public void PlayIntroClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1746222514u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1746222514u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { SpeakClips(new List<AudioClip> { Plugin.LetsPlayClip }); } catch (Exception arg) { Plugin.Log.LogError((object)$"PlayIntroClientRpc: {arg}"); } } [ClientRpc] public void SpeakRoundClientRpc(int packedRound, int roundIndex) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(212779188u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, packedRound); BytePacker.WriteValueBitPacked(val, roundIndex); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 212779188u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { SimonRound round = SimonRound.Unpack(packedRound); SpeakClips(SimonSaysWords.BuildUtterance(round)); } catch (Exception arg) { Plugin.Log.LogError((object)$"SpeakRoundClientRpc: {arg}"); } } [ClientRpc] public void OpenWindowClientRpc(int packedRound, int roundIndex) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2369853749u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, packedRound); BytePacker.WriteValueBitPacked(val, roundIndex); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2369853749u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { if (IsLocalTarget()) { BeginLocalJudging(SimonRound.Unpack(packedRound), roundIndex); } } catch (Exception arg) { Plugin.Log.LogError((object)$"OpenWindowClientRpc: {arg}"); } } [ClientRpc] public void CloseWindowClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(447314282u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 447314282u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; _judging = false; _judgeRoundIndex = -1; } } } [ClientRpc] public void PlayCongratulationsClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3841940082u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3841940082u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { SpeakClips(new List<AudioClip> { Plugin.CongratulationsClip }); } catch (Exception arg) { Plugin.Log.LogError((object)$"PlayCongratulationsClientRpc: {arg}"); } } [ClientRpc] public void PlayGoodbyeClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2046626769u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2046626769u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { SpeakClips(new List<AudioClip> { Plugin.GoodbyeClip }); } catch (Exception arg) { Plugin.Log.LogError((object)$"PlayGoodbyeClientRpc: {arg}"); } } [ClientRpc] public void PlayerFailedClientRpc(ulong targetClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3584274768u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, targetClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3584274768u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { _judging = false; if (IsLocalTarget()) { EndFocusLocal(); PlayerControllerB val3 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)val3 != (Object)null) { BlackHoleEffect.BeginFor(val3); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"PlayerFailedClientRpc: {arg}"); } } [ClientRpc] public void VanishClientRpc(Vector3 position) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1932661538u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe(ref position); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1932661538u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { EndFocusLocal(); StopSpeech(); CreatureAudio.StopLoop(loopSource); VanishSmokeEffect.SpawnAt(position, Cfg != null && Cfg.VanishSmokeForceHdrpShaders.Value); ((EnemyAI)this).EnableEnemyMesh(false, false, false); } catch (Exception arg) { Plugin.Log.LogError((object)$"VanishClientRpc: {arg}"); } } [ClientRpc] public void SetWheelsLoopClientRpc(bool on) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1535394079u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref on, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1535394079u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (on) { CreatureAudio.StartLoop(loopSource, wheelsRollLoopClip); } else { CreatureAudio.StopLoop(loopSource); } } } [ServerRpc(RequireOwnership = false)] public void ReportRoundOutcomeServerRpc(int roundIndex, bool complied, ServerRpcParams rpcParams = default(ServerRpcParams)) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1726491939u, rpcParams, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, roundIndex); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref complied, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 1726491939u, rpcParams, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { if (rpcParams.Receive.SenderClientId == _targetClientId && roundIndex == _awaitingRoundIndex) { _roundReported = true; _roundComplied = complied; DLog($"target reported round {roundIndex}: complied={complied}"); } } catch (Exception arg) { Plugin.Log.LogError((object)$"ReportRoundOutcomeServerRpc: {arg}"); } } private void SpeakClips(List<AudioClip> clips) { StopSpeech(); if (clips != null && clips.Coun
Y4NGZCreepyDoll.dll
Decompiled 2 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Audio; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Y4NGZCreepyDoll.NetcodePatcher; using Y4NGZMonsters.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZCreepyDoll")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZCreepyDoll")] [assembly: AssemblyTitle("Y4NGZCreepyDoll")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZCreepyDoll { public sealed class CreepyDollAI : EnemyAI { private enum EncounterState { Dormant, Suspicious, Chase, Search, Hypnosis } private sealed class RaycastHitDistanceComparer : IComparer<RaycastHit> { internal static readonly RaycastHitDistanceComparer Instance = new RaycastHitDistanceComparer(); public int Compare(RaycastHit x, RaycastHit y) { return ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance); } } public const int StateIdle = 0; public const int StateLuring = 1; public const int StateNeckSlash = 2; private const float PossessionProbeInterval = 0.12f; private const float ConstantLoopVolume = 0.3f; private const float MindControlVolume = 0.95f; private const float MindControlDampenedDecibels = -18f; private const float PursuitSirenVolume = 0.55f; private const float IdleBeatVolume = 0.4f; private const int IdleBeatMinimumSteps = 5; private const int IdleBeatMaximumSteps = 9; private const float FootstepPhaseWindow = 0.09f; private const float MinimumMoveSpeed = 0.34f; private const float MinimumAcceleration = 22.5f; private const float MinimumAngularSpeed = 120f; private const float MinimumGazeRange = 80f; private const float NavigationRadius = 0.5f; private const float NavigationHeight = 2f; private const float NavigationStoppingDistance = 0.6f; private const float SlowWalkClipDurationSeconds = 4.85f; private const float SlowWalkCycleDistance = 4.56f; private const float SlowWalkControllerStateSpeed = 0.625f; private const float RunClipDurationSeconds = 1.9f; private const float RunCycleDistance = 4.54f; private const float RunGaitEnterSpeedMetersPerSecond = 1.3f; private const float RunGaitExitSpeedMetersPerSecond = 1.1f; private const float HeadFocusHeardSeconds = 4.5f; private const float HeadTrackingAimDeadZoneDegrees = 0.35f; private const float NoisePlayerMatchRadius = 4f; private const float VoiceHearingMinimumAmplitude = 0.02f; private const float OccludedHearingRangeFraction = 0.5f; private const float HeadFocusSyncInterval = 0.22f; private const float NeckYawShare = 0.42f; private const float NeckPitchShare = 0.38f; private const float LowerSpineDuckShare = 0.3f; private const float UpperSpineDuckShare = 0.32f; private const float NeckDuckShare = 0.22f; private const float IdleSoundMinDistance = 2f; private const float IdleSoundMaxDistance = 30f; private const float CreatureAudioSpread = 40f; private const float MinimumPossessionStopDistance = 4.35f; private const float ScheduledExecutionKillDelay = 2f; private const float ExecutionDollStopDistance = 2.05f; private const float ExecutionCloseMinimumSpeed = 2.35f; private const float ExecutionHeadFocusRefreshSeconds = 0.08f; private const float PursuitDropRangeMultiplier = 1.75f; private const float PursuitMinimumDropRange = 12f; private const float PursuitMaximumDropRange = 35f; private const float SuspiciousMinDwellSeconds = 3f; private const float SuspiciousTimeoutSeconds = 6f; private const float ChaseMinDwellSeconds = 5f; private const float ChaseLostSeconds = 12f; private const float ReacquireRefractorySeconds = 20f; private const float SearchVocalIntervalSeconds = 4f; private const float SearchScanSpeedMultiplier = 2f; private const float SearchScanHoldScale = 0.5f; private const float PossessionCommandAckSeconds = 1f; private const float InvestigateTravelTimeoutSeconds = 12f; private const float InvestigateArriveRadius = 1.6f; private const float InvestigateLookHoldSeconds = 5f; private const float SearchLingerSeconds = 30f; private const float SearchLingerWidthScale = 0.5f; private const int MinLingerSearchNodes = 4; private const float ChaseSpeedMetersPerSecond = 2f; private const float ChaseSprintSpeedMetersPerSecond = 3.6f; private const float SprintDurationSeconds = 3f; private const float SprintCooldownSeconds = 30f; private const float SprintChance = 0.35f; private const float SprintMinimumTriggerDistance = 6f; private const float SprintReleaseDistance = 2.5f; private const float SprintWindupDelaySeconds = 0.8f; private const float SprintRerollIntervalSeconds = 20f; private const float SprintSpawnGraceSeconds = 30f; private const float SprintVocalVolume = 0.85f; private const float SprintVocalPitchMinimum = 1.12f; private const float SprintVocalPitchMaximum = 1.18f; private const float SprintLungeDuckDegrees = 22f; private const float NeckSlashImpactRangeGrace = 0.35f; private const float NeckSlashVerticalTolerance = 1.75f; private const float NeckSlashFacingHalfAngleDegrees = 75f; private const float SpotConfirmHysteresisDegrees = 8f; private const float SpotConfirmRangeHysteresis = 1.15f; private const float PitchReachSlackDegrees = 15f; private const float NoiseAcceptCooldownSeconds = 1.75f; private const float NoiseMinimumLoudness = 0.3f; private const float NoiseMinimumPerceivedLoudness = 0.04f; private const float HeadSnapWindowSeconds = 0.35f; private const float HeadSnapSettleDegrees = 3f; private const float HeadSnapRearmDegrees = 18f; private const float SightFocusOcclusionGraceSeconds = 0.4f; private const float ObservationHoldSeconds = 4.5f; private const float ObservationPlantMaximumSeconds = 4.5f; private const float ObservationReplantCooldownSeconds = 10f; private const float FootGroundedDistance = 0.14f; private const float FootstepContactCooldown = 0.24f; private const float MinimumTravelPerFootstep = 0.34f; private const float GroundRaycastVerticalPadding = 1.4f; private const float VisualGroundSmoothSpeed = 14f; private const float FootBoneGroundingFallbackSoleOffset = 0.18f; private const float DoorwayDuckCastRadius = 0.13f; private const float DoorwayDuckSmoothDegreesPerSecond = 190f; private const float DoorwayPeekSmoothDegreesPerSecond = 70f; private const float DoorwayDuckChestProbeHeight = 0.95f; private const float DoorwayDuckMinimumClearanceHeight = 1.25f; private const float DoorwayDuckMinimumLocomotionSpeed = 0.06f; private const float DoorwayLintelProbeInset = 0.21f; private const float HeadPostureMeasureInterval = 0.2f; private const float HeadPostureSyncStepDegrees = 1.5f; private const float PeekRollFocusRetention = 0.4f; private const float IdleScanDuckSuppressionDegrees = 8f; private const float GazeAuthorityBlendPerSecond = 8f; private const float HypnosisPitchBlendSeconds = 0.3f; private const float NeckCumulativeDuckShare = 0.84000003f; private const float NeckRollShare = 0.3f; private const double IdleScanEpochCellSeconds = 60.0; private const long IdleScanBeatsPerCell = 128L; private const float IdleScanGlanceHoldMinSeconds = 0.6f; private const float IdleScanGlanceHoldMaxSeconds = 1.2f; private const float IdleScanDownwardPitchDegrees = 4f; private const float FootClearanceProbeHeight = 1f; private const float FootClearanceProbeDepth = 2.5f; private const float FootSoleOffsetDecayPerSecond = 0.08f; private const float FootSoleOffsetMinimumSample = 0.02f; private const float FootSoleOffsetSeedCeiling = 0.35f; private const float StandingHeadHeightDecayPerSecond = 0.15f; private const float RoamSearchMinimumWidth = 12f; private const float RoamSearchMaximumWidth = 40f; private const float RoamSearchNodeBudgetSeconds = 16f; private const float RoamSearchRegionSpread = 2.5f; private const float RoamSearchPrecision = 1.5f; private const float BodyTurnStepThresholdDegreesPerSecond = 10f; private const float BodyTurnStepMetersPerDegree = 0.006f; private const float NeckSlashRecoverySeconds = 0.32f; private const int ClientConfirmLogReceived = 1; private const int FootstepSurfaceConcrete = 0; private const int FootstepSurfaceMetal = 1; private const int FootstepSurfaceWood = 2; private const float FootstepGainConcrete = 11.2f; private const float FootstepGainMetal = 15f; private const float FootstepGainWood = 5.3f; private const float FootstepGainCeiling = 64f; private const float StandardFootstepBroadcastVolume = 1f; private const float FolleyChance = 0.35f; private const float FolleyVolumeScale = 0.8f; private const float FolleyGainQuietClip = 5.6f; private const string FolleyQuietClipName = "folley02"; public Transform attackOrigin; public AudioSource stepAudioSource; public AudioSource idleAudioSource; public AudioSource constantAudioSource; public AudioSource mindControlAudioSource; public AudioClip[] stepClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip[] stepClipsConcrete = (AudioClip[])(object)new AudioClip[0]; public AudioClip[] stepClipsMetal = (AudioClip[])(object)new AudioClip[0]; public AudioClip[] stepClipsWood = (AudioClip[])(object)new AudioClip[0]; public AudioClip[] idleClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip idleBeatClip; public AudioClip[] folleyClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip constantClip; public AudioClip mindControlClip; public AudioClip[] mindControlClips = (AudioClip[])(object)new AudioClip[0]; public AudioClip killClip; public AudioClip headSnapClip; public AISearchRoutine facilitySearch = new AISearchRoutine(); private static readonly int AnimIsMoving = Animator.StringToHash("IsMoving"); private static readonly int AnimIsRunning = Animator.StringToHash("IsRunning"); private static readonly int AnimWalkRate = Animator.StringToHash("WalkRate"); private static readonly int AnimRunRate = Animator.StringToHash("RunRate"); private static readonly int AnimNeckSlash = Animator.StringToHash("NeckSlash"); private static readonly float[] StandardWalkFootstepPhases = new float[2] { 0.08f, 0.56f }; private static readonly string[] VoiceSpeakingMemberNames = new string[4] { "IsSpeaking", "isSpeaking", "Speaking", "speaking" }; private static readonly string[] VoiceAmplitudeMemberNames = new string[2] { "Amplitude", "amplitude" }; private static readonly float[] VoiceOutputSamples = new float[64]; private static FieldInfo _voicePlayerStateField; private EncounterState _encounterState; private float _encounterStateEnteredTime; private ulong _encounterTargetClientId = ulong.MaxValue; private float _encounterLastStimulusTime; private ulong _chaseRefractoryClientId = ulong.MaxValue; private float _chaseRefractoryUntilTime; private float _nextSearchVocalTime; private int _lastEncounterNoticeCueFrame = -1; private PlayerControllerB _serverEntrancedPlayer; private ulong _serverEntrancedClientId = ulong.MaxValue; private float _serverPossessionCommandTime; private bool _serverPossessionAcknowledged; private PlayerControllerB _serverPursuitPlayer; private ulong _serverPursuitClientId = ulong.MaxValue; private float _serverPursuitLastVisibleTime; private string _serverPursuitSource = "none"; private bool _serverPursuitSirenActive; private Vector3 _serverPursuitLastSeenPosition; private bool _hasServerPursuitLastSeen; private bool _serverInvestigating; private bool _serverInvestigateLooking; private Vector3 _serverInvestigatePoint; private float _serverInvestigateStartedTime; private float _serverInvestigateLookUntilTime; private bool _serverInvestigateLingering; private float _serverInvestigateLingerUntilTime; private string _serverSearchExitReason = "search complete"; private float _serverSprintPendingStartTime = -1f; private float _serverSprintUntilTime; private float _nextSprintAllowedTime; private float _nextSprintRollTime; private bool _serverSprintGuaranteePending; private bool _serverSprintLungeActive; private bool _serverSprintWasActive; private ulong _serverSlashTargetClientId = ulong.MaxValue; private bool _isNeckSlashing; private float _serverSlashMomentumSpeed; private float _serverSlashMomentumUntil; private bool _audioParityApplied; private AudioSource _constantLoopConfiguredSource; private AudioSource _idleAudioConfiguredSource; private bool _serverExecutionShouldCloseDistance; private float _nextNeckSlashTime; private ulong _serverObservationClientId = ulong.MaxValue; private bool _serverObservationFromNoise; private float _serverObservationUntilTime; private float _serverGazeContactSeconds; private float _serverGazeLastContactTime; private bool _serverGazeGraceLogged; private bool _serverSpotConfirmed; private float _serverSpotConfirmedAtTime; private int _serverSpotConfirmEpoch; private int _possessionRangeRefusalEpoch = -1; private ulong _possessionRangeRefusalClientId = ulong.MaxValue; private Vector3 _serverNoiseStimulusPoint; private float _serverSightLastSeenTime; private float _nextNoiseAcceptTime; private float _nextVoiceAcceptTime; private ulong _syncedObservedClientId = ulong.MaxValue; private bool _syncedSpotConfirmed; private int _syncedSpotConfirmEpoch; private float _nextObservationSyncRefreshTime; private ulong _replicatedObservedClientId = ulong.MaxValue; private bool _replicatedSpotConfirmed; private float _replicatedSpotConfirmedTime; private int _replicatedSpotConfirmEpoch; private int _clientConfirmLogEpoch = -1; private int _clientConfirmLogFlags; private float _serverEntrancedStartTime; private float _serverBodyRotationUnlockTime; private bool _localPossessed; private bool _localControlsSaved; private bool _localSavedDisableLookInput; private bool _localSavedDisableMoveInput; private float _localPossessionStartTime; private float _localPossessionStopTime; private float _nextLocalSlashRequestTime; private bool _localExecutionRequested; private bool _localSlashPresentationActive; private bool _localSlashImpactReceived; private float _localSlashStartedTime; private float _localSlashImpactTime; private float _localSlashWindupSeconds; private bool _localSlashUsesClip; private bool _localSlashClipRecoveryStarted; private int _strikeClipPresence; private float _nextMovementDiagnosticTime; private ulong _reportedPossessionClientId = ulong.MaxValue; private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[32]; private readonly Vector3[] _bodyProbePoints = (Vector3[])(object)new Vector3[3]; private float _nextPossessionLosProbeTime; private bool _cachedPossessionLos; private float _possessionLosLostSinceTime; private float _hypnosisPitchBlend; private int _lastFootstepClipIndex = -1; private int _lastFolleyClipIndex = -1; private int _lastStandardFootstepKey = -1; private int _stepsUntilIdleBeat = -1; private bool _mindControlAudioPlaying; private bool _mindControlAudioDampened; private float _nextMindControlSnapshotRefreshTime; private bool _localMindControlCameraSaved; private float _localMindControlBaseFov; private Transform _headBone; private Transform _neckBone; private Transform _lowerSpineBone; private Transform _upperSpineBone; private Transform _rightClavicleBone; private Transform _rightUpperArmBone; private Transform _rightForearmBone; private Vector3 _headFocusPoint; private float _headFocusUntilTime; private float _headBodyFollowAllowedTime; private float _headSnapUntilTime; private bool _headFocusFromNoise; private float _nextHeadFocusSyncTime; private float _headAimYawDegrees; private float _headAimPitchDegrees; private float _headAimRollDegrees; private Vector3 _headAimWorldDirection; private Quaternion _headRestToRoot = Quaternion.identity; private Quaternion _neckRestToRoot = Quaternion.identity; private bool _hasHeadChainRestPose; private string _headRestPoseSource = "none"; private float _gazeAuthorityWeight; private readonly NetworkVariable<float> _networkDuckDegrees = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkPeekYawDegrees = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<float> _networkPeekRollDegrees = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private float _headPeekYawDegrees; private float _headPeekRollDegrees; private float _nextHeadPostureMeasureTime; private readonly Vector3[] _pathCornerBuffer = (Vector3[])(object)new Vector3[8]; private bool _serverDuckActive; private bool _serverPeekActive; private long _idleScanBeatIndex; private long _idleScanCell; private long _idleScanBeatStep; private double _idleScanBeatStartTime; private double _idleScanBeatEndTime; private bool _hasIdleScanCursor; private float _idleScanHoldScale = 1f; private bool _idleScanActive; private Transform _leftFootBone; private Transform _rightFootBone; private Vector3 _leftFootPreviousPosition; private Vector3 _rightFootPreviousPosition; private bool _leftFootWasGrounded; private bool _rightFootWasGrounded; private float _leftFootSoleOffset = -1f; private float _rightFootSoleOffset = -1f; private bool _contactFootstepClockActive; private float _nextContactFootstepTime; private Vector3 _lastFootstepTravelPosition; private bool _hasFootstepTravelPosition; private float _footstepTravelAccumulator; private Transform _visualRoot; private Vector3 _lastLocomotionSamplePosition; private float _lastLocomotionSampleYawDegrees; private bool _hasLocomotionSample; private float _smoothedLocomotionSpeed; private float _smoothedBodyTurnSpeed; private float _lastSlowWalkPlaybackRate; private string _lastGaitName = "none"; private bool _runGaitEngaged; private int _runClipPresence; private int _gaitRateParameterPresence; private float _doorwayDuckPitchDegrees; private float _standingHeadHeight; private bool _hasStandingHeadHeight; private bool _standingHeadHeightIsBoundsSeed; private bool _serverObservationPlanted; private float _serverObservationPlantStartTime; private float _serverObservationPlantAlignedTime; private bool _serverObservationPlantSpent; private ulong _serverLastPlantedClientId = ulong.MaxValue; private float _serverLastPlantCompletedTime = float.NegativeInfinity; private bool _loggedRuntimeDiagnostics; private float _nextHeadDiagnosticTime; private float _nextRoamDiagnosticTime; private string _lastHeadStateLogLine; private float _nextHeadStateLogTime; private bool _loggedEyeOrigin; private bool _serverBodyTurnInProgress; private int _contactFootstepCount; private int _phasedFootstepCount; private float _nextFootstepDiagnosticTime; private const float BodyProbeChestHeight = 2f; private const float BodyProbeLowHeight = 0.5f; private const int GazeAngleProbePointCount = 2; private float MoveSpeed => Mathf.Clamp(Plugin.ModConfig?.MoveSpeed?.Value ?? 0.6f, 0.34f, 5f); private float Acceleration => Mathf.Max(22.5f, 22.5f); private float AngularSpeed => Mathf.Max(120f, 150f); private float GazeRange => Mathf.Clamp(Plugin.ModConfig?.GazeRange?.Value ?? 80f, 5f, 100f); private float HypnosisOnsetDelaySeconds => Mathf.Clamp(Plugin.ModConfig?.HypnosisOnsetDelay?.Value ?? 0.5f, 0f, 5f); private float GazeHalfAngleDegrees => 18f; private float CloseRangeGazeHalfAngleDegrees => 40f; private float MovementLockDelay => Mathf.Clamp(Plugin.ModConfig?.MovementLockDelay?.Value ?? 3f, 0f, 10f); private float PossessionStrafeSeconds => 2f; private float PossessedWalkSpeed => Mathf.Clamp(Plugin.ModConfig?.PullSpeed?.Value ?? 0.85f, 0.1f, 5f); private float PossessedStrafeSpeed => 0.75f; private float PossessedLookTurnSpeed => 280f; private float RoamRadius => 18f; private float RoamRepathSeconds => 5f; private float RoamSearchWidth { get { float num = Mathf.Clamp(MoveSpeed * 16f * 2.5f, 12f, 40f); return Mathf.Clamp(RoamRadius * 2.5f, 12f, num); } } private bool HeadTrackingEnabled => true; private float HeadTrackingRange => Mathf.Max(80f, 80f); private float HeadSightRange => Mathf.Clamp(Plugin.ModConfig?.SightRange?.Value ?? 18f, 2f, HeadTrackingRange); private float HeadHearingRange => Mathf.Clamp(Plugin.ModConfig?.HearingRange?.Value ?? 20f, 4f, 80f); private float HeadVisionConeDegrees => 30f; private float HeadProximityAwareness => 3f; private float HeadRearAwarenessRange => 4.5f; private float HeadSightHoldSeconds => 3.5f; private float HeadRearTurnDelaySeconds => 1.2f; private float SpotConfirmSeconds => 0.8f; private float SpotConfirmGraceSeconds => 0.6f; private float PossessionBeginMaxDistance => 12f; private float PossessionLosGraceSeconds => 0.6f; private float HeadYawLimitDegrees => 78f; private float HeadPitchLimitDegrees => 32f; private float HypnosisHeadPitchLimitDegrees => 55f; private float EffectiveHeadPitchLimitDegrees => Mathf.Lerp(HeadPitchLimitDegrees, HypnosisHeadPitchLimitDegrees, _hypnosisPitchBlend); private float HeadSnapSpeed => 520f; private float HeadTrackSpeed => 120f; private float HeadBodyFollowDelay => 3f; private float HeadBodyFollowSpeed => 60f; private float PursuitDropRange => Mathf.Clamp(HeadSightRange * 1.75f, 12f, 35f); private float NeckSlashRange => Mathf.Clamp(Plugin.ModConfig?.NeckSlashRange?.Value ?? 2.15f, 0.5f, 5f); private float NeckSlashCooldown => Mathf.Clamp(Plugin.ModConfig?.AttackCooldown?.Value ?? 2.4f, 0.1f, 30f); private float NeckSlashKillDelay => Mathf.Max(2f, 2f); private float PossessionStopDistance => Mathf.Max(4.35f, NeckSlashRange + 2f); private bool PlayNeckSlashAnimation => Plugin.PlayAttackAnimation; private bool StaticVisualTestMode => Plugin.StaticVisualTestMode; private bool DoorwayDuckEnabled => true; private float DoorwayDuckProbeDistance => 1.15f; private float DoorwayDuckAngleDegrees => 32f; private float DoorwayDuckClearanceMargin => 0.08f; private float DoorwayDuckDegreesPerMeter => 55f; private bool DoorwayPeekEnabled => true; private float DoorwayPeekYawDegrees => 40f; private float DoorwayPeekRollDegrees => 14f; private float DoorwayPeekLookaheadDistance => 3f; private float DoorwayPeekMinimumTurnDegrees => 45f; private float HeadPoseAuthority => 1f; private float HeadRestPitchTrimDegrees => 0f; private float HeadRollLimitDegrees => 18f; private bool IdleExamineEnabled => true; private float IdleScanYawRangeDegrees => 55f; private float IdleScanPitchRangeDegrees => 12f; private float IdleScanRollDegrees => 6f; private float IdleScanSpeedDegreesPerSecond => 26f; private float IdleScanHoldMinSeconds => 2.5f; private float IdleScanHoldMaxSeconds => 6f; private float IdleScanGlanceChance => 0.2f; private float FootstepVolume => Mathf.Clamp(Plugin.ModConfig?.FootstepVolume?.Value ?? 1f, 0f, 4f); private float MindControlVisualIntensity => Mathf.Clamp01(Plugin.ModConfig?.MindControlVisualIntensity?.Value ?? 0.65f); private bool DevSnapSpawnNearPlayer => false; private float DevSpawnDistance => 6f; private bool DebugLogs => Plugin.ModConfig?.DebugLogs?.Value == true; private bool ServerMindControlMovementUnlocked { get { if (_serverEntrancedClientId != ulong.MaxValue) { return Time.time - _serverEntrancedStartTime >= MovementLockDelay; } return false; } } private bool ServerSprintActive => Time.time < _serverSprintUntilTime; public override void Awake() { try { EnsureBehaviourStates(); ((EnemyAI)this).Awake(); ResolveRuntimeReferences(); ConfigureSearchDefaults(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] Awake failed: {arg}"); } } } public override void Start() { //IL_0111: Unknown result type (might be due to invalid IL or missing references) try { EnsureBehaviourStates(); ((EnemyAI)this).Start(); ResolveRuntimeReferences(); CorrectPrototypeSpawnPlacement(); ConfigureAgent(); ConfigureSearchDefaults(); Plugin.EnsureCollision(((Component)this).gameObject, this); Plugin.EnsureScanNode(((Component)this).gameObject); Plugin.DisablePhysicalVisualColliders(((Component)this).gameObject); RepairFacilityAINodes(); Plugin.RepairVisuals(((Component)this).gameObject, "spawned instance"); Plugin.ApplyVisualYawOffset(((Component)this).gameObject, "spawned instance"); SeedStandingHeadHeightFromBounds(); base.enemyHP = 999; base.isOutside = false; if ((Object)(object)base.creatureAnimator != (Object)null) { Plugin.ConfigureAnimatorForCurrentMode(base.creatureAnimator, "spawned instance"); if (!StaticVisualTestMode) { base.creatureAnimator.SetBool(AnimIsMoving, false); base.creatureAnimator.SetBool(AnimIsRunning, false); _runGaitEngaged = false; base.creatureAnimator.ResetTrigger(AnimNeckSlash); base.creatureAnimator.Play("Idle", 0, 0f); } } EnsureConstantLoop(); if (((NetworkBehaviour)this).IsServer) { StartRoamingSearch(((Component)this).transform.position); _nextSprintAllowedTime = Time.time + 30f; } if (DebugLogs) { LogSpawnDiagnostic("Started"); } LogHushdollRuntimeDiagnostics("start"); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] Start failed: {arg}"); } } } public override void Update() { try { ((EnemyAI)this).Update(); if (base.isEnemyDead) { EndLocalPossession(); StopConstantLoop(); StopPursuitSirenLocal(); return; } if ((Object)(object)base.creatureAnimator == (Object)null || (Object)(object)base.agent == (Object)null) { ResolveRuntimeReferences(); } Plugin.ApplyVisualYawOffset(((Component)this).gameObject, "static visual tick", log: false); TickLocalGaze(); UpdateAnimatorMovementFlag(); TickCreatureAudio(); UpdateEyeTransform(); TickServerHeadDetectionState(); TickServerEncounterState(); SyncServerObservationState(); RefreshAgentRotationOwnership(); TickServerBodyFollowHeadFocus(); TickServerHeadPosture(); LogRoamDiagnostic(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] Update failed: {arg}"); } } } private void LateUpdate() { try { TickLocalPossessionControl(); StabilizeVisualRootOnGround(); ResolveHeadTrackingReferences(); TrackStandingHeadHeight(); TickHeadPostureSmoothing(); ApplyProceduralPose(); ApplyProceduralNeckSlash(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] LateUpdate failed: {arg}"); } } } private void OnDisable() { try { if (_localPossessed || _reportedPossessionClientId != ulong.MaxValue) { EndLocalPossession(); } else { StopLocalMindControlAudioAndEffects(); } StopConstantLoop(); StopPursuitSirenLocal(); _localSlashPresentationActive = false; _localSlashImpactReceived = false; _localSlashUsesClip = false; _localSlashClipRecoveryStarted = false; } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] OnDisable failed: {arg}"); } } } public override void DoAIInterval() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).DoAIInterval(); if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead) { return; } ConfigureAgent(); ConfigureSearchDefaults(); RepairFacilityAINodes(); if (_isNeckSlashing) { StopAgentPath(); PlayerControllerB val = FindPlayerByClientId(_serverSlashTargetClientId); if ((Object)(object)val != (Object)null && !val.isPlayerDead) { FacePosition(((Component)val).transform.position); FocusHeadOnPlayerServer(val, 0.45f, fromNoise: false); } return; } if ((_encounterState == EncounterState.Chase || _encounterState == EncounterState.Hypnosis) && Time.time >= _nextNeckSlashTime) { PlayerControllerB val2 = FindBasicAttackTarget(); if ((Object)(object)val2 != (Object)null) { BeginNeckSlashServer(val2, fromPossessionStop: false); return; } } switch (_encounterState) { case EncounterState.Hypnosis: { PlayerControllerB val3 = ResolveServerEntrancedPlayer(); if ((Object)(object)val3 != (Object)null) { PursueServerTarget(val3, respectMindControlDelay: true); } else { StopMovingServer(); } break; } case EncounterState.Chase: { PlayerControllerB val4 = ResolveServerPursuitPlayer(); if ((Object)(object)val4 != (Object)null) { TickServerSprint(val4); PursueServerTarget(val4, respectMindControlDelay: false); } else { StopMovingServer(); } break; } case EncounterState.Search: if (!TickServerInvestigation()) { StopMovingServer(); } break; case EncounterState.Suspicious: if (ServerHoldsStillForObservation()) { StopMovingServer(); } else { RoamServer(); } break; default: RoamServer(); break; } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] DoAIInterval failed: {arg}"); } } } private void TickServerEncounterState() { if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead) { return; } PlayerControllerB val = ResolveEncounterTargetPlayer(); if (_isNeckSlashing) { if ((Object)(object)val == (Object)null && (_encounterState == EncounterState.Suspicious || _encounterState == EncounterState.Chase)) { LeaveChaseBookkeeping(); TransitionEncounterState(EncounterState.Dormant, "target invalid during slash"); } if (_encounterState == EncounterState.Hypnosis && (Object)(object)ResolveServerEntrancedPlayer() == (Object)null) { LeaveHypnosisAfterRelease(); } return; } switch (_encounterState) { case EncounterState.Suspicious: TickSuspiciousEncounterState(val); break; case EncounterState.Chase: TickChaseEncounterState(val); break; case EncounterState.Search: TickSearchEncounterState(); break; case EncounterState.Hypnosis: TickHypnosisEncounterState(); break; } } private void TickSuspiciousEncounterState(PlayerControllerB target) { if ((Object)(object)target == (Object)null) { TransitionEncounterState(EncounterState.Dormant, "target invalid"); } else if (!TryEnterHypnosisFromGaze(target)) { float num = Time.time - _encounterStateEnteredTime; if (Time.time - _encounterLastStimulusTime > 6f && num >= 3f) { TransitionEncounterState(EncounterState.Dormant, "no stimulus refresh"); } } } private void TickChaseEncounterState(PlayerControllerB target) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_012d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { LeaveChaseBookkeeping(); TransitionEncounterState(EncounterState.Dormant, "chase target invalid"); } else { if (TryEnterHypnosisFromGaze(target)) { return; } Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position; float magnitude = ((Vector3)(ref val)).magnitude; bool flag = magnitude <= PursuitDropRange; if (flag && HasClearLineOfSightToPlayerFace(target)) { _serverPursuitPlayer = target; _serverPursuitLastVisibleTime = Time.time; _serverPursuitLastSeenPosition = ((Component)target).transform.position; _hasServerPursuitLastSeen = true; return; } float num = Time.time - _serverPursuitLastVisibleTime; if ((!flag || !(num <= 12f)) && !(Time.time - _encounterStateEnteredTime < 5f)) { LogHeadStateEvent($"chase lost: player={_encounterTargetClientId}, source={_serverPursuitSource}, " + $"distance={magnitude:0.0}/{PursuitDropRange:0.0} m, unseen={num:0.00} s."); bool hasServerPursuitLastSeen = _hasServerPursuitLastSeen; Vector3 serverPursuitLastSeenPosition = _serverPursuitLastSeenPosition; ulong encounterTargetClientId = _encounterTargetClientId; LeaveChaseBookkeeping(); ArmChaseRefractory(encounterTargetClientId); if (hasServerPursuitLastSeen) { BeginServerInvestigation(serverPursuitLastSeenPosition); _encounterTargetClientId = encounterTargetClientId; TransitionEncounterState(EncounterState.Search, "lost sight"); } else { TransitionEncounterState(EncounterState.Dormant, "lost sight, nowhere to search"); } } } } private void TickSearchEncounterState() { if (!_serverInvestigating) { TransitionEncounterState(EncounterState.Dormant, _serverSearchExitReason); } else if (Time.time >= _nextSearchVocalTime) { _nextSearchVocalTime = Time.time + 4f; PlayIdleBeatClientRpc(0.5f, 1f); } } private void TickHypnosisEncounterState() { if ((Object)(object)ResolveServerEntrancedPlayer() != (Object)null) { if (!_serverPossessionAcknowledged && Time.time - _serverPossessionCommandTime > 1f) { LogHeadStateEvent("possession command unacknowledged after " + $"{Time.time - _serverPossessionCommandTime:0.00} s: player={_serverEntrancedClientId}. " + "Releasing the trance."); ClearServerEntrancedPlayer(_serverEntrancedClientId); LeaveHypnosisAfterRelease(); } else { _encounterTargetClientId = _serverEntrancedClientId; } } else { LeaveHypnosisAfterRelease(); } } private void LeaveHypnosisAfterRelease() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = ResolveEncounterTargetPlayer(); if ((Object)(object)val != (Object)null) { ArmChaseRefractory(val.actualClientId); Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val2)).magnitude <= PursuitDropRange) || !HasClearLineOfSightToPlayerFace(val, allowBodyPoints: true) || !TryBeginChase(val, "trance released, still visible")) { BeginServerInvestigation(((Component)val).transform.position); TransitionEncounterState(EncounterState.Search, "trance released, victim gone"); } } else { ArmChaseRefractory(_encounterTargetClientId); TransitionEncounterState(EncounterState.Dormant, "trance released, no victim"); } } private bool TryEnterHypnosisFromGaze(PlayerControllerB target) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer || (Object)(object)target == (Object)null || _serverEntrancedClientId != ulong.MaxValue || !_serverSpotConfirmed || _serverObservationClientId != target.actualClientId || Time.time - _serverSpotConfirmedAtTime < HypnosisOnsetDelaySeconds || !((EnemyAI)this).PlayerIsTargetable(target, true, false, true) || !HasClearLineOfSightToPlayerFace(target, allowBodyPoints: true)) { return false; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position); if (num > PossessionBeginMaxDistance) { LogPossessionRangeRefusal(target.actualClientId, num); return false; } BeginServerPossession(target); _encounterTargetClientId = target.actualClientId; ArmChaseRefractory(target.actualClientId); TransitionEncounterState(EncounterState.Hypnosis, "mutual gaze held"); return true; } private void LogPossessionRangeRefusal(ulong clientId, float distance) { if (_possessionRangeRefusalEpoch != _serverSpotConfirmEpoch || _possessionRangeRefusalClientId != clientId) { _possessionRangeRefusalEpoch = _serverSpotConfirmEpoch; _possessionRangeRefusalClientId = clientId; LogHeadStateEvent($"possession refused (out of reach): player={clientId}, " + $"epoch={_serverSpotConfirmEpoch}, distance={distance:0.0} m, " + $"max={PossessionBeginMaxDistance:0.0} m."); } } private void BeginServerPossession(PlayerControllerB player) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !((Object)(object)player == (Object)null)) { ulong actualClientId = player.actualClientId; ClearServerPursuitTarget(clearObservationForSameTarget: false); _serverEntrancedPlayer = player; _serverEntrancedClientId = actualClientId; _serverEntrancedStartTime = Time.time; _serverPossessionCommandTime = Time.time; _serverPossessionAcknowledged = false; _serverBodyRotationUnlockTime = Time.time; ClearServerObservationTarget(); ResetServerObservationPlantHistory(); base.targetPlayer = player; base.movingTowardsTargetPlayer = false; _headBodyFollowAllowedTime = Time.time; ForceHeadSnapToPlayerServer(player, 0.65f); StopSearchIfNeeded(clear: false); StopAgentPath(); if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 0) { ((EnemyAI)this).SwitchToBehaviourState(0); } LogHeadStateEvent($"possession commanded: player={actualClientId}, epoch={_serverSpotConfirmEpoch}, " + $"confirmAge={Time.time - _serverSpotConfirmedAtTime:0.00}/{HypnosisOnsetDelaySeconds:0.00} s, " + $"distance={Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position):0.0} m."); BeginPossessionClientRpc(actualClientId); } } [ClientRpc] private void BeginPossessionClientRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(301402725u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 301402725u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayerControllerB val3 = ResolveLocalPlayer(); if (!((Object)(object)val3 == (Object)null) && !val3.isPlayerDead && PlayerMatchesClientId(val3, playerClientId) && ((EnemyAI)this).PlayerIsTargetable(val3, false, false, true) && !_localPossessed) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[CreepyDollAI][head][client] possession commanded by the server: " + $"clientId={playerClientId}.")); } BeginLocalPossession(val3); } } [ClientRpc] private void EndPossessionClientRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2754516961u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2754516961u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!_localPossessed) { return; } PlayerControllerB val3 = ResolveLocalPlayer(); if (!((Object)(object)val3 == (Object)null) && PlayerMatchesClientId(val3, playerClientId)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[CreepyDollAI][head][client] possession released by the server: " + $"clientId={playerClientId}.")); } EndLocalPossession(); } } private void TransitionEncounterState(EncounterState next, string reason) { if (!((NetworkBehaviour)this).IsServer || next == _encounterState) { return; } EncounterState encounterState = _encounterState; float num = Time.time - _encounterStateEnteredTime; _encounterState = next; _encounterStateEnteredTime = Time.time; bool num2 = encounterState == EncounterState.Chase || encounterState == EncounterState.Hypnosis; bool flag = next == EncounterState.Chase || next == EncounterState.Hypnosis; if (num2 && !flag) { StopPursuitSirenServer(); } switch (next) { case EncounterState.Suspicious: if (encounterState == EncounterState.Dormant) { if (TargetIsInChaseRefractory(_encounterTargetClientId)) { reason += ", re-entered (remembered)"; } else { PlayEncounterNoticeCue(); } } break; case EncounterState.Chase: if (TargetIsInChaseRefractory(_encounterTargetClientId)) { reason += ", re-entered (remembered)"; } else { PlayEncounterNoticeCue(); } StartPursuitSirenServer(); _serverSprintGuaranteePending = true; break; case EncounterState.Search: _nextSearchVocalTime = Time.time + 4f; PlayIdleBeatClientRpc(0.55f, 1f); break; case EncounterState.Dormant: if (encounterState == EncounterState.Search) { PlayIdleBeatClientRpc(0.3f, 0.94f); } _encounterTargetClientId = ulong.MaxValue; break; } if (encounterState == EncounterState.Chase) { _serverSprintUntilTime = 0f; _serverSprintPendingStartTime = -1f; _serverSprintWasActive = false; } ApplyAgentSpeed(); LogHeadStateEvent($"[encounter] {encounterState} -> {next}: reason={reason}, " + "target=" + ((_encounterTargetClientId == ulong.MaxValue) ? "none" : _encounterTargetClientId.ToString()) + ", " + $"dwell={num:0.0}s"); } private void PlayEncounterNoticeCue() { if (_lastEncounterNoticeCueFrame != Time.frameCount) { _lastEncounterNoticeCueFrame = Time.frameCount; PlayHeadSnapClientRpc(); } } private void ArmChaseRefractory(ulong clientId) { if (clientId != ulong.MaxValue) { _chaseRefractoryClientId = clientId; _chaseRefractoryUntilTime = Time.time + 20f; } } private bool TargetIsInChaseRefractory(ulong clientId) { if (clientId != ulong.MaxValue && _chaseRefractoryClientId == clientId) { return Time.time <= _chaseRefractoryUntilTime; } return false; } private void NoteEncounterStimulus(PlayerControllerB player, bool seen, Vector3? point = null) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)player == (Object)null || player.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(player, true, false, true)) { return; } ulong actualClientId = player.actualClientId; switch (_encounterState) { case EncounterState.Dormant: _encounterTargetClientId = actualClientId; _encounterLastStimulusTime = Time.time; TransitionEncounterState(EncounterState.Suspicious, seen ? "sighted" : "heard"); if (!seen) { break; } goto case EncounterState.Suspicious; case EncounterState.Suspicious: _encounterLastStimulusTime = Time.time; if (_serverObservationClientId == actualClientId) { _encounterTargetClientId = actualClientId; } if (seen) { TryBeginChase(player, "clear sight of a player"); } break; case EncounterState.Chase: { if (!seen || actualClientId == _encounterTargetClientId) { break; } PlayerControllerB val = ResolveEncounterTargetPlayer(); if ((Object)(object)val != (Object)null) { Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = ((Component)player).transform.position - ((Component)this).transform.position; if (sqrMagnitude <= ((Vector3)(ref val2)).sqrMagnitude) { break; } } SetServerPursuitTarget(player, "sight"); if (_serverPursuitClientId == actualClientId) { _encounterTargetClientId = actualClientId; LogHeadStateEvent($"[encounter] chase retargeted to player={actualClientId} (no announcement)."); } break; } case EncounterState.Search: if (seen && TryBeginChase(player, "sighted during search")) { EndServerInvestigation("target sighted again"); } break; } } private bool TryBeginChase(PlayerControllerB player, string reason) { if ((Object)(object)player == (Object)null) { return false; } SetServerPursuitTarget(player, "sight"); if (_serverPursuitClientId != player.actualClientId) { return false; } _encounterTargetClientId = player.actualClientId; TransitionEncounterState(EncounterState.Chase, reason); return true; } private void LeaveChaseBookkeeping() { ClearServerPursuitTarget(clearObservationForSameTarget: true); } private PlayerControllerB ResolveEncounterTargetPlayer() { if (_encounterTargetClientId == ulong.MaxValue) { return null; } PlayerControllerB val = FindPlayerByClientId(_encounterTargetClientId); if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, true, false, true)) { return null; } return val; } private bool EncounterStateAllowsRoaming() { if (_encounterState == EncounterState.Dormant) { return true; } if (_encounterState == EncounterState.Suspicious) { return !ServerHoldsStillForObservation(); } return false; } private void PursueServerTarget(PlayerControllerB target, bool respectMindControlDelay) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer || (Object)(object)target == (Object)null || target.isPlayerDead) { return; } base.targetPlayer = target; StopSearchIfNeeded(clear: false); int num; if (respectMindControlDelay) { num = (ServerMindControlMovementUnlocked ? 1 : 0); if (num == 0) { base.movingTowardsTargetPlayer = false; StopAgentPath(); goto IL_004d; } } else { num = 1; } ((EnemyAI)this).SetMovingTowardsTargetPlayer(target); goto IL_004d; IL_004d: FocusHeadOnPlayerServer(target, 0.65f, fromNoise: false); if (num == 0) { FacePosition(((Component)target).transform.position); if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 0) { ((EnemyAI)this).SwitchToBehaviourState(0); } return; } if (EnsureAgentOnNavMesh()) { base.agent.updateRotation = AgentDrivesBodyRotation(); base.agent.isStopped = false; } else { StopAgentPath(); LogMovementDiagnostic("target movement skipped: agent is not on NavMesh"); } if (!AgentDrivesBodyRotation()) { FacePosition(((Component)target).transform.position); } if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 1) { ((EnemyAI)this).SwitchToBehaviourState(1); } } private PlayerControllerB FindBasicAttackTarget() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsServer || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB result = null; float num = float.PositiveInfinity; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (PlayerFitsNeckSlashGeometry(val, NeckSlashRange, requireFacing: false, requireLineOfSight: true)) { Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; val2.y = 0f; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; result = val; } } } return result; } private void RoamServer() { if (!((NetworkBehaviour)this).IsServer || _isNeckSlashing || !EncounterStateAllowsRoaming()) { return; } base.targetPlayer = null; base.movingTowardsTargetPlayer = false; if (!EnsureAgentOnNavMesh()) { LogMovementDiagnostic("roam skipped: agent is not on NavMesh"); return; } base.agent.updateRotation = AgentDrivesBodyRotation(); base.agent.isStopped = false; EnsureRoamingSearch(); if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 1) { ((EnemyAI)this).SwitchToBehaviourState(1); } } private void ConfigureSearchDefaults() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown if (facilitySearch == null) { facilitySearch = new AISearchRoutine(); } facilitySearch.loopSearch = true; facilitySearch.randomized = false; facilitySearch.onlySearchNodesInLOS = false; bool flag = _serverInvestigating && _serverInvestigateLingering && _encounterState == EncounterState.Search; facilitySearch.searchWidth = (flag ? (RoamSearchWidth * 0.5f) : RoamSearchWidth); facilitySearch.searchPrecision = 1.5f; } private void EnsureRoamingSearch() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !_isNeckSlashing && EncounterStateAllowsRoaming() && !((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh) { ConfigureSearchDefaults(); if (facilitySearch == null || base.currentSearch != facilitySearch || !facilitySearch.inProgress) { StartRoamingSearch(((Component)this).transform.position); } } } private void StartRoamingSearch(Vector3 start) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh) { ConfigureSearchDefaults(); StopSearchIfNeeded(clear: false); ((EnemyAI)this).StartSearch(start, facilitySearch); } } private void StartLingerSearch() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) StartRoamingSearch(_serverInvestigatePoint); NarrowSearchToLingerArea(); } private void NarrowSearchToLingerArea() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = facilitySearch?.unsearchedNodes; if (list == null || list.Count <= 4) { return; } Vector3 anchor = _serverInvestigatePoint; list.Sort(delegate(GameObject a, GameObject b) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Vector3 val3; float num3; if (!((Object)(object)a == (Object)null)) { val3 = a.transform.position - anchor; num3 = ((Vector3)(ref val3)).sqrMagnitude; } else { num3 = float.MaxValue; } float num4 = num3; float num5; if (!((Object)(object)b == (Object)null)) { val3 = b.transform.position - anchor; num5 = ((Vector3)(ref val3)).sqrMagnitude; } else { num5 = float.MaxValue; } float value = num5; return num4.CompareTo(value); }); float num = RoamSearchWidth * 0.5f; num *= num; int num2; for (num2 = 4; num2 < list.Count; num2++) { GameObject val = list[num2]; if ((Object)(object)val == (Object)null) { break; } Vector3 val2 = val.transform.position - anchor; if (((Vector3)(ref val2)).sqrMagnitude > num) { break; } } if (num2 < list.Count) { list.RemoveRange(num2, list.Count - num2); } } private void StopSearchIfNeeded(bool clear) { if (base.currentSearch != null && base.currentSearch.inProgress) { ((EnemyAI)this).StopSearch(base.currentSearch, clear); } } private void RefreshAgentRotationOwnership() { if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled) { bool flag = AgentDrivesBodyRotation(); if (base.agent.updateRotation != flag) { base.agent.updateRotation = flag; } } } [ServerRpc(RequireOwnership = false)] private void ReportPossessionServerRpc(ulong playerClientId, bool active) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1621209323u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref active, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 1621209323u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { if (active) { if (_serverEntrancedClientId != playerClientId) { LogHeadStateEvent($"possession report ignored: player={playerClientId} was never commanded " + "(entranced=" + ((_serverEntrancedClientId == ulong.MaxValue) ? "none" : _serverEntrancedClientId.ToString()) + ")."); } else { _serverPossessionAcknowledged = true; } } else if (_serverEntrancedClientId == playerClientId) { ClearServerEntrancedPlayer(ulong.MaxValue); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] ReportPossessionServerRpc failed: {arg}"); } } } [ServerRpc(RequireOwnership = false)] private void RequestNeckSlashKillServerRpc(ulong playerClientId, bool fromPossessionStop) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2495072846u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref fromPossessionStop, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 2495072846u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; try { PlayerControllerB val3 = FindPlayerByClientId(playerClientId); if (!((Object)(object)val3 == (Object)null) && !val3.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(val3, false, false, true)) { float num = (fromPossessionStop ? (PossessionStopDistance + 1f) : (NeckSlashRange + 1.5f)); if (!(Vector3.Distance(((Component)this).transform.position, ((Component)val3).transform.position) > num)) { BeginNeckSlashServer(val3, fromPossessionStop); } } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[CreepyDollAI] RequestNeckSlashKillServerRpc failed: {arg}"); } } } [ClientRpc] private void PlayNeckSlashClientRpc(ulong playerClientId, float windupSeconds) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1190224957u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref windupSeconds, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1190224957u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); _localSlashPresentationActive = true; _localSlashImpactReceived = false; _localSlashUsesClip = false; _localSlashClipRecoveryStarted = false; _localSlashStartedTime = Time.time; _localSlashImpactTime = 0f; _localSlashWindupSeconds = Mathf.Max(0.05f, windupSeconds); PlayClipOneShot(base.creatureSFX ?? stepAudioSource, headSnapClip, 0.7f, 0.9f); if (!((Object)(object)base.creatureAnimator == (Object)null) && !StaticVisualTestMode) { base.creatureAnimator.applyRootMotion = false; base.creatureAnimator.ResetTrigger(AnimNeckSlash); _localSlashUsesClip = PlayNeckSlashAnimation && AnimatorHasStrikeClip(); if (_localSlashUsesClip) { float num = (_runGaitEngaged ? 0.35f : 0.12f); base.creatureAnimator.SetBool(AnimIsMoving, false); base.creatureAnimator.SetBool(AnimIsRunning, false); _runGaitEngaged = false; base.creatureAnimator.CrossFadeInFixedTime("NeckSlash", num, 0, 0f); } else if (_smoothedLocomotionSpeed <= 0.05f) { base.creatureAnimator.SetBool(AnimIsMoving, false); base.creatureAnimator.SetBool(AnimIsRunning, false); _runGaitEngaged = false; base.creatureAnimator.CrossFadeInFixedTime("Idle", 0.08f, 0, 0f); } } } private bool AnimatorHasStrikeClip() { if (_strikeClipPresence == 0) { _strikeClipPresence = -1; RuntimeAnimatorController val = (((Object)(object)base.creatureAnimator != (Object)null) ? base.creatureAnimator.runtimeAnimatorController : null); if ((Object)(object)val != (Object)null) { AnimationClip[] animationClips = val.animationClips; foreach (AnimationClip val2 in animationClips) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name.IndexOf("NeckSlash_Strike", StringComparison.OrdinalIgnoreCase) >= 0) { _strikeClipPresence = 1; break; } } } } return _strikeClipPresence == 1; } [ClientRpc] private void ResolveNeckSlashClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1957274175u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1957274175u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (_localSlashPresentationActive) { _localSlashImpactReceived = true; _localSlashImpactTime = Time.time; } } } [ClientRpc] private void PlayFootstepClientRpc(int surfaceIndex, int clipIndex, float volume, float pitch) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(799409866u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, surfaceIndex); BytePacker.WriteValueBitPacked(val, clipIndex); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref volume, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitch, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 799409866u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); AudioClip[] array = ResolveStepClipPool(surfaceIndex); float volume2 = volume * ResolveStepClipGain(array); AudioSource source = stepAudioSource ?? base.creatureSFX; PlayClipOneShot(source, array, clipIndex, volume2, pitch); MaybePlayFootstepFolley(source, volume * FootstepVolume); } } } private void MaybePlayFootstepFolley(AudioSource source, float stepBroadcastVolume) { if (folleyClips != null && folleyClips.Length != 0 && !(Random.value > 0.35f)) { int num = PickRandomClipIndex(folleyClips, ref _lastFolleyClipIndex); if (num >= 0) { AudioClip clip = folleyClips[num]; PlayClipOneShot(source ?? base.creatureSFX, clip, stepBroadcastVolume * 0.8f * ResolveFolleyClipGain(clip), Random.Range(0.95f, 1.05f)); } } } private static float ResolveFolleyClipGain(AudioClip clip) { if ((Object)(object)clip == (Object)null || ((Object)clip).name == null) { return 1f; } if (((Object)clip).name.IndexOf("folley02", StringComparison.OrdinalIgnoreCase) < 0) { return 1f; } return 5.6f; } private float ResolveStepClipGain(AudioClip[] pool) { if (pool == null || pool.Length == 0) { return 1f; } float num = ((pool == stepClipsMetal) ? 15f : ((pool == stepClipsWood) ? 5.3f : ((pool != stepClipsConcrete) ? 1f : 11.2f))); return num * FootstepVolume; } [ClientRpc] private void PlayIdleBeatClientRpc(float volume, float pitch) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2374545687u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref volume, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitch, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2374545687u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); PlayClipOneShot(idleAudioSource ?? base.creatureSFX, idleBeatClip, volume, pitch); } } } [ClientRpc] private void PlaySprintVocalClientRpc(float volume, float pitch) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(726890257u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref volume, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitch, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 726890257u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); AudioSource val3 = idleAudioSource ?? base.creatureSFX; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)idleBeatClip == (Object)null)) { val3.pitch = Mathf.Clamp(pitch, 0.6f, 1.35f); val3.PlayOneShot(idleBeatClip, Mathf.Clamp(volume, 0f, 1f)); } } } [ClientRpc] private void StartPursuitSirenClientRpc(int clipIndex) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2920004268u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, clipIndex); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2920004268u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); AudioClip val3 = null; if (mindControlClips != null && clipIndex >= 0 && clipIndex < mindControlClips.Length) { val3 = mindControlClips[clipIndex]; } if ((Object)(object)val3 == (Object)null) { val3 = mindControlClip; } AudioSource val4 = (((Object)(object)base.creatureVoice != (Object)null) ? base.creatureVoice : base.creatureSFX); if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val3 == (Object)null)) { val4.clip = val3; val4.loop = true; val4.volume = 0.55f; val4.pitch = 1f; val4.Play(); } } } [ClientRpc] private void StopPursuitSirenClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2826517116u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2826517116u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; StopPursuitSirenLocal(); } } } private void StopPursuitSirenLocal() { if (!((Object)(object)base.creatureVoice == (Object)null) && base.creatureVoice.loop) { base.creatureVoice.Stop(); base.creatureVoice.loop = false; base.creatureVoice.clip = null; base.creatureVoice.volume = 1f; } } [ClientRpc] private void PlayHeadSnapClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2504793662u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2504793662u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); PlayClipOneShot(base.creatureSFX ?? stepAudioSource, headSnapClip, 0.55f, Random.Range(0.97f, 1.03f)); } } } [ClientRpc] private void PlayKillSoundClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(395634359u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 395634359u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ResolveRuntimeReferences(); PlayClipOneShot(((Object)(object)base.creatureVoice != (Object)null && !base.creatureVoice.loop) ? base.creatureVoice : (((Object)(object)base.creatureSFX != (Object)null) ? base.creatureSFX : base.creatureVoice), killClip, 0.95f, Random.Range(0.96f, 1.03f)); } } } [ClientRpc] private void ExecuteNeckSlashKillClientRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2272386025u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2272386025u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayerControllerB val3 = ResolveLocalPlayer(); if (!((Object)(object)val3 == (Object)null) && (val3.actualClientId == playerClientId || val3.playerClientId == playerClientId)) { bool flag = !val3.isPlayerDead; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[CreepyDollAI][combat][victim] neck slash kill " + string.Format("{0}: clientId={1}, ", flag ? "executed" : "skipped", playerClientId) + $"isPlayerDead={val3.isPlayerDead}.")); } if (flag) { val3.KillPlayer(Vector3.up * 14f, true, (CauseOfDeath)17, 7, default(Vector3), false); } EndLocalPossession(); } } [ClientRpc] private void RearmPossessionExecutionClientRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(4045993336u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 4045993336u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayerControllerB val3 = ResolveLocalPlayer(); if (!((Object)(object)val3 == (Object)null) && !val3.isPlayerDead && PlayerMatchesClientId(val3, playerClientId) && _localPossessed) { _localExecutionRequested = false; _localPossessionStopTime = 0f; _nextLocalSlashRequestTime = Time.time + Mathf.Max(0.25f, NeckSlashCooldown); } } } public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID); if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || !HeadTrackingEnabled || Time.time < _nextNoiseAcceptTime) { return; } float num = Vector3.Distance(((Component)this).transform.position, noisePosition); if (!(num > HeadHearingRange) && !(num <= 0.05f) && !(noiseLoudness < 0.3f) && !(noiseLoudness / Mathf.Max(num, 1f) < 0.04f)) { PlayerControllerB val = FindPlayerNearPosition(noisePosition, 4f); if (PlayerCanBeHeadTracked(val) && ((EnemyAI)this).PlayerIsTargetable(val, true, false, true) && (!(num > HeadHearingRange * 0.5f) || HasClearLineOfSightToPlayerFace(val))) { _nextNoiseAcceptTime = Time.time + 1.75f; SetServerObservationTarget(val, fromNoise: true, noisePosition, "noise"); NoteEncounterStimulus(val, seen: false, noisePosition); } } } private void TickLocalGaze() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = ResolveLocalPlayer(); if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true)) { _cachedPossessionLos = false; EndLocalPossession(); } else if (_localPossessed) { if (!PossessionLineOfSightHolds(val)) { EndLocalPossession(); return; } ReportLocalPossession(val, active: true); SetHeadFocus(GetPlayerFocusPoint(val), 0.35f, fromNoise: false); TryRequestExecutionFromLocalStop(val); } else if (_replicatedSpotConfirmed && _replicatedObservedClientId != ulong.MaxValue && PlayerMatchesClientId(val, _replicatedObservedClientId)) { LogClientConfirmEvent(1, $"confirm received (t-{Time.time - _replicatedSpotConfirmedTime:0.00} s), " + $"server onset delay {HypnosisOnsetDelaySeconds:0.00} s."); } } private void TickLocalPossessionControl() { if (!_localPossessed) { return; } PlayerControllerB val = ResolveLocalPlayer(); if ((Object)(object)val == (Object)null || val.isPlayerDead) { EndLocalPossession(); return; } if (!PossessionLineOfSightHolds(val)) { EndLocalPossession(); return; } val.disableLookInput = true; bool flag = Time.time - _localPossessionStartTime >= MovementLockDelay; val.disableMoveInput = flag || _localSavedDisableMoveInput; AimLocalPlayerAtDoll(val); if (flag) { MoveLocalPlayerTowardDoll(val, flag); } TryRequestExecutionFromLocalStop(val); UpdateLocalMindControlAudioAndEffects(val); } private bool PossessionLineOfSightHolds(PlayerControllerB player) { if (CachedPlayerHasLineOfSightToDoll(player, 0.12f, ref _nextPossessionLosProbeTime, ref _cachedPossessionLos)) { _possessionLosLostSinceTime = 0f; return true; } if (_possessionLosLostSinceTime <= 0f) { _possessionLosLostSinceTime = Time.time; } return Time.time - _possessionLosLostSinceTime < PossessionLosGraceSeconds; } private void BeginLocalPossession(PlayerControllerB player) { if ((Object)(object)player == (Object)null || _localPossessed) { return; } _localPossessed = true; _localPossessionStartTime = Time.time; _localPossessionStopTime = 0f; _nextLocalSlashRequestTime = Time.time + 0.25f; _localExecutionRequested = false; _nextPossessionLosProbeTime = Time.time + PossessionLosGraceSeconds; _cachedPossessionLos = true; _possessionLosLostSinceTime = 0f; SaveLocalControlState(player); player.disableLookInput = true; player.disableMoveInput = _localSavedDisableMoveInput; ReportLocalPossession(player, active: true); StartLocalMindControlAudioAndEffects(player); if (DebugLogs) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[CreepyDollAI] Local player possessed by gaze. clientId={player.actualClientId}"); } } } private void EndLocalPossession() { if (!_localPossessed && _reportedPossessionClientId == ulong.MaxValue && !_mindControlAudioPlaying && !_mindControlAudioDampened) { return; } bool localPossessed = _localPossessed; ulong reportedPossessionClientId = _reportedPossessionClientId; _localPossessed = false; _reportedPossessionClientId = ulong.MaxValue; PlayerControllerB val = ResolveLocalPlayer(); if ((Object)(object)val != (Object)null) { RestoreLocalControlState(val); } StopLocalMindControlAudioAndEffects(); if (reportedPossessionClientId != ulong.MaxValue) { if (((NetworkBehaviour)this).IsServer) { ClearServerEntrancedPlayer(reportedPossessionClientId); } else { ReportPossessionServerRpc(reportedPossessionClientId, active: false); } } _localControlsSaved = false; _localPossessionStopTime = 0f; _localExecutionRequested = false; _nextPossessionLosProbeTime = 0f; _cachedPossessionLos = false; _possessionLosLostSinceTime = 0f; if (localPossessed) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[CreepyDollAI][head][client] local possession ended after " + $"{Time.time - _localPossessionStartTime:0.00} s.")); } } } private void ReportLocalPossession(PlayerControllerB player, bool active) { if ((Object)(object)player == (Object)null) { return; } ulong actualClientId = player.actualClientId; if (active && _reportedPossessionClientId == actualClientId) { return; } _reportedPossessionClientId = (active ? actualClientId : ulong.MaxValue); if (((NetworkBehaviour)this).IsServer) { if (!active) { ClearServerEntrancedPlayer(actualClientId); } else if (_serverEntrancedClientId == actualClientId) { _serverPossessionAcknowledged = true; } } else { ReportPossessionServerRpc(actualClientId, active); } } private void SaveLocalControlState(PlayerControllerB player) { if (!((Object)(object)player == (Object)null) && !_localControlsSaved) { _localSavedDisableLookInput = player.disableLookInput; _localSavedDisableMoveInput = player.disableMoveInput; _localControlsSaved = true; } } private void RestoreLocalControlState(PlayerControllerB player) { if (!((Object)(object)player == (Object)null) && _localControlsSaved) { player.disableLookInput = _localSavedDisableLookInput; player.disableMoveInput = _localSavedDisableMoveInput; } } private void AimLocalPlayerAtDoll(PlayerControllerB player) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)player.thisPlayerBody != (Object)null) ? player.thisP
Y4NGZScissorsCreature.dll
Decompiled 2 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.SceneManagement; using Y4NGZMonsters.Shared; using Y4NGZScissorsCreature.NetcodePatcher; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZScissorsCreature")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+25ca94fed298fe073d4c739917e3b7f046e875bf")] [assembly: AssemblyProduct("Y4NGZScissorsCreature")] [assembly: AssemblyTitle("Y4NGZScissorsCreature")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Y4NGZScissorsCreature { public sealed class ScissorsCreatureAI : EnemyAI { public const int StateIdleWalk = 0; public const int StateWindupWalk = 1; public const int StateRushSnipping = 2; [Header("Scissors Creature anchors")] public Transform attackOrigin; public Transform wheelBone; public Collider bodyBlockerCollider; [Header("Scissors Creature audio")] public AudioClip windupClip; public AudioClip wheelUnwindClip; public AudioClip attackedByPlayerClip; public AudioClip footstepClip; public AudioClip attackRunClip; public AudioClip tickingClip; public AudioClip alarmClip; public AudioClip idleGrowlClip; public AudioClip snipKillClip; public AudioClip[] snipClips; public AudioSource tickingAudioSource; public AudioSource alarmAudioSource; private const float ScissorsDamageBehindOrigin = 1.1f; private const float ScissorsDamageAheadOfOrigin = 2.75f; private const float ScissorsDamageHalfWidth = 1.35f; private const float ScissorsDamageBelowOrigin = 0.75f; private const float ScissorsDamageAboveOrigin = 1.35f; private const float ScissorsApproachDistance = 2.35f; private const float ScissorsRushStoppingDistance = 0.6f; private const int ScissorsHittableForce = 2; private const float SnipjackDoorwayAgentRadius = 0.32f; private const float ScissorsNavigationRadius = 0.32f; private const float ScissorsIdleStoppingDistance = 0.85f; private const float ScissorsProgressSpeedFraction = 0.25f; private const float ScissorsStuckRecoverySeconds = 1.2f; private const float ScissorsOffMeshRepairInterval = 0.8f; private const float WheelConnectorRadius = 0.055f; private const float HeadTrackYawGeometryLimit = 45f; private const float HeadTrackPitchGeometryLimit = 30f; private const float HeadTrackAbandonYawDegrees = 100f; private const float HeadTrackSearchInterval = 0.25f; private const float HeadTrackDeadZoneDegrees = 0.4f; private static readonly Vector3 WheelFallbackLocalPosition = new Vector3(0f, 1.18f, -0.55f); private static readonly Vector3 WheelConnectorBodyAnchorLocalPosition = new Vector3(0f, 1.18f, -0.12f); private const string ScanSubTextIdle = "Try unwinding the back wheel"; private const string ScanSubTextWound = "Try unwinding the back wheel"; private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[32]; private readonly Collider[] _attackOverlapResults = (Collider[])(object)new Collider[64]; private readonly Dictionary<ulong, float> _lastDamageTimes = new Dictionary<ulong, float>(); private readonly Dictionary<int, float> _lastHittableDamageTimes = new Dictionary<int, float>(); private float _windupTimer; private float _snipAudioTimer; private float _footstepAudioTimer; private float _idleGrowlTimer; private int _tickingRepeatCount; private Vector3 _lastKnownTargetPosition; private float _lastTargetContactTime; private float _currentTargetLastContactTime; private Transform _wheelInteractionProxy; private Transform _wheelConnector; private Quaternion _wheelBaseLocalRotation = Quaternion.identity; private float _wheelVisualAngle; private ScanNodeProperties _creatureScanNode; private bool _scanNodeShowsWheelHint; private Vector3 _lastNavigationRecoveryPosition; private float _navigationStuckTimer; private float _nextAgentRepairTime; private bool _capturedWheelBase; private bool _windupTickingActive; private Transform _headTrackBone; private bool _headTrackCalibrated; private Quaternion _headTrackBaseLocalRotation = Quaternion.identity; private Vector3 _headTrackFaceLocalAxis = Vector3.forward; private float _headTrackYawDegrees; private float _headTrackPitchDegrees; private float _nextHeadTrackSearchTime; private PlayerControllerB _headTrackTarget; public bool CanUseWindupWheel { get { if (!base.isEnemyDead) { if (base.currentBehaviourStateIndex != 1) { return base.currentBehaviourStateIndex == 2; } return true; } return false; } } private float WalkSpeed { get { if (Plugin.ModConfig == null) { return 0.286f; } return Plugin.ModConfig.WalkSpeed.Value; } } private float WindupMoveSpeed => 0.05f; private float WalkTurnSpeed => 11.7f; private float RushSpeed { get { if (Plugin.ModConfig == null) { return 6.24f; } return Plugin.ModConfig.RushSpeed.Value; } } private float DetectionRange { get { if (Plugin.ModConfig == null) { return 28f; } return Plugin.ModConfig.DetectionRange.Value; } } private float DetectionWidth => 75f; private float ProximityAwareness => 4f; private float WindupDuration { get { if (Plugin.ModConfig == null) { return 12f; } return Plugin.ModConfig.WindupDuration.Value; } } private float AttackDamageCooldown => 0.45f; private int AttackDamage { get { if (Plugin.ModConfig == null) { return 35; } return Plugin.ModConfig.AttackDamage.Value; } } private float WheelInteractDistance => 3f; private float DisengageDistance => 20f; private float LostContactGracePeriod => 7f; private float RushSearchTimeout => 8f; private bool HeadTrackingEnabled => true; private float HeadTrackingRange => 18f; private float HeadTrackingMaxYaw => Mathf.Clamp(22f, 0f, 45f); private float HeadTrackingMaxPitch => Mathf.Clamp(12f, 0f, 30f); private float HeadTrackingTurnSpeed => 90f; public override void Awake() { try { ((EnemyAI)this).Awake(); ResolveRuntimeReferences(); } catch (Exception arg) { Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Awake failed: {arg}"); } } public override void Start() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) try { ((EnemyAI)this).Start(); Plugin.EnsureScanNode(((Component)this).gameObject); ResolveRuntimeReferences(); _idleGrowlTimer = Random.Range(2f, 6f); ConfigureAgentForState(0); _lastNavigationRecoveryPosition = ((Component)this).transform.position; if ((Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.applyRootMotion = false; base.creatureAnimator.SetTrigger("DoIdleWalk"); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Start failed: {arg}"); } } public override void Update() { try { ((EnemyAI)this).Update(); TickScanNodeSubText(); if (!base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead) { if ((Object)(object)base.creatureAnimator != (Object)null) { base.creatureAnimator.applyRootMotion = false; } if (((NetworkBehaviour)this).IsServer) { TickServerState(Time.deltaTime); RepairAgentIfNeeded(); TickNavigationRecovery(Time.deltaTime); } TickFootstepAudio(Time.deltaTime); TickWindupTickingAudio(); TickAttackAlarmAudio(); TickSnipAudio(Time.deltaTime); TickIdleGrowlAudio(Time.deltaTime); DamageObjectsInAttackVolume(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Update failed: {arg}"); } } private void LateUpdate() { try { if (!base.isEnemyDead) { TickWheelVisual(Time.deltaTime); } AlignWheelTargetsAndConnector(); TickHeadTracking(Time.deltaTime); } catch (Exception arg) { Plugin.Log.LogError((object)$"[ScissorsCreatureAI] LateUpdate failed: {arg}"); } } private void TickHeadTracking(float deltaTime) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_headTrackBone == (Object)null || !HeadTrackingEnabled || !CalibrateHeadTracking()) { return; } float num = 0f; float num2 = 0f; if (!base.isEnemyDead && TryGetHeadTrackFocusPoint(out var focusPoint)) { Vector3 val = focusPoint - _headTrackBone.position; Vector3 val2 = ((Component)this).transform.InverseTransformDirection(val); if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val2)).Normalize(); float num3 = Mathf.Atan2(val2.x, val2.z) * 57.29578f; float num4 = (0f - Mathf.Asin(Mathf.Clamp(val2.y, -1f, 1f))) * 57.29578f; if (Mathf.Abs(num3) <= 100f) { num = Mathf.Clamp(num3, 0f - HeadTrackingMaxYaw, HeadTrackingMaxYaw); num2 = Mathf.Clamp(num4, 0f - HeadTrackingMaxPitch, HeadTrackingMaxPitch); } } } float num5 = HeadTrackingTurnSpeed * deltaTime; float num6 = HeadTrackingTurnSpeed * 0.6f * deltaTime; _headTrackYawDegrees = Mathf.MoveTowards(_headTrackYawDegrees, num, num5); _headTrackPitchDegrees = Mathf.MoveTowards(_headTrackPitchDegrees, num2, num6); _headTrackBone.localRotation = _headTrackBaseLocalRotation; if (!(Mathf.Abs(_headTrackYawDegrees) < 0.4f) || !(Mathf.Abs(_headTrackPitchDegrees) < 0.4f)) { Quaternion val3 = Quaternion.Euler(_headTrackPitchDegrees, _headTrackYawDegrees, 0f); Vector3 val4 = ((Component)this).transform.TransformDirection(val3 * Vector3.forward); Vector3 val5 = _headTrackBone.TransformDirection(_headTrackFaceLocalAxis); if (!(((Vector3)(ref val4)).sqrMagnitude < 0.0001f) && !(((Vector3)(ref val5)).sqrMagnitude < 0.0001f)) { _headTrackBone.rotation = Quaternion.FromToRotation(((Vector3)(ref val5)).normalized, ((Vector3)(ref val4)).normalized) * _headTrackBone.rotation; } } } private bool CalibrateHeadTracking() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (_headTrackCalibrated) { return true; } if ((Object)(object)_headTrackBone == (Object)null) { return false; } _headTrackBaseLocalRotation = _headTrackBone.localRotation; Vector3 val = _headTrackBone.InverseTransformDirection(((Component)this).transform.forward); _headTrackFaceLocalAxis = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward); _headTrackCalibrated = true; return true; } private bool TryGetHeadTrackFocusPoint(out Vector3 focusPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) focusPoint = Vector3.zero; PlayerControllerB val = base.targetPlayer; if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true)) { if (Time.time >= _nextHeadTrackSearchTime) { _nextHeadTrackSearchTime = Time.time + 0.25f; _headTrackTarget = FindClosestVisibleTargetablePlayer(HeadTrackingRange); } val = _headTrackTarget; } if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true)) { _headTrackTarget = null; return false; } Transform val2 = (((Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform : ((Component)val).transform); if (Vector3.Distance(_headTrackBone.position, val2.position) > HeadTrackingRange) { return false; } focusPoint = val2.position; return true; } public override void DoAIInterval() { try { ((EnemyAI)this).DoAIInterval(); if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead) { switch (base.currentBehaviourStateIndex) { case 0: DoIdleWalk(); break; case 1: DoWindupWalk(); break; case 2: DoRushSnipping(); break; } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[ScissorsCreatureAI] DoAIInterval failed: {arg}"); } } private void TickServerState(float deltaTime) { switch (base.currentBehaviourStateIndex) { case 1: _windupTimer += deltaTime; ConfigureAgentForState(1); if (_windupTimer >= WindupDuration) { if (CanBeginRushSnipping()) { BeginRushSnipping(); } else { WindDownToIdle(); } } break; case 2: ConfigureAgentForState(2); break; } } private void DoIdleWalk() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) ConfigureAgentForState(0); if (!base.currentSearch.inProgress) { ((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null); } PlayerControllerB val = FindClosestVisibleTargetablePlayer(DetectionRange); if ((Object)(object)val != (Object)null) { BeginWindup(val); } } private void DoWindupWalk() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) bool hasMeaningfulContact; bool flag = TryKeepCurrentTarget(enforceRushSearchTimeout: false, out hasMeaningfulContact); if (!flag) { flag = TryAcquireMeaningfulTarget(); hasMeaningfulContact = flag; } if (!flag) { if (HasLostEveryTargetLongEnough()) { WindDownToIdle(); } else { MoveTowardLastKnownTarget(); } } else if (hasMeaningfulContact) { MoveTowardCurrentOrLastTarget(); } else { ((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false); } } private void DoRushSnipping() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) bool hasMeaningfulContact; bool flag = TryKeepCurrentTarget(enforceRushSearchTimeout: true, out hasMeaningfulContact); if (!flag) { flag = TryAcquireMeaningfulTarget(); hasMeaningfulContact = flag; } if (!flag) { WindDownToIdle(); return; } if (base.currentSearch != null && base.currentSearch.inProgress) { ((EnemyAI)this).StopSearch(base.currentSearch, true); } if (hasMeaningfulContact) { MoveTowardCurrentOrLastTarget(); return; } base.movingTowardsTargetPlayer = false; ((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false); } private bool CanBeginRushSnipping() { if (!TryKeepCurrentTarget(enforceRushSearchTimeout: false, out var _)) { return TryAcquireMeaningfulTarget(); } return true; } private bool TryKeepCurrentTarget(bool enforceRushSearchTimeout, out bool hasMeaningfulContact) { hasMeaningfulContact = false; PlayerControllerB targetPlayer = base.targetPlayer; if (!TargetIsWithinDisengageDistance(targetPlayer)) { DropCurrentTarget(); return false; } if (PlayerHasMeaningfulContact(targetPlayer, DisengageDistance)) { SetTargetWithContact(targetPlayer); hasMeaningfulContact = true; return true; } float num = Time.time - _currentTargetLastContactTime; if (num >= LostContactGracePeriod || (enforceRushSearchTimeout && num >= RushSearchTimeout)) { DropCurrentTarget(); return false; } return true; } private bool TryAcquireMeaningfulTarget() { PlayerControllerB val = FindClosestMeaningfulContactTargetablePlayer(DisengageDistance); if ((Object)(object)val == (Object)null) { return false; } SetTargetWithContact(val); return true; } private void SetTargetWithContact(PlayerControllerB player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) base.targetPlayer = player; _lastKnownTargetPosition = ((Component)player).transform.position; _currentTargetLastContactTime = Time.time; _lastTargetContactTime = Time.time; } private void DropCurrentTarget() { base.targetPlayer = null; base.movingTowardsTargetPlayer = false; } private bool TargetIsWithinDisengageDistance(PlayerControllerB player) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player != (Object)null && !player.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(player, false, false, true)) { return Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position) <= DisengageDistance; } return false; } private bool HasLostEveryTargetLongEnough() { if ((Object)(object)FindClosestMeaningfulContactTargetablePlayer(DisengageDistance) != (Object)null) { _lastTargetContactTime = Time.time; return false; } return Time.time - _lastTargetContactTime >= LostContactGracePeriod; } private void WindDownToIdle() { _wheelVisualAngle += 180f; ReturnToIdleWalk(); PlayWheelUnwindClientRpc(_wheelVisualAngle); } private void BeginWindup(PlayerControllerB player) { ((EnemyAI)this).StopSearch(base.currentSearch, true); SetTargetWithContact(player); _windupTimer = 0f; _tickingRepeatCount = 0; ConfigureAgentForState(1); SwitchState(1); PlayWindupClientRpc(); } private void BeginRushSnipping() { ((EnemyAI)this).StopSearch(base.currentSearch, true); ConfigureAgentForState(2); SwitchState(2); PlaySnipClientRpc(); } private void ReturnToIdleWalk() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) _windupTimer = 0f; DropCurrentTarget(); _currentTargetLastContactTime = 0f; ConfigureAgentForState(0); SwitchState(0); if (!base.currentSearch.inProgress) { ((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null); } } private void SwitchState(int state) { if (base.currentBehaviourStateIndex != state) { ((EnemyAI)this).SwitchToBehaviourState(state); } } private void ConfigureAgentForState(int state) { ConfigureBodyBlockerForState(state); if (!((Object)(object)base.agent == (Object)null)) { base.agent.speed = state switch { 1 => WindupMoveSpeed, 2 => RushSpeed, _ => WalkSpeed, }; base.agent.angularSpeed = ((state == 2) ? 324f : WalkTurnSpeed); base.agent.acceleration = state switch { 1 => 0.6f, 2 => 36f, _ => 2.6f, }; base.agent.stoppingDistance = state switch { 1 => 2.35f, 2 => 0.6f, _ => 0.85f, }; base.agent.radius = 0.32f; base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; base.agent.avoidancePriority = 35; base.agent.autoBraking = state != 2; } } private void MoveTowardLastKnownTarget() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(base.targetPlayer, false, false, true)) { _lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position; } ((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false); } private void MoveTowardCurrentOrLastTarget() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(base.targetPlayer, false, false, true)) { _lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position; ((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer); } else { ((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false); } } private void RepairAgentIfNeeded() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && !base.agent.isOnNavMesh && !(Time.time < _nextAgentRepairTime)) { _nextAgentRepairTime = Time.time + 0.8f; int num = ((base.agent.areaMask != 0) ? base.agent.areaMask : (-1)); NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(((Component)this).transform.position, ref val, 4f, num) && base.agent.Warp(((NavMeshHit)(ref val)).position)) { ResetNavigationRecovery(); } } } private void TickNavigationRecovery(float deltaTime) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.agent == (Object)null || !((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh) { ResetNavigationRecovery(); return; } Vector3 position = ((Component)this).transform.position; Vector3 val = position - _lastNavigationRecoveryPosition; val.y = 0f; _lastNavigationRecoveryPosition = position; bool num = base.currentBehaviourStateIndex == 1 || base.currentBehaviourStateIndex == 2 || (base.currentSearch != null && base.currentSearch.inProgress); bool flag = base.agent.hasPath && !base.agent.pathPending && base.agent.remainingDistance <= Mathf.Max(base.agent.stoppingDistance + 0.45f, 0.9f); float num2 = Mathf.Max(0.01f, base.agent.speed) * 0.25f; int num3; if (!(((Vector3)(ref val)).sqrMagnitude > 0.0025f)) { Vector3 velocity = base.agent.velocity; num3 = ((((Vector3)(ref velocity)).sqrMagnitude > num2 * num2) ? 1 : 0); } else { num3 = 1; } bool flag2 = (byte)num3 != 0; if (!num || flag || flag2) { _navigationStuckTimer = 0f; return; } _navigationStuckTimer += Mathf.Max(0f, deltaTime); if (_navigationStuckTimer < 1.2f) { return; } _navigationStuckTimer = 0f; _nextAgentRepairTime = Time.time + 0.8f; int num4 = ((base.agent.areaMask != 0) ? base.agent.areaMask : (-1)); NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(((Component)this).transform.position, ref val2, 1.5f, num4)) { base.agent.Warp(((NavMeshHit)(ref val2)).position); } if (base.currentBehaviourStateIndex == 0) { if (base.currentSearch != null && base.currentSearch.inProgress) { ((EnemyAI)this).StopSearch(base.currentSearch, false); } ((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null); } else { Vector3 val3 = (PlayerHasMeaningfulContact(base.targetPlayer, DisengageDistance) ? ((Component)base.targetPlayer).transform.position : _lastKnownTargetPosition); ((EnemyAI)this).SetDestinationToPosition(val3, false); } } private void ResetNavigationRecovery() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) _navigationStuckTimer = 0f; _lastNavigationRecoveryPosition = ((Component)this).transform.position; } private PlayerControllerB FindClosestMeaningfulContactTargetablePlayer(float range) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } PlayerControllerB result = null; float num = range; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && !val.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(val, false, false, true)) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position); if (!(num2 > num) && PlayerHasMeaningfulContact(val, range)) { num = num2; result = val; } } } return result; } private bool PlayerHasMeaningfulContact(PlayerControllerB player, float range) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || player.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(player, false, false, true)) { return false; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position); if (num > range) { return false; } if (num <= ProximityAwareness) { return true; } Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform); Transform val2 = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)player).transform); return !IsLineOfSightBlocked(val.position, val2.position); } private PlayerControllerB FindClosestVisibleTargetablePlayer(float range) { //IL_0099: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform); PlayerControllerB result = null; float num = range; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if (!((Object)(object)val2 == (Object)null) && !val2.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(val2, false, false, true)) { Transform val3 = (((Object)(object)val2.gameplayCamera != (Object)null) ? ((Component)val2.gameplayCamera).transform : ((Component)val2).transform); float num2 = Vector3.Distance(val.position, val3.position); if (!(num2 > num) && (!(num2 > ProximityAwareness) || (!(Vector3.Angle(val.forward, val3.position - val.position) > DetectionWidth) && !IsLineOfSightBlocked(val.position, val3.position)))) { num = num2; result = val2; } } } return result; } private bool IsLineOfSightBlocked(Vector3 from, Vector3 to) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!RaycastHasNonSelfBlocker(from, to)) { return RaycastHasNonSelfBlocker(to, from); } return true; } private bool RaycastHasNonSelfBlocker(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.05f) { return false; } int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault; int num = Physics.RaycastNonAlloc(new Ray(from, val / magnitude), _lineOfSightHits, magnitude, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref _lineOfSightHits[i])).collider; if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)this).transform)) { return true; } } return false; } private void DamageObjectsInAttackVolume() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (base.currentBehaviourStateIndex != 2 || (Object)(object)attackOrigin == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if ((Object)(object)val != (Object)null && PlayerIsInsideScissorsDamageVolume(val)) { TryDamagePlayer(val, requireScissorsVolume: false); } if (!((NetworkBehaviour)this).IsServer) { return; } Vector3 scissorsForward = GetScissorsForward(); Quaternion val2 = Quaternion.LookRotation(scissorsForward, Vector3.up); Vector3 val3 = attackOrigin.position + scissorsForward * 0.825f + Vector3.up * 0.3f; Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(1.35f, 1.05f, 1.925f); int num = Physics.OverlapBoxNonAlloc(val3, val4, _attackOverlapResults, val2, -1, (QueryTriggerInteraction)2); IHittable componentInParent = default(IHittable); for (int i = 0; i < num; i++) { Collider val5 = _attackOverlapResults[i]; _attackOverlapResults[i] = null; if (!((Object)(object)val5 == (Object)null) && !((Component)val5).transform.IsChildOf(((Component)this).transform) && !((Object)(object)((Component)val5).GetComponentInParent<PlayerControllerB>() != (Object)null)) { EnemyAICollisionDetect val6 = ((Component)val5).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val5).GetComponentInParent<EnemyAICollisionDetect>(); if ((Object)(object)val6 != (Object)null) { TryDamageEnemy(val6, scissorsForward); } else if (((Component)val5).TryGetComponent<IHittable>(ref componentInParent) || (componentInParent = ((Component)val5).GetComponentInParent<IHittable>()) != null) { TryHitGenericHittable(componentInParent, scissorsForward); } } } } public override void OnCollideWithPlayer(Collider other) { ((EnemyAI)this).OnCollideWithPlayer(other); if (base.currentBehaviourStateIndex == 2) { PlayerControllerB val = ((EnemyAI)this).MeetsStandardPlayerCollisionConditions(other, false, false); if ((Object)(object)val != (Object)null) { TryDamagePlayer(val); } } } public override void OnCollideWithEnemy(Collider other, EnemyAI collidedEnemy = null) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).OnCollideWithEnemy(other, collidedEnemy); if (((NetworkBehaviour)this).IsServer && base.currentBehaviourStateIndex == 2 && !((Object)(object)collidedEnemy == (Object)null) && !collidedEnemy.isEnemyDead && ColliderIsInsideScissorsDamageVolume(other)) { EnemyAICollisionDetect val = ((Component)other).GetComponent<EnemyAICollisionDetect>() ?? ((Component)other).GetComponentInParent<EnemyAICollisionDetect>(); if ((Object)(object)val != (Object)null) { TryDamageEnemy(val, GetScissorsForward()); } } } private void TryDamageEnemy(EnemyAICollisionDetect enemyCollision, Vector3 hitDirection) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)enemyCollision == (Object)null) && !((Object)(object)enemyCollision.mainScript == (Object)null) && !((Object)(object)enemyCollision.mainScript == (Object)(object)this) && !enemyCollision.mainScript.isEnemyDead) { int instanceID = ((Object)enemyCollision.mainScript).GetInstanceID(); if (CanDamageHittable(instanceID) && ((IHittable)enemyCollision).Hit(2, hitDirection, (PlayerControllerB)null, true, 7)) { _lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup; } } } private void TryHitGenericHittable(IHittable hittable, Vector3 hitDirection) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) Object val = (Object)(object)((hittable is Object) ? hittable : null); if (val == (Object)null) { return; } int instanceID = val.GetInstanceID(); if (!CanDamageHittable(instanceID)) { return; } try { PlayerControllerB val2 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if (hittable.Hit(2, hitDirection, val2, true, 7)) { _lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup; } } catch (Exception ex) { _lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup; Plugin.Log.LogWarning((object)("[ScissorsCreatureAI] Failed to hit " + val.name + " with scissors: " + ex.Message)); } } private bool CanDamageHittable(int key) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (_lastHittableDamageTimes.TryGetValue(key, out var value)) { return realtimeSinceStartup - value >= AttackDamageCooldown; } return true; } private void TryDamagePlayer(PlayerControllerB player, bool requireScissorsVolume = true) { //IL_00b3: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || player.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(player, false, false, true)) { return; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if (((Object)(object)val != (Object)null && (Object)(object)player != (Object)(object)val) || (requireScissorsVolume && !PlayerIsInsideScissorsDamageVolume(player))) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (!_lastDamageTimes.TryGetValue(player.playerClientId, out var value) || !(realtimeSinceStartup - value < AttackDamageCooldown)) { _lastDamageTimes[player.playerClientId] = realtimeSinceStartup; Vector3 val2 = (((Object)(object)attackOrigin != (Object)null) ? attackOrigin.position : ((Component)this).transform.position); Vector3 val3 = ((Component)player).transform.position - val2; Vector3 val4 = ((Vector3)(ref val3)).normalized * 8f; if (player.health <= AttackDamage) { PlaySnipKillAudio(); Vector3 val5 = Vector3.up * 14f; val3 = default(Vector3); player.KillPlayer(val5, true, (CauseOfDeath)17, 7, val3, false); } else { player.DamagePlayer(AttackDamage, true, true, (CauseOfDeath)17, 7, false, val4); } } } private bool PlayerIsInsideScissorsDamageVolume(PlayerControllerB player) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)attackOrigin == (Object)null) { return false; } Vector3 val = ((Component)player).transform.position + Vector3.up * 0.9f - attackOrigin.position; Vector3 scissorsForward = GetScissorsForward(); Vector3 val2 = Vector3.Cross(Vector3.up, scissorsForward); if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f) { val2 = ((Component)this).transform.right; } ((Vector3)(ref val2)).Normalize(); float num = Vector3.Dot(val, scissorsForward); float num2 = Vector3.Dot(val, val2); float num3 = Vector3.Dot(val, Vector3.up); if (num >= -1.1f && num <= 2.75f && Mathf.Abs(num2) <= 1.35f && num3 >= -0.75f) { return num3 <= 1.35f; } return false; } private bool ColliderIsInsideScissorsDamageVolume(Collider hitCollider) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hitCollider != (Object)null) { Bounds bounds = hitCollider.bounds; return PointIsInsideScissorsDamageVolume(((Bounds)(ref bounds)).center); } return false; } private bool PointIsInsideScissorsDamageVolume(Vector3 point) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)attackOrigin == (Object)null) { return false; } Vector3 val = point - attackOrigin.position; Vector3 scissorsForward = GetScissorsForward(); Vector3 val2 = Vector3.Cross(Vector3.up, scissorsForward); if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f) { val2 = ((Component)this).transform.right; } ((Vector3)(ref val2)).Normalize(); float num = Vector3.Dot(val, scissorsForward); float num2 = Vector3.Dot(val, val2); float num3 = Vector3.Dot(val, Vector3.up); if (num >= -1.1f && num <= 2.75f && Mathf.Abs(num2) <= 1.35f && num3 >= -0.75f) { return num3 <= 1.35f; } return false; } private Vector3 GetScissorsForward() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)attackOrigin != (Object)null) { Vector3 val = attackOrigin.position - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { return ((Vector3)(ref val)).normalized; } } Vector3 val2 = -((Component)this).transform.forward; val2.y = 0f; if (!(((Vector3)(ref val2)).sqrMagnitude > 0.001f)) { return -((Component)this).transform.forward; } return ((Vector3)(ref val2)).normalized; } [ServerRpc(RequireOwnership = false)] public void RequestWheelUnwindServerRpc(ulong playerClientId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(300173571u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, playerClientId); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 300173571u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!CanUseWindupWheel) { return; } PlayerControllerB val3 = FindPlayerByClientId(playerClientId); if (!((Object)(object)val3 == (Object)null)) { Vector3 val4 = (((Object)(object)_wheelInteractionProxy != (Object)null) ? _wheelInteractionProxy.position : (((Object)(object)wheelBone != (Object)null) ? wheelBone.position : ((Component)this).transform.position)); if (!(Vector3.Distance(((Component)val3).transform.position, val4) > WheelInteractDistance + 1.25f)) { WindDownToIdle(); } } } private PlayerControllerB FindPlayerByClientId(ulong playerClientId) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; for (int i = 0; i < allPlayerScripts.Length; i++) { if ((Object)(object)allPlayerScripts[i] != (Object)null && allPlayerScripts[i].playerClientId == playerClientId) { return allPlayerScripts[i]; } } return null; } private void ResolveRuntimeReferences() { if ((Object)(object)base.creatureAnimator == (Object)null) { base.creatureAnimator = ((Component)this).GetComponent<Animator>() ?? ((Component)this).GetComponentInChildren<Animator>(true); } if ((Object)(object)base.agent == (Object)null) { base.agent = ((Component)this).GetComponent<NavMeshAgent>() ?? ((Component)this).GetComponentInChildren<NavMeshAgent>(true); } if ((Object)(object)base.creatureSFX == (Object)null) { base.creatureSFX = FindAudioSource("CreatureSFX"); } if ((Object)(object)base.creatureVoice == (Object)null) { base.creatureVoice = FindAudioSource("CreatureVoice"); } if ((Object)(object)tickingAudioSource == (Object)null) { tickingAudioSource = FindAudioSource("TickingAudio"); } if ((Object)(object)alarmAudioSource == (Object)null) { alarmAudioSource = FindAudioSource("AlarmAudio"); } if ((Object)(object)attackOrigin == (Object)null) { attackOrigin = FindChildRecursive(((Component)this).transform, "AttackOrigin") ?? ((Component)this).transform; } if ((Object)(object)wheelBone == (Object)null) { wheelBone = FindChildRecursive(((Component)this).transform, "back_windup_wheel_mount"); } if ((Object)(object)_headTrackBone == (Object)null) { _headTrackBone = FindChildRecursive(((Component)this).transform, "head_track"); } if ((Object)(object)_creatureScanNode == (Object)null) { Transform obj = FindChildRecursive(((Component)this).transform, "ScanNode"); _creatureScanNode = ((obj != null) ? ((Component)obj).GetComponent<ScanNodeProperties>() : null); } DisableStaleWheelScanNode(); if ((Object)(object)_wheelInteractionProxy == (Object)null) { _wheelInteractionProxy = FindChildRecursive(((Component)this).transform, "BackWindupWheel_InteractionProxy"); } if ((Object)(object)_wheelConnector == (Object)null) { _wheelConnector = FindChildRecursive(((Component)this).transform, "BackWindupWheelConnector"); } if ((Object)(object)bodyBlockerCollider == (Object)null) { object obj2 = ((Component)this).GetComponent<CapsuleCollider>(); if (obj2 == null) { obj2 = ((Component)this).GetComponent<Collider>(); if (obj2 == null) { Transform obj3 = FindChildRecursive(((Component)this).transform, "BodyBlocker"); obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<Collider>() : null); } } bodyBlockerCollider = (Collider)obj2; } if ((Object)(object)base.eye == (Object)null) { base.eye = FindChildRecursive(((Component)this).transform, "EyeTransform") ?? ((Component)this).transform; } EnsureWheelConnector(); AlignWheelTargetsAndConnector(); } private void TickScanNodeSubText() { if (!((Object)(object)_creatureScanNode == (Object)null)) { bool canUseWindupWheel = CanUseWindupWheel; if (canUseWindupWheel != _scanNodeShowsWheelHint) { _scanNodeShowsWheelHint = canUseWindupWheel; _creatureScanNode.subText = (canUseWindupWheel ? "Try unwinding the back wheel" : "Try unwinding the back wheel"); } } } private void DisableStaleWheelScanNode() { Transform val = FindChildRecursive(((Component)this).transform, "WheelScanNode"); if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } } private void ConfigureBodyBlockerForState(int state) { if (!((Object)(object)bodyBlockerCollider == (Object)null)) { bodyBlockerCollider.isTrigger = false; bodyBlockerCollider.enabled = true; } } private AudioSource FindAudioSource(string childName) { Transform val = FindChildRecursive(((Component)this).transform, childName); AudioSource val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<AudioSource>() : null); if ((Object)(object)val2 != (Object)null) { return val2; } AudioSource componentInChildren = ((Component)this).GetComponentInChildren<AudioSource>(true); if ((Object)(object)componentInChildren != (Object)null && string.Equals(childName, "TickingAudio", StringComparison.Ordinal)) { Plugin.Log.LogWarning((object)("[ScissorsCreatureAI] Dedicated TickingAudio source is missing; ticking is falling back to shared AudioSource '" + ((Object)componentInChildren).name + "'.")); } return componentInChildren; } private static Transform FindChildRecursive(Transform parent, string name) { if ((Object)(object)parent == (Object)null) { return null; } if (((Object)parent).name == name) { return parent; } for (int i = 0; i < parent.childCount; i++) { Transform val = FindChildRecursive(parent.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private void TickWheelVisual(float deltaTime) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)wheelBone == (Object)null)) { if (!_capturedWheelBase) { _wheelBaseLocalRotation = wheelBone.localRotation; _capturedWheelBase = true; } float num = ((base.currentBehaviourStateIndex == 2) ? (420f * deltaTime) : 0f); if (num > 0f) { _wheelVisualAngle += num; } wheelBone.localRotation = _wheelBaseLocalRotation * Quaternion.AngleAxis(_wheelVisualAngle, Vector3.up); } } private void AlignWheelTargetsAndConnector() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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) Vector3 val = ResolveWheelCenterPosition(); if ((Object)(object)_wheelInteractionProxy != (Object)null) { _wheelInteractionProxy.position = val; _wheelInteractionProxy.rotation = ((Component)this).transform.rotation; } EnsureWheelConnector(); if (!((Object)(object)_wheelConnector == (Object)null)) { Vector3 start = ((Component)this).transform.TransformPoint(WheelConnectorBodyAnchorLocalPosition); AlignConnectorCylinder(_wheelConnector, start, val, 0.055f); } } private Vector3 ResolveWheelCenterPosition() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)wheelBone != (Object)null)) { return ((Component)this).transform.TransformPoint(WheelFallbackLocalPosition); } return wheelBone.position; } private void EnsureWheelConnector() { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_wheelConnector == (Object)null) { _wheelConnector = FindChildRecursive(((Component)this).transform, "BackWindupWheelConnector"); } if ((Object)(object)_wheelConnector != (Object)null) { return; } GameObject val = GameObject.CreatePrimitive((PrimitiveType)2); ((Object)val).name = "BackWindupWheelConnector"; val.transform.SetParent(((Component)this).transform, false); _wheelConnector = val.transform; Collider component = val.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = val.GetComponent<Renderer>(); if ((Object)(object)component2 == (Object)null) { return; } Material material = component2.material; if (!((Object)(object)material == (Object)null)) { Color val2 = default(Color); ((Color)(ref val2))..ctor(0.035f, 0.03f, 0.028f, 1f); if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", val2); } else if (material.HasProperty("_Color")) { material.color = val2; } } } private void AlignConnectorCylinder(Transform connector, Vector3 start, Vector3 end, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) Vector3 val = end - start; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.04f) { if (((Component)connector).gameObject.activeSelf) { ((Component)connector).gameObject.SetActive(false); } return; } if (!((Component)connector).gameObject.activeSelf) { ((Component)connector).gameObject.SetActive(true); } connector.position = (start + end) * 0.5f; connector.rotation = Quaternion.FromToRotation(Vector3.up, ((Vector3)(ref val)).normalized); Vector3 lossyScale = ((Component)this).transform.lossyScale; connector.localScale = new Vector3(radius / Mathf.Max(0.001f, Mathf.Abs(lossyScale.x)), magnitude * 0.5f / Mathf.Max(0.001f, Mathf.Abs(lossyScale.y)), radius / Mathf.Max(0.001f, Mathf.Abs(lossyScale.z))); } private void TickFootstepAudio(float deltaTime) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.creatureSFX == (Object)null) { return; } if (base.currentBehaviourStateIndex != 0 && base.currentBehaviourStateIndex != 1 && base.currentBehaviourStateIndex != 2) { _footstepAudioTimer = 0f; return; } if (base.currentBehaviourStateIndex == 0 && (Object)(object)base.agent != (Object)null) { Vector3 velocity = base.agent.velocity; if (((Vector3)(ref velocity)).sqrMagnitude < 0.01f) { return; } } bool flag = base.currentBehaviourStateIndex == 2; AudioClip val = ((flag && (Object)(object)attackRunClip != (Object)null) ? attackRunClip : footstepClip); if (!((Object)(object)val == (Object)null)) { _footstepAudioTimer -= deltaTime; if (!(_footstepAudioTimer > 0f)) { float num = (flag ? 0.42f : 1.35f); _footstepAudioTimer = Mathf.Max(0.12f, (val.length > 0f) ? (val.length * 0.9f) : num); base.creatureSFX.PlayOneShot(val, flag ? 1.35f : 1.15f); } } } private void TickWindupTickingAudio() { if (!_windupTickingActive && base.currentBehaviourStateIndex != 1) { StopWindupTicking(resetRepeatCount: true); return; } _windupTickingActive = true; if (!((Object)(object)tickingClip == (Object)null) && !((Object)(object)tickingAudioSource == (Object)null) && !tickingAudioSource.isPlaying) { tickingAudioSource.clip = tickingClip; tickingAudioSource.loop = false; tickingAudioSource.volume = 1.25f; tickingAudioSource.pitch = Mathf.Min(2.5f, 1.15f + (float)_tickingRepeatCount * 0.2f); tickingAudioSource.time = 0f; tickingAudioSource.Play(); _tickingRepeatCount++; } } private void StopWindupTicking(bool resetRepeatCount) { if ((Object)(object)tickingAudioSource != (Object)null) { tickingAudioSource.Stop(); tickingAudioSource.loop = false; tickingAudioSource.pitch = 1f; tickingAudioSource.time = 0f; } if (resetRepeatCount) { _tickingRepeatCount = 0; } } private void TickAttackAlarmAudio() { if (base.currentBehaviourStateIndex != 2) { StopAttackAlarm(); } else if (!((Object)(object)alarmClip == (Object)null) && !((Object)(object)alarmAudioSource == (Object)null) && !alarmAudioSource.isPlaying) { alarmAudioSource.clip = alarmClip; alarmAudioSource.loop = true; alarmAudioSource.volume = 1.25f; alarmAudioSource.pitch = 1f; alarmAudioSource.Play(); } } private void StopAttackAlarm() { if (!((Object)(object)alarmAudioSource == (Object)null)) { alarmAudioSource.Stop(); alarmAudioSource.loop = false; alarmAudioSource.pitch = 1f; alarmAudioSource.time = 0f; } } private void TickSnipAudio(float deltaTime) { if (base.currentBehaviourStateIndex != 2 || snipClips == null || snipClips.Length == 0 || (Object)(object)base.creatureSFX == (Object)null) { return; } _snipAudioTimer -= deltaTime; if (!(_snipAudioTimer > 0f)) { _snipAudioTimer = 0.27f; AudioClip val = snipClips[Random.Range(0, snipClips.Length)]; if ((Object)(object)val != (Object)null) { base.creatureSFX.PlayOneShot(val, 2.6f); } } } private void PlayAttackedByPlayerAudio() { if (!((Object)(object)attackedByPlayerClip == (Object)null)) { AudioSource val = (((Object)(object)base.creatureVoice != (Object)null) ? base.creatureVoice : base.creatureSFX); if ((Object)(object)val != (Object)null) { val.PlayOneShot(attackedByPlayerClip, 9f); } } } private void PlaySnipKillAudio() { if (!((Object)(object)base.creatureSFX == (Object)null) && !((Object)(object)snipKillClip == (Object)null)) { base.creatureSFX.PlayOneShot(snipKillClip, 2.8f); } } private void TickIdleGrowlAudio(float deltaTime) { if (base.currentBehaviourStateIndex == 2) { return; } if (base.currentBehaviourStateIndex != 0 && base.currentBehaviourStateIndex != 1) { _idleGrowlTimer = 0f; } else { if ((Object)(object)idleGrowlClip == (Object)null || (Object)(object)base.creatureVoice == (Object)null) { return; } _idleGrowlTimer -= deltaTime; if (!(_idleGrowlTimer > 0f)) { float num = ((base.currentBehaviourStateIndex == 1) ? 4f : 7f); float num2 = ((base.currentBehaviourStateIndex == 1) ? 7f : 12f); _idleGrowlTimer = Random.Range(num, num2); if (!base.creatureVoice.isPlaying) { base.creatureVoice.PlayOneShot(idleGrowlClip, (base.currentBehaviourStateIndex == 1) ? 1.45f : 1.1f); } } } } [ClientRpc] private void PlayWindupClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2316245045u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2316245045u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; _windupTickingActive = true; StopAttackAlarm(); StopWindupTicking(resetRepeatCount: true); if ((Object)(object)base.creatureSFX != (Object)null && (Object)(object)windupClip != (Object)null) { base.creatureSFX.PlayOneShot(windupClip, 1.25f); } TickWindupTickingAudio(); } } [ClientRpc] private void PlaySnipClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1552068909u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1552068909u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; _snipAudioTimer = 0f; _windupTickingActive = false; StopWindupTicking(resetRepeatCount: true); TickAttackAlarmAudio(); } } } [ClientRpc] private void PlayWheelUnwindClientRpc(float wheelAngle) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(159684443u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref wheelAngle, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 159684443u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; _wheelVisualAngle = wheelAngle; _windupTickingActive = false; StopWindupTicking(resetRepeatCount: true); StopAttackAlarm(); if ((Object)(object)base.creatureSFX != (Object)null && (Object)(object)wheelUnwindClip != (Object)null) { base.creatureSFX.PlayOneShot(wheelUnwindClip); } } } private void OnDisable() { _windupTickingActive = false; StopWindupTicking(resetRepeatCount: true); StopAttackAlarm(); } public override void OnDestroy() { _windupTickingActive = false; StopWindupTicking(resetRepeatCount: true); StopAttackAlarm(); ((EnemyAI)this).OnDestroy(); } public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { ((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID); if (!base.isEnemyDead) { PlayAttackedByPlayerAudio(); base.enemyHP -= force; if (base.enemyHP <= 0 && ((NetworkBehaviour)this).IsOwner) { ((EnemyAI)this).KillEnemyOnOwnerClient(false); } } } protected override void __initializeVariables() { ((EnemyAI)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(300173571u, new RpcReceiveHandler(__rpc_handler_300173571), "RequestWheelUnwindServerRpc"); ((NetworkBehaviour)this).__registerRpc(2316245045u, new RpcReceiveHandler(__rpc_handler_2316245045), "PlayWindupClientRpc"); ((NetworkBehaviour)this).__registerRpc(1552068909u, new RpcReceiveHandler(__rpc_handler_1552068909), "PlaySnipClientRpc"); ((NetworkBehaviour)this).__registerRpc(159684443u, new RpcReceiveHandler(__rpc_handler_159684443), "PlayWheelUnwindClientRpc"); ((EnemyAI)this).__initializeRpcs(); } private static void __rpc_handler_300173571(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: 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_0050: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { ulong playerClientId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref playerClientId); target.__rpc_exec_stage = (__RpcExecStage)1; ((ScissorsCreatureAI)(object)target).RequestWheelUnwindServerRpc(playerClientId); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2316245045(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((ScissorsCreatureAI)(object)target).PlayWindupClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_1552068909(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((ScissorsCreatureAI)(object)target).PlaySnipClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_159684443(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { float wheelAngle = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref wheelAngle, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)1; ((ScissorsCreatureAI)(object)target).PlayWheelUnwindClientRpc(wheelAngle); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "ScissorsCreatureAI"; } } [BepInPlugin("y4ngz.lethalcompany.scissorscreature", "Y4NGZ Scissors Creature", "0.1.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal const string BundleFilename = "y4ngzscissorscreature.bundle"; internal const string PrefabName = "Y4NGZScissorsCreature"; internal const string LegacyPrefabName = "LGUScissorsCreature"; internal const string DawnNamespace = "y4ngz_monsters"; internal const string DawnEnemyKey = "snipjack"; internal const string BestiaryText = "Snipjack\n\nDanger level: high\n\nA slow-moving construct with a clockwork wheel on its back and oversized shears mounted forward. It winds itself at whatever it sees ahead of it. If the wheel winds fully, the creature begins rapid snipping until the back wheel is unwound. Unwinding the wheel stops it at once; left alone with nothing in reach, its spring eventually runs down on its own.\n\n"; internal const string ScanNodeSubtitle = "Try unwinding the back wheel"; private const float CreatureScale = 0.7f; private const float ScissorsAgentRadius = 0.32f; internal static ManualLogSource Log; internal static ScissorsCreatureConfig ModConfig; internal static AssetBundle ModAssets; internal static EnemyType EnemyType; private static AudioClip[] _bundleAudioClips; private static bool _netcodeInitialized; private static bool _loggedScanNodeLayer; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; try { InitializeNetcodeRPCs(); ModConfig = new ScissorsCreatureConfig(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Y4NGZ Scissors Creature is disabled by config."); } else { if (!LoadBundle()) { return; } GameObject val = LoadBundlePrefab(); if ((Object)(object)val == (Object)null) { Log.LogError((object)"[Y4NGZ Scissors Creature] Prefab 'Y4NGZScissorsCreature' not found in y4ngzscissorscreature.bundle."); string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { Log.LogError((object)(" - " + text)); } return; } PreparePrefab(val); EnemyType = CreateEnemyType(val); ScissorsCreatureAI component = val.GetComponent<ScissorsCreatureAI>(); if ((Object)(object)component != (Object)null) { ((EnemyAI)component).enemyType = EnemyType; } RegisterWithDawn(val); Log.LogInfo((object)"Y4NGZ Scissors Creature v0.1.2 loaded. Registered as 'Snipjack'."); } } catch (Exception arg) { Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Scissors Creature", arg)); } } private static void RegisterWithDawn(GameObject prefab) { SnipjackSpawnWeights spawnWeights = new SnipjackSpawnWeights(() => ModConfig.SpawnWeightMultiplier.Value); DawnLib.RegisterNetworkPrefab(prefab); DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "snipjack"), EnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder) { ((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location) { location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table) { table.SetGlobalWeight((IWeighted)(object)spawnWeights); }); }).CreateBestiaryNode("Snipjack\n\nDanger level: high\n\nA slow-moving construct with a clockwork wheel on its back and oversized shears mounted forward. It winds itself at whatever it sees ahead of it. If the wheel winds fully, the creature begins rapid snipping until the back wheel is unwound. Unwinding the wheel stops it at once; left alone with nothing in reach, its spring eventually runs down on its own.\n\n").CreateNameKeyword("snipjack")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[5] { Tags.Hostile, Tags.Mechanical, Tags.Killable, Tags.Biped, Tags.Medium }); }); } private static void InitializeNetcodeRPCs() { if (_netcodeInitialized) { return; } _netcodeInitialized = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0) { continue; } try { methodInfo.Invoke(null, null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message)); } } } } } private static bool LoadBundle() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrEmpty(directoryName)) { Log.LogError((object)"[Y4NGZ Scissors Creature] Could not resolve plugin assembly directory."); return false; } string text = Path.Combine(directoryName, "y4ngzscissorscreature.bundle"); if (!File.Exists(text)) { Log.LogError((object)("[Y4NGZ Scissors Creature] Missing asset bundle: " + text)); return false; } ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { Log.LogError((object)("[Y4NGZ Scissors Creature] AssetBundle.LoadFromFile returned null for " + text + ".")); return false; } return true; } private static GameObject LoadBundlePrefab() { GameObject val = ModAssets.LoadAsset<GameObject>("Y4NGZScissorsCreature"); if ((Object)(object)val != (Object)null) { return val; } val = ModAssets.LoadAsset<GameObject>("LGUScissorsCreature"); if ((Object)(object)val != (Object)null) { Log.LogInfo((object)"Loaded legacy prefab 'LGUScissorsCreature' from y4ngzscissorscreature.bundle; runtime registration will still use 'Y4NGZ Scissors Creature'."); return val; } string[] allAssetNames = ModAssets.GetAllAssetNames(); foreach (string text in allAssetNames) { string text2 = text.Replace('\\', '/'); if (!text2.EndsWith("/y4ngzscissorscreature.prefab", StringComparison.OrdinalIgnoreCase) && !text2.EndsWith("/lguscissorscreature.prefab", StringComparison.OrdinalIgnoreCase) && !string.Equals(Path.GetFileNameWithoutExtension(text2), "Y4NGZScissorsCreature", StringComparison.OrdinalIgnoreCase)) { continue; } val = ModAssets.LoadAsset<GameObject>(text); if ((Object)(object)val != (Object)null) { if (text2.EndsWith("/lguscissorscreature.prefab", StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)("Loaded legacy prefab asset '" + text2 + "' from y4ngzscissorscreature.bundle.")); } return val; } } return null; } private static void PreparePrefab(GameObject prefab) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) AssignUniqueNetworkHash(prefab, "Y4NGZScissorsCreature"); prefab.transform.localScale = Vector3.one * 0.7f; ScissorsCreatureAI scissorsCreatureAI = prefab.GetComponent<ScissorsCreatureAI>(); if ((Object)(object)scissorsCreatureAI == (Object)null) { scissorsCreatureAI = prefab.AddComponent<ScissorsCreatureAI>(); } ((EnemyAI)scissorsCreatureAI).enemyHP = Mathf.Max(1, ModConfig.Health.Value); Animator val = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true); if ((Object)(object)val != (Object)null) { val.applyRootMotion = false; ((EnemyAI)scissorsCreatureAI).creatureAnimator = val; } else { Log.LogWarning((object)"[ScissorsCreature] Prefab has no Animator."); } NavMeshAgent val2 = prefab.GetComponent<NavMeshAgent>() ?? prefab.GetComponentInChildren<NavMeshAgent>(true); if ((Object)(object)val2 != (Object)null) { ((EnemyAI)scissorsCreatureAI).agent = val2; val2.speed = ModConfig.WalkSpeed.Value; val2.angularSpeed = 11.7f; val2.acceleration = 2.6f; val2.stoppingDistance = 0.85f; val2.radius = 0.32f; val2.height = 1.61f; val2.obstacleAvoidanceType = (ObstacleAvoidanceType)4; val2.avoidancePriority = 35; } else { Log.LogWarning((object)"[ScissorsCreature] Prefab has no NavMeshAgent."); } ((EnemyAI)scissorsCreatureAI).creatureSFX = FindOrCreateAudioSource(prefab, "CreatureSFX"); ((EnemyAI)scissorsCreatureAI).creatureVoice = FindOrCreateAudioSource(prefab, "CreatureVoice"); scissorsCreatureAI.tickingAudioSource = FindOrCreateAudioSource(prefab, "TickingAudio"); scissorsCreatureAI.alarmAudioSource = FindOrCreateAudioSource(prefab, "AlarmAudio"); RecoverAudioClips(scissorsCreatureAI); ((EnemyAI)scissorsCreatureAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 1.65f, 0.2f)); ((EnemyAI)scissorsCreatureAI).eye.localPosition = new Vector3(0f, 1.65f, 0.2f); scissorsCreatureAI.attackOrigin = FindOrCreateChild(prefab.transform, "AttackOrigin", new Vector3(0f, 1.05f, 2.2f)); scissorsCreatureAI.attackOrigin.localPosition = new Vector3(0f, 1.05f, 2.2f); scissorsCreatureAI.wheelBone = FindChildRecursive(prefab.transform, "back_windup_wheel_mount"); EnsureBehaviourStates(scissorsCreatureAI); EnsureScanNode(prefab); EnsureCollision(prefab, scissorsCreatureAI); EnsureWheelInteract(prefab); HideWheelArtifacts(prefab); ManualLogSource log = Log; object[] obj = new object[7] { LoadAllAudioClips().Length, null, null, null, null, null, null }; AudioClip[] snipClips = scissorsCreatureAI.snipClips; obj[1] = ((snipClips != null) ? snipClips.Length : 0); obj[2] = (Object)(object)scissorsCreatureAI.footstepClip != (Object)null; obj[3] = (Object)(object)scissorsCreatureAI.attackRunClip != (Object)null; obj[4] = (Object)(object)scissorsCreatureAI.tickingClip != (Object)null; obj[5] = (Object)(object)scissorsCreatureAI.alarmClip != (Object)null; obj[6] = (Object)(object)scissorsCreatureAI.idleGrowlClip != (Object)null; log.LogInfo((object)string.Format("[ScissorsCreature] Audio ready. bundleClips={0}, snips={1}, footstep={2}, run={3}, ticking={4}, alarm={5}, idle={6}.", obj)); } private static void EnsureBehaviourStates(ScissorsCreatureAI ai) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown ((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[3] { new EnemyBehaviourState { name = "IdleWalk", IsAnimTrigger = true, parameterString = "DoIdleWalk" }, new EnemyBehaviourState { name = "WindupWalk", IsAnimTrigger = true, parameterString = "DoWindupWalk" }, new EnemyBehaviourState { name = "RushSnipping", IsAnimTrigger = true, parameterString = "DoRushSnipping" } }; ((EnemyAI)ai).currentBehaviourStateIndex = 0; ((EnemyAI)ai).previousBehaviourStateIndex = 0; ((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0]; } internal static void EnsureScanNode(GameObject prefab) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties val = null; ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true); foreach (ScanNodeProperties val2 in componentsInChildren) { bool flag = val2.creatureScanID >= 0; bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0; bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal); bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal); if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4)) { val = val2; } } if (componentsInChildren.Length > 1) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"[Snipjack] Found {componentsInChildren.Length} scan nodes; retiring every duplicate."); } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)(object)val) { RetireExtraScanNode(componentsInChildren[j], val, prefab); } } Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.7f, 0f))); ((Object)((Component)val3).gameObject).name = "ScanNode"; TrySetTag(((Component)val3).gameObject, "DoNotSet"); TrySetLayer(((Component)val3).gameObject, "ScanNode"); EnsureHierarchyActive(val3, prefab.transform); ((Component)val3).gameObject.SetActive(true); if (!_loggedScanNodeLayer) { _loggedScanNodeLayer = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)($"[Snipjack] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}.")); } } BoxCollider obj = ((Component)val3).GetComponent<BoxCollider>() ?? ((Component)val3).gameObject.AddComponent<BoxCollider>(); ((Collider)obj).enabled = true; ((Collider)obj).isTrigger = true; obj.center = Vector3.zero; obj.size = new Vector3(0.9f, 1.2f, 0.9f); val = val ?? ((Component)val3).gameObject.AddComponent<ScanNodeProperties>(); val.headerText = "Snipjack"; val.subText = "Try unwinding the back wheel"; val.maxRange = 13; val.minRange = 1; val.requiresLineOfSight = true; val.nodeType = 1; } private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)extra == (Object)null) { return; } Scene scene; if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject)) { scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)extra); } else { Object.DestroyImmediate((Object)(object)extra, true); } return; } GameObject gameObject = ((Component)extra).gameObject; gameObject.SetActive(false); Collider[] components = gameObject.GetComponents<Collider>(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } scene = root.scene; if (((Scene)(ref scene)).IsValid()) { Object.Destroy((Object)(object)gameObject); } else { Object.DestroyImmediate((Object)(object)gameObject, true); } } private static void EnsureCollision(GameObject prefab, ScissorsCreatureAI ai) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) TrySetTag(prefab, "Enemy"); TrySetLayer(prefab, "Enemies"); CapsuleCollider val = prefab.GetComponent<CapsuleCollider>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<CapsuleCollider>(); } ((Collider)val).isTrigger = false; val.direction = 1; val.center = new Vector3(0f, 1.12f, 0.05f); val.radius = 0.34f; val.height = 1.85f; ai.bodyBlockerCollider = (Collider)(object)val; Transform val2 = prefab.transform.Find("BodyBlocker"); if ((Object)(object)val2 != (Object)null) { Collider component = ((Component)val2).GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { component.enabled = false; } ((Component)val2).gameObject.SetActive(false); } Transform val3 = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1.05f, 2.2f)); val3.localPosition = new Vector3(0f, 1.05f, 2.2f); TrySetTag(((Component)val3).gameObject, "Enemy"); TrySetLayer(((Component)val3).gameObject, "Enemies"); BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>(); } ((Collider)val4).isTrigger = true; val4.center = Vector3.zero; val4.size = new Vector3(1.7f, 0.95f, 2.3f); Rigidbody val5 = ((Component)val3).GetComponent<Rigidbody>(); if ((Object)(object)val5 == (Object)null) { val5 = ((Component)val3).gameObject.AddComponent<Rigidbody>(); } val5.isKinematic = true; val5.useGravity = false; val5.detectCollisions = true; EnemyAICollisionDetect val6 = ((Component)val3).GetComponent<EnemyAICollisionDetect>(); if ((Object)(object)val6 == (Object)null) { val6 = ((Component)val3).gameObject.AddComponent<EnemyAICollisionDetect>(); } val6.mainScript = (EnemyAI)(object)ai; val6.alwaysAllowHitting = true; val6.canCollideWithEnemies = true; val6.onlyCollideWhenGrounded = false; DisableLegacySolidCollider(prefab.transform, "PhysicalBodyCollider"); DisableLegacySolidCollider(prefab.transform, "PhysicalHeadCollider"); Disabl